aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-05-16 01:43:09 -0400
committerB. Watson <urchlay@slackware.uk>2024-05-16 01:43:09 -0400
commita4cc3ad3504d634e379369862c9f9fd8eed379f3 (patch)
tree7b6f55c352a4ca62dddaa1b4a6854799111d2d2f
parentb33c25d1363110e6e4a714530f460b0ff951f56b (diff)
downloadbw-atari8-tools-a4cc3ad3504d634e379369862c9f9fd8eed379f3.tar.gz
Add Jindrich Kubec's tools.
-rw-r--r--.gitignore2
-rw-r--r--LICENSE17
-rw-r--r--Makefile6
-rw-r--r--jindroush/Makefile62
-rw-r--r--jindroush/README.txt37
-rw-r--r--jindroush/acvt/Makefile52
-rw-r--r--jindroush/acvt/acvt.cpp216
-rw-r--r--jindroush/acvt/pub.def31
-rw-r--r--jindroush/acvt/readme.txt152
-rw-r--r--jindroush/acvt/switches.def64
-rw-r--r--jindroush/adir/Makefile52
-rw-r--r--jindroush/adir/adir.cpp494
-rw-r--r--jindroush/adir/pub.def31
-rw-r--r--jindroush/adir/readme.txt112
-rw-r--r--jindroush/adir/switches.def64
-rw-r--r--jindroush/aext/Makefile49
-rw-r--r--jindroush/aext/aext.cpp280
-rw-r--r--jindroush/aext/pub.def31
-rw-r--r--jindroush/aext/readme.txt76
-rw-r--r--jindroush/aext/switches.def25
-rw-r--r--jindroush/bas2boot/Makefile59
-rw-r--r--jindroush/bas2boot/bas2boot.asm169
-rw-r--r--jindroush/bas2boot/bas2boot.boobin0 -> 256 bytes
-rw-r--r--jindroush/bas2boot/bas2boot.cpp286
-rw-r--r--jindroush/bas2boot/pub.def31
-rw-r--r--jindroush/bas2boot/readme.txt72
-rw-r--r--jindroush/bas2boot/switches.def32
-rw-r--r--jindroush/chkbas/Makefile61
-rw-r--r--jindroush/chkbas/basic.h152
-rw-r--r--jindroush/chkbas/basic_tb.h223
-rw-r--r--jindroush/chkbas/basic_xe.h219
-rw-r--r--jindroush/chkbas/basic_xl.h213
-rw-r--r--jindroush/chkbas/carray.cpp158
-rw-r--r--jindroush/chkbas/carray.h49
-rw-r--r--jindroush/chkbas/chkbas.cpp1009
l---------jindroush/chkbas/listbas1
-rw-r--r--jindroush/chkbas/pub.def31
-rw-r--r--jindroush/chkbas/readme.txt87
-rw-r--r--jindroush/chkbas/strlwr.cpp11
-rw-r--r--jindroush/chkbas/switches.def34
-rw-r--r--jindroush/chkexe/Makefile55
-rw-r--r--jindroush/chkexe/chkexe.cpp504
-rw-r--r--jindroush/chkexe/pub.def31
-rw-r--r--jindroush/chkexe/readme.txt100
-rw-r--r--jindroush/chkexe/switches.def21
-rw-r--r--jindroush/chkrom/Makefile56
-rw-r--r--jindroush/chkrom/chkrom.cpp119
-rw-r--r--jindroush/chkrom/pub.def31
-rw-r--r--jindroush/chkrom/readme.txt56
-rw-r--r--jindroush/chkrom/switches.def5
-rw-r--r--jindroush/gpl.txt339
-rw-r--r--jindroush/include/adsk.h75
-rw-r--r--jindroush/include/adsk_atr.h38
-rw-r--r--jindroush/include/adsk_dcm.h72
-rw-r--r--jindroush/include/adsk_di.h38
-rw-r--r--jindroush/include/adsk_scp.h37
-rw-r--r--jindroush/include/adsk_xfd.h38
-rw-r--r--jindroush/include/at_dis.h25
-rw-r--r--jindroush/include/autil.h35
-rw-r--r--jindroush/include/cdisk.h95
-rw-r--r--jindroush/include/cdsk.h72
-rw-r--r--jindroush/include/cdsk_atr.h38
-rw-r--r--jindroush/include/cdsk_dcm.h72
-rw-r--r--jindroush/include/cdsk_scp.h37
-rw-r--r--jindroush/include/cdsk_xfd.h38
-rw-r--r--jindroush/include/cfile.h54
-rw-r--r--jindroush/include/cfs.h65
-rw-r--r--jindroush/include/cfs_b2b.h42
-rw-r--r--jindroush/include/cfs_boot.h42
-rw-r--r--jindroush/include/cfs_dos2.h67
-rw-r--r--jindroush/include/cfs_dos3.h59
-rw-r--r--jindroush/include/cfs_dosm.h66
-rw-r--r--jindroush/include/cfs_doss.h70
-rw-r--r--jindroush/include/cfs_howf.h43
-rw-r--r--jindroush/include/cfs_jonw.h43
-rw-r--r--jindroush/include/cfs_kboo.h42
-rw-r--r--jindroush/include/cfs_robc.h43
-rw-r--r--jindroush/include/cgenfile.h55
-rw-r--r--jindroush/include/cobj.h34
-rw-r--r--jindroush/include/cprefile.h56
-rw-r--r--jindroush/include/errbase.h26
-rw-r--r--jindroush/include/jintypes.h95
-rw-r--r--jindroush/lib/Makefile23
-rw-r--r--jindroush/lib/adsk.cpp319
-rw-r--r--jindroush/lib/adsk_atr.cpp483
-rw-r--r--jindroush/lib/adsk_dcm.cpp764
-rw-r--r--jindroush/lib/adsk_di.cpp271
-rw-r--r--jindroush/lib/adsk_scp.cpp281
-rw-r--r--jindroush/lib/adsk_xfd.cpp327
-rw-r--r--jindroush/lib/at_dis.cpp1201
-rw-r--r--jindroush/lib/autil.cpp139
-rw-r--r--jindroush/lib/cdisk.cpp276
-rw-r--r--jindroush/lib/cdsk.cpp115
-rw-r--r--jindroush/lib/cdsk_atr.cpp439
-rw-r--r--jindroush/lib/cdsk_dcm.cpp762
-rw-r--r--jindroush/lib/cdsk_scp.cpp279
-rw-r--r--jindroush/lib/cdsk_xfd.cpp334
-rw-r--r--jindroush/lib/cfile.cpp139
-rw-r--r--jindroush/lib/cfs.cpp69
-rw-r--r--jindroush/lib/cfs_b2b.cpp156
-rw-r--r--jindroush/lib/cfs_boot.cpp128
-rw-r--r--jindroush/lib/cfs_dos2.cpp224
-rw-r--r--jindroush/lib/cfs_dos3.cpp209
-rw-r--r--jindroush/lib/cfs_dosm.cpp240
-rw-r--r--jindroush/lib/cfs_doss.cpp383
-rw-r--r--jindroush/lib/cfs_howf.cpp209
-rw-r--r--jindroush/lib/cfs_jonw.cpp204
-rw-r--r--jindroush/lib/cfs_kboo.cpp148
-rw-r--r--jindroush/lib/cfs_robc.cpp231
-rw-r--r--jindroush/lib/cgenfile.cpp95
-rw-r--r--jindroush/lib/cobj.cpp23
-rw-r--r--jindroush/lib/cprefile.cpp153
-rw-r--r--jindroush/man/Makefile12
-rw-r--r--jindroush/man/acvt.1116
-rw-r--r--jindroush/man/acvt.rst77
-rw-r--r--jindroush/man/adir.1141
-rw-r--r--jindroush/man/adir.rst89
-rw-r--r--jindroush/man/aext.155
-rw-r--r--jindroush/man/aext.rst24
-rw-r--r--jindroush/man/bas2boot.184
-rw-r--r--jindroush/man/bas2boot.rst53
-rw-r--r--jindroush/man/chkbas.1155
-rw-r--r--jindroush/man/chkbas.rst118
-rw-r--r--jindroush/man/chkexe.186
-rw-r--r--jindroush/man/chkexe.rst55
-rw-r--r--jindroush/man/chkrom.190
-rw-r--r--jindroush/man/chkrom.rst51
-rw-r--r--jindroush/man/manftr.rst21
-rw-r--r--jindroush/man/manhdr.rst7
-rw-r--r--jindroush/switches.pl322
130 files changed, 17856 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index c2c2162..a03f602 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+*.bas
+*.BAS
*.car
*.cart
*.rom
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..421538c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,17 @@
+This is a collection of software from multiple sources, released
+under separate license.
+
+The software by me (B. Watson, urchlay@slackware.uk), found in the
+main bw-atari8-tools directory, is released under the WTFPL. Do WTF
+you want with it.
+
+The software by Ken Siders, in the ksiders/ subdirectory, is
+copyrighted by Ken Siders. It doesn't have a formal license, but
+the file atr.txt says: "Feel free to use them in your own freeware
+and public domain programs if credit is given". This is not strictly
+speaking an open source license, but it does allow use of the code as
+it's being used here.
+
+The software by Jindrich Kubec, in the jindroush/ subdirectory, is
+released under the GPL (version 2), and includes its own copy of the
+GPL as "gpl.txt".
diff --git a/Makefile b/Makefile
index 12b4364..67767a0 100644
--- a/Makefile
+++ b/Makefile
@@ -21,9 +21,9 @@ SCRIPTS=dasm2atasm a8utf8
MANS=a8eol.1 xfd2atr.1 atr2xfd.1 blob2c.1 cart2xex.1 fenders.1 xexsplit.1 xexcat.1 atrsize.1 rom2cart.1 unmac65.1 axe.1 dasm2atasm.1 a8utf8.1 blob2xex.1 xexamine.1 xex1to2.1
MAN5S=xex.5
MAN7S=atascii.7
-DOCS=README equates.inc *.dasm ksiders/atr.txt
+DOCS=README equates.inc *.dasm LICENSE ksiders/atr.txt
-SUBDIRS=ksiders
+SUBDIRS=ksiders jindroush
# All the programs share this version number...
VERSION=0.2.1
@@ -197,5 +197,5 @@ install: all install-subdirs
install-subdirs: subdirs
for dir in $(SUBDIRS); do \
- make -C $$dir DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) BINDIR=$(BINDIR) MAN1DIR=$(MAN1DIR); \
+ make -C $$dir DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) BINDIR=$(BINDIR) MAN1DIR=$(MAN1DIR) GZIP_MAN=$(GZIP_MAN) DOCDIR=$(DOCDIR) install; \
done
diff --git a/jindroush/Makefile b/jindroush/Makefile
new file mode 100644
index 0000000..0a11a8f
--- /dev/null
+++ b/jindroush/Makefile
@@ -0,0 +1,62 @@
+# Unified Makefile for Jindroush's various Atari 8-bit utilities
+
+DESTDIR=
+PREFIX=/usr/local
+BINDIR=$(PREFIX)/bin
+DOCDIR=$(PREFIX)/share/doc/jindroush_atari8_utils
+
+MANDIR=$(PREFIX)/share/man
+MAN1DIR=$(MANDIR)/man1
+
+GZIP_MAN=y
+RST2MAN=rst2man
+
+BINS=acvt adir aext bas2boot chkbas chkexe chkrom
+
+# The -Wno-write-strings prevents hundreds of "ISO C++ forbids
+# converting a string to 'char*'" warnings. Eventually will fix.
+W=-Wall -Wno-write-strings
+
+all: libs manpages
+ for i in $(BINS); do \
+ make -C $$i COPT="$(COPT) $(W)" ; \
+ done
+
+manpages:
+ make -C man
+
+libs:
+ make -C lib COPT="$(COPT) $(W)"
+
+clean:
+ make -C lib clean
+ for i in $(BINS); do \
+ make -C $$i clean ; \
+ done
+
+install: all
+ mkdir -p $(DESTDIR)/$(BINDIR) $(DESTDIR)/$(DOCDIR) ; \
+ cp README.txt $(DESTDIR)/$(DOCDIR)/README_jindroush.txt ; \
+ cp gpl.txt $(DESTDIR)/$(DOCDIR)/gpl.txt ; \
+ for i in $(BINS); do \
+ strip $$i/$$i ; \
+ cp $$i/$$i $(DESTDIR)/$(BINDIR)/$$i ; \
+ chown root.root $$i/$$i $(DESTDIR)/$(BINDIR)/$$i 2>/dev/null || true ; \
+ chmod 755 $(DESTDIR)/$(BINDIR)/$$i ; \
+ cp $$i/readme.txt $(DESTDIR)/$(DOCDIR)/$$i.txt ; \
+ chown root.root $(DESTDIR)/$(DOCDIR)/$$i.txt 2>/dev/null || true ; \
+ chmod 644 $(DESTDIR)/$(DOCDIR)/$$i.txt ; \
+ done ; \
+ mkdir -p $(DESTDIR)/$(MAN1DIR) ; \
+ for i in $(BINS); do \
+ cp man/$$i.1 $(DESTDIR)/$(MAN1DIR) ; \
+ chown root.root $(DESTDIR)/$(MAN1DIR)/$$i.1 2>/dev/null || true ; \
+ chmod 644 $(DESTDIR)/$(MAN1DIR)/$$i.1 ; \
+ [ "$(GZIP_MAN)" = "y" ] && gzip -f $(DESTDIR)/$(MAN1DIR)/$$i.1 ; \
+ done
+ ln -sf chkbas $(DESTDIR)$(BINDIR)/listbas
+ if [ "$(GZIP_MAN)" = "y" ]; then \
+ ln -sf chkbas.1.gz $(DESTDIR)$(MAN1DIR)/listbas.1.gz ; \
+ else \
+ ln -sf chkbas.1 $(DESTDIR)$(MAN1DIR)/listbas.1 ; \
+ fi
diff --git a/jindroush/README.txt b/jindroush/README.txt
new file mode 100644
index 0000000..31d9af9
--- /dev/null
+++ b/jindroush/README.txt
@@ -0,0 +1,37 @@
+This is a collection of GPL'ed Atari 8-bit tools developed by
+Jindroush, AKA Jindrich Kubec. The original site has gone offline, but
+there's a copy at archive.org:
+
+http://web.archive.org/web/20010412172202/http://www.asw.cz/~kubecj/asoft.htm
+
+The utilities are:
+
+acvt - converts disk images between xfd, atr, dcm, and other formats.
+adir - extracts files from disk images, supports lots of formats.
+aext - extracts segments from .xex files as blocks of raw data.
+bas2boot - converts Atari BASIC files to bootable disk images.
+chkbas - checks and lists tokenized Atari BASIC files.
+chkexe - lists and optionally disassembles segments in a .xex file.
+chkrom - checks and disassembles Atari 8K and 16K cartridge images.
+
+Originally, these were published separately. This collection was
+put together by B. Watson <urchlay@slackware.uk>. The only changes
+I've made to Jindroush's code:
+
+- The common code from each source .zip file has been collected
+ in the lib/ directory, and the Makefiles were modified to
+ use this library.
+
+- switches.pl: changed a "char *" to a "const char *" to avoid
+ g++ warnings.
+
+- All instances of open() that create files originally created them
+ with mode 0600; changed this to 0666 (which will still be affected
+ by the user's umask).
+
+- Added "listbas" symlink, to save typing "chkbas -short" over and over
+ again.
+
+- adir's -dir option now creates the directory if it doesn't exist.
+
+- Wrote man pages for all the utilities.
diff --git a/jindroush/acvt/Makefile b/jindroush/acvt/Makefile
new file mode 100644
index 0000000..498e2fc
--- /dev/null
+++ b/jindroush/acvt/Makefile
@@ -0,0 +1,52 @@
+#=====================================================================
+PRGNAME = acvt
+
+DESTDIR=
+PREFIX=/usr
+
+LDLIBS=-L../lib -ljindroush
+INCPATH=-I../include
+
+all: release
+
+release:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall -D__CDISK_SAVE__" LDFLAGS=""
+ @echo RELEASE: Compiled.
+
+rel_strip: release
+ @strip $(PRGNAME)
+
+install: rel_strip
+ cp $(PRGNAME) $(DESTDIR)/$(PREFIX)/bin/
+ @echo RELEASE: Installed.
+
+debug:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG -D__CDISK_SAVE__" LDFLAGS="-g"
+ @echo DEBUG: Compiled.
+
+clean:
+ rm -rf *.o $(PRGNAME) $(PRGNAME).exe switches.cpp
+ @echo DEBUG: Cleaned.
+
+
+OBJECTS = acvt.o
+
+#=====================================================================
+CXX = g++
+LD = g++
+CPPFLAGS=$(COPT)
+COPT=-O2
+
+#=====================================================================
+
+$(PRGNAME) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME)
+
+%.o : %.cpp switches.cpp
+ $(CXX) $(INCPATH) $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+%.o : %.cpp
+ $(CXX) $(INCPATH) $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+switches.cpp : switches.def ../switches.pl
+ perl ../switches.pl $< $@
diff --git a/jindroush/acvt/acvt.cpp b/jindroush/acvt/acvt.cpp
new file mode 100644
index 0000000..857da5b
--- /dev/null
+++ b/jindroush/acvt/acvt.cpp
@@ -0,0 +1,216 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "pub.def"
+#include "jintypes.h"
+#include "autil.h"
+#include "adsk.h"
+
+BOOL Convert( char* szInFile, char* szOutFile );
+
+DISK_TYPE g_dtypeIn = DISK_AUTO;
+DISK_TYPE g_dtypeOut = DISK_ATR;
+
+BOOL g_bVerbose = FALSE;
+BOOL g_bBatchMode = FALSE;
+BOOL g_bRepairAuto = FALSE;
+BOOL g_bRepair = TRUE;
+BOOL g_bFirstErrStop = FALSE;
+BOOL g_bOverWrite = FALSE;
+BOOL g_bTestOnly = FALSE;
+BOOL g_bForceClassic = FALSE;
+
+#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n"
+
+#define HEADER SHEADER \
+ PRG_DESC "\n" \
+ " Latest version can be found at " PRG_URL "\n" \
+ " Published under GPL. See GPL.TXT.\n\n"
+
+#define USAGE HEADER "Usage: " PRG_NAME " " PRG_USAGE
+
+#include "switches.cpp"
+
+int main(int argc,char *argv[])
+{
+ setbuf( stdout, NULL );
+ setbuf( stderr, NULL );
+
+ if ( !SWITCHES_Init( &argc, argv ) )
+ return 1;
+
+ if ( argc < 2 )
+ {
+ SWFN_HELP( USAGE );
+ return 1;
+ }
+
+ fprintf( stderr, SHEADER );
+
+ BOOL bRet = FALSE;
+
+ char szOutFile[ 255 ];
+
+ if ( g_bBatchMode )
+ {
+ argc--;
+ argv++;
+
+ while( argc-- )
+ {
+ char* szInFile = *(argv++);
+ GuessBestFnameFromPC( szOutFile, szInFile, GetDiskTypeExt( g_dtypeOut ) );
+ bRet = Convert( szInFile, szOutFile );
+ printf( "\n" );
+
+ if ( !bRet && g_bFirstErrStop )
+ break;
+ }
+
+ }
+ else
+ {
+ char* szInFile = argv[ 1 ];
+
+ if ( argc >= 3 )
+ {
+ strcpy( szOutFile, argv[ 2 ] );
+ }
+ else
+ {
+ GuessBestFnameFromPC( szOutFile, szInFile, GetDiskTypeExt( g_dtypeOut ) );
+ }
+
+ bRet = Convert( szInFile, szOutFile );
+ }
+
+ if ( bRet && !g_bTestOnly )
+ printf ( "Done.\n" );
+
+ return bRet ? 0 : 1;
+}
+
+BOOL Convert( char* szInFile, char* szOutFile )
+{
+ ADisk* pDiskIn = NULL;
+ ADisk* pDiskOut = NULL;
+
+ DISKINIT_RETCODE ret;
+
+ g_dtypeIn = DISK_ATR;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &pDiskIn, DISK_ATR, szInFile, FALSE, g_bRepair, g_bRepairAuto ) ) )
+ {
+ g_dtypeIn = DISK_DI;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &pDiskIn, DISK_DI, szInFile, FALSE, g_bRepair, g_bRepairAuto ) ) )
+ {
+ g_dtypeIn = DISK_DCM;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &pDiskIn, DISK_DCM, szInFile, FALSE, g_bRepair, g_bRepairAuto ) ) )
+ {
+ g_dtypeIn = DISK_SCP;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &pDiskIn, DISK_SCP, szInFile, FALSE, g_bRepair, g_bRepairAuto ) ) )
+ {
+ g_dtypeIn = DISK_XFD;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &pDiskIn, DISK_XFD, szInFile, FALSE, g_bRepair, g_bRepairAuto ) ) )
+ {
+ printf( "Unable to determine format of disk image '%s'!\n", szInFile );
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ if ( ret == DI_RET_CANT_CONTINUE )
+ return FALSE;
+
+ printf( "Input file '%s' (%s)\n", szInFile, GetDiskTypeName( g_dtypeIn ) );
+
+ if ( g_bVerbose )
+ {
+ DISK_GEOMETRY* pgeo = pDiskIn->GetGeometry();
+ printf( "Sides: %d\n", pgeo->iSides );
+ printf( "Tracks: %d\n", pgeo->iTracks );
+ printf( "SecPerTrack: %d\n", pgeo->iSectorsPerTrack );
+ printf( "BytesPerSec: %d\n", pgeo->iBytesPerSector );
+ printf( "Sectors: %d\n", pgeo->iSectors );
+ }
+
+ if ( g_bTestOnly )
+ {
+ printf( "File loaded OK.\n" );
+ delete pDiskIn;
+ return TRUE;
+ }
+
+ switch( g_dtypeOut )
+ {
+ case DISK_ATR:
+ pDiskOut = new CAtr();
+ break;
+
+ case DISK_XFD:
+ pDiskOut = new CXfd();
+ break;
+
+ case DISK_DI:
+ pDiskOut = new CDi();
+ break;
+
+ case DISK_SCP:
+ pDiskOut = new CScp();
+ break;
+
+ case DISK_DCM:
+ pDiskOut = new CDcm();
+ break;
+
+ default:
+ break;
+ }
+
+ if ( !pDiskOut )
+ {
+ fprintf( stderr, "Can't create such image!\n" );
+ return FALSE;
+ }
+
+ DISK_GEOMETRY* pgeo = pDiskIn->GetGeometry();
+ DISK_GEOMETRY forced;
+
+ memcpy( &forced, pgeo, sizeof( DISK_GEOMETRY ) );
+
+ if ( g_bForceClassic )
+ ForceClassicSize( &forced );
+
+ //duplicating the image
+ pDiskOut->Duplicate( pDiskIn, &forced );
+
+ printf( "Output file '%s' (%s)\n", szOutFile, GetDiskTypeName( g_dtypeOut ) );
+
+ //and save it in new format
+ if ( !pDiskOut->Save( szOutFile, g_bOverWrite ) )
+ {
+ printf( "Error! %s\n", pDiskOut->GetLastError() );
+ delete pDiskIn;
+ delete pDiskOut;
+ return FALSE;
+ }
+
+ delete pDiskIn;
+ delete pDiskOut;
+
+ return TRUE;
+}
+
diff --git a/jindroush/acvt/pub.def b/jindroush/acvt/pub.def
new file mode 100644
index 0000000..5068092
--- /dev/null
+++ b/jindroush/acvt/pub.def
@@ -0,0 +1,31 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define PRG_NAME "acvt"
+#define PRG_VERSION "1.07"
+#define PRG_COPYRIGHT "2000-2001"
+#define PRG_UNDERGPL "1"
+#define PRG_AUTHOR "Jindrich Kubec <kubecj@asw.cz>"
+
+#define PRG_URL "http://www.asw.cz/~kubecj"
+
+#define PRG_DESC "Converts between XFD-SCP-ATR-DCM-DI formats."
+#define PRG_USAGE "[options] sourcefile [destfile]"
+
+#define PRG_ARCH "PC"
+#define PRG_TOOLS "PERL"
+
+#define PRG_SRCS "!GENERATED!"
+#define PRG_BINS "rel/acvt.exe"
diff --git a/jindroush/acvt/readme.txt b/jindroush/acvt/readme.txt
new file mode 100644
index 0000000..e2b41d5
--- /dev/null
+++ b/jindroush/acvt/readme.txt
@@ -0,0 +1,152 @@
+Acvt v1.07 (c) 2000-2001 Jindrich Kubec <kubecj@asw.cz>
+Latest version can be found at http://www.asw.cz/~kubecj
+
+This program is provided 'as is', no warranty will be taken
+for any damage caused by it or by any use of it.
+
+The whole package is placed under the GNU Public License, for further
+information on redistribution see the included file "GPL.TXT".
+
+
+Description:
+------------
+Converts between XFD-SCP-ATR-DCM-DI formats.
+ATR - SIO2PC images
+XFD - XFormer images
+DCM - DiskCommunicator images
+SCP - SpartaDos SCOPY images
+DI - XL/ST link / XLDJ disk images
+
+It's replacement for DOS version of Steven Tucker's Imagic.
+It's in fact better because:
+1) It's free.
+2) It comes with source.
+3) Therefore it could be ported to another architectures.
+4) Contains less bugs. (Hope so.)
+5) Can repair some invalid images.
+6) Now also supports DI file format.
+
+Thanks go to:
+Ernest Schreurs for his DiskCommunicator dissection and paper about DCM format.
+Chad Wagner for DCMtoATR utility (DCM driver is still loosely based on his
+ code).
+Burian brothers for lots of DI files.
+
+
+Usage:
+------
+Acvt [options] sourcefile [destfile]
+
+sourcefile is Atari disk image (ATR,XFD,SCP,DCM,DI).
+
+destfile is output disk image. If omitted, output filename is created
+ automatically.
+
+-xfd -atr -scp -dcm -di options are output type modes. Default is -atr.
+
+-batchmode: turns on multi file processing mode. Only input files are specified
+ on command-line (Unix-like compatible regexp expressions are allowed when
+ compiled under DJGPP). Output filenames are created automatically.
+
+-autorepair: automatically determines the best repair method.
+
+-norepair: doesn't ask for repair options and considers input file invalid.
+
+-errstop: in batch mode ends on first error encountered.
+
+-over: overwrites existing files. Otherwise returns an error.
+
+-test: only loads input images and displays their state.
+
+-classic: forces to create 'classic' Atari disk sizes.
+
+
+History:
+--------
+Date, Author, Version
+5/22/1999, kubecj, 0.10
+First version
+
+5/25/1999, kubecj, 0.15
+SCP save added
+
+5/29/1999, kubecj, 0.20
+DCM save added, decompression corrected
+
+5/30/1999, kubecj, 0.30
+Code cleanup
+
+6/1/1999, kubecj, 0.35
+Invalid DD ATR repair added
+
+6/2/1999, kubecj, 0.40
+Invalid DD XFD repair added
+Invalid ATR length repair added
+Added cached read for DCM decompression
+
+6/3/1999, kubecj, 0.42
+Code cleanup
+
+6/4/1999, kubecj, 0.43
+Added checks for DCM decompression
+Check for multi-arc
+
+6/5/1999, kubecj, 1.00
+First public version
+
+6/10/1999, kubecj, 1.01
+Compatibility macros & valid archive :)
+
+6/11/1999, kubecj, 1.02
+Repaired repairing ;)
+
+6/13/1999, kubecj, 1.03
+Changed switches processing
+
+10/10/1999, kubecj, 1.04
+Only changed generation of archive, new version to avoid version checking
+problems.
+
+6/6/2000, kubecj, 1.05
+Minor bugfix concerning repairing.
+Added -classic commandline switch to force to create 'classic' disk sizes.
+
+2/26/2001, kubecj, 1.06
+Added DI file format. Its support is just a beta!
+
+3/8/2001, kubecj, 1.07
+Handling of double sided diskettes in DI format.
+
+
+To Do:
+------
+Maybe check pass count in DCM images?
+Better handling of DI files.
+
+
+Known Bugs:
+-----------
+DCM record 0x42 is not decompressed, code is present, but commented out and
+ untested. I need some sample first.
+
+DI files are really an educated guess. There are many 'white places' for me.
+I need the description of the disk format.
+
+Function for actual conversion is stupid. In fact in order to convert ATR to
+ XFD there is created Atr object, loaded in, and same Xfd object is created and
+ all the data are duplicated. With 16MB SpartaDOS Atr images it's simply too
+ much.
+
+
+Compiling Tools:
+----------------
+For scripts: Perl.
+URL: http://www.perl.com
+
+For PC executables: DJGPP.
+Sources were written/tested on GCC/Intel only. There should be only
+minor problems to port it to different architectures/environments.
+Makefile should need only minor changes.
+URL: http://www.delorie.com
+
+
diff --git a/jindroush/acvt/switches.def b/jindroush/acvt/switches.def
new file mode 100644
index 0000000..763907b
--- /dev/null
+++ b/jindroush/acvt/switches.def
@@ -0,0 +1,64 @@
+v
+verbose output
+=g_bVerbose = TRUE;
+=
+
+atr, a
+output is ATR
+=g_dtypeOut = DISK_ATR;
+=
+
+di
+output is DI
+=g_dtypeOut = DISK_DI;
+=
+
+xfd, x
+output is XFD
+=g_dtypeOut = DISK_XFD;
+=
+
+scp, s
+output is SCP
+=g_dtypeOut = DISK_SCP;
+=
+
+dcm, d
+output is DCM
+=g_dtypeOut = DISK_DCM;
+=
+
+batch, batchmode, b
+batch mode
+=g_bBatchMode = TRUE;
+=
+
+errstop
+in batchmode stop on first error
+=g_bFirstErrStop = TRUE;
+=
+
+over, overwrite
+turns on file overwriting
+=g_bOverWrite = TRUE;
+=
+
+autorepair
+auto repair mode
+=g_bRepairAuto = TRUE;
+=
+
+norepair
+don't repair
+=g_bRepair = FALSE;
+=
+
+test
+only test input files
+=g_bTestOnly = TRUE;
+=
+
+classic
+force to create 'classic' disk formats
+=g_bForceClassic = TRUE;
+=
diff --git a/jindroush/adir/Makefile b/jindroush/adir/Makefile
new file mode 100644
index 0000000..284add5
--- /dev/null
+++ b/jindroush/adir/Makefile
@@ -0,0 +1,52 @@
+#=====================================================================
+PRGNAME = adir
+
+DESTDIR=
+PREFIX=/usr
+
+LDLIBS=-L../lib -ljindroush
+INCPATH=-I../include
+
+all: release
+
+release:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall -D__CDISK_SAVE__" LDFLAGS=""
+ @echo RELEASE: Compiled.
+
+rel_strip: release
+ @strip $(PRGNAME)
+
+install: rel_strip
+ cp $(PRGNAME) $(DESTDIR)/$(PREFIX)/bin/
+ @echo RELEASE: Installed.
+
+debug:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG -D__CDISK_SAVE__" LDFLAGS="-g"
+ @echo DEBUG: Compiled.
+
+clean:
+ rm -rf *.o $(PRGNAME) $(PRGNAME).exe switches.cpp
+ @echo DEBUG: Cleaned.
+
+
+OBJECTS = adir.o
+
+#=====================================================================
+CXX = g++
+LD = g++
+CPPFLAGS=$(COPT)
+COPT=-O2
+
+#=====================================================================
+
+$(PRGNAME) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME)
+
+%.o : %.cpp switches.cpp
+ $(CXX) $(INCPATH) $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+%.o : %.cpp
+ $(CXX) $(INCPATH) $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+switches.cpp : switches.def ../switches.pl
+ perl ../switches.pl $< $@
diff --git a/jindroush/adir/adir.cpp b/jindroush/adir/adir.cpp
new file mode 100644
index 0000000..7dceb01
--- /dev/null
+++ b/jindroush/adir/adir.cpp
@@ -0,0 +1,494 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include <sys/stat.h>
+
+#include "jintypes.h"
+#include <fnmatch.h>
+
+#include "pub.def"
+
+#include "adsk.h"
+
+#include "cfs.h"
+#include "cfs_dos2.h"
+#include "cfs_dos3.h"
+#include "cfs_dosm.h"
+#include "cfs_doss.h"
+#include "cfs_kboo.h"
+#include "cfs_b2b.h"
+#include "cfs_jonw.h"
+#include "cfs_howf.h"
+#include "cfs_robc.h"
+#include "cfs_boot.h"
+
+typedef enum
+{
+ DOS_AUTO,
+ DOS_2,
+ DOS_3,
+ DOS_MY,
+ DOS_SP,
+ DOS_KBOOT,
+ DOS_B2B,
+ DOS_JONW,
+ DOS_HOWF,
+ DOS_ROBC,
+ DOS_BOOT,
+} DOS_TYPE;
+
+void ReadDir( char* szDirName, CDirEntry* pEntry );
+BOOL CheckMask( char* szFname, char* szMask );
+void MakePath( char* szDest, char* szDir, char* szFileName );
+BOOL InitializeFs( DOS_TYPE dostype, BOOL bVerbose );
+// BOOL SWFN_DOST( void* );
+char* GetFSName( DOS_TYPE dostype );
+
+BOOL g_bIsMyDos = FALSE;
+BOOL g_bToLower = FALSE;
+BOOL g_bVerbose = FALSE;
+BOOL g_bListOnly = TRUE;
+BOOL g_bRepairAuto = TRUE;
+
+DOS_TYPE g_dostype = DOS_AUTO;
+DISK_TYPE g_dtypeIn = DISK_AUTO;
+
+char g_szMask[ 256 ] = "*";
+char g_szPath[ 256 ] = ".";
+
+ADisk* g_pDisk;
+CFs* g_pFs;
+
+#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n"
+
+#define HEADER SHEADER \
+ PRG_DESC "\n" \
+ " Latest version can be found at " PRG_URL "\n" \
+ " Published under GPL. See GPL.TXT.\n\n"
+
+#define USAGE HEADER "Usage: " PRG_NAME " " PRG_USAGE
+
+#include "switches.cpp"
+
+int main(int argc,char *argv[])
+{
+ setbuf( stdout, NULL );
+ setbuf( stderr, NULL );
+
+ if ( !SWITCHES_Init( &argc, argv ) )
+ return 1;
+
+ if ( argc < 2 )
+ {
+ SWFN_HELP( USAGE );
+ return 1;
+ }
+
+ fprintf( stderr, SHEADER );
+
+ char* szInfile = argv[ 1 ];
+
+ if ( argc >= 3 )
+ {
+ strcpy( g_szMask, argv[ 2 ] );
+ }
+
+ DISKINIT_RETCODE ret;
+ g_dtypeIn = DISK_ATR;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &g_pDisk, DISK_ATR, szInfile, FALSE, TRUE, g_bRepairAuto ) ) )
+ {
+ g_dtypeIn = DISK_DI;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &g_pDisk, DISK_DI, szInfile, FALSE, FALSE, FALSE ) ) )
+ {
+ g_dtypeIn = DISK_DCM;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &g_pDisk, DISK_DCM, szInfile, FALSE, FALSE, FALSE ) ) )
+ {
+ g_dtypeIn = DISK_SCP;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &g_pDisk, DISK_SCP, szInfile, FALSE, FALSE, FALSE ) ) )
+ {
+ g_dtypeIn = DISK_XFD;
+ if ( DI_RET_CONTINUE == ( ret = InitializeDisk( &g_pDisk, DISK_XFD, szInfile, FALSE, TRUE, g_bRepairAuto ) ) )
+ {
+ printf( "Unable to determine format of disk image '%s'!\n", szInfile );
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ if ( ret == DI_RET_CANT_CONTINUE )
+ return 1;
+
+ printf( "Input file '%s' (%s)\n", szInfile, GetDiskTypeName( g_dtypeIn ) );
+
+
+ if ( g_dostype == DOS_AUTO )
+ {
+ DOS_TYPE bestfs = DOS_AUTO;
+ int iBest = 100;
+
+ printf( "Checking '%s' for possible filesystems:\n", argv[1] );
+
+ if ( InitializeFs( DOS_SP, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_SP;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( InitializeFs( DOS_ROBC, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_ROBC;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( InitializeFs( DOS_MY, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_MY;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( InitializeFs( DOS_2, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_2;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+
+ }
+
+ if ( InitializeFs( DOS_KBOOT, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_KBOOT;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( InitializeFs( DOS_B2B, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_B2B;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( InitializeFs( DOS_JONW, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_JONW;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( InitializeFs( DOS_HOWF, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_HOWF;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( InitializeFs( DOS_3, FALSE ) )
+ {
+ if ( iBest > g_pFs->GetInvalidPercent() )
+ {
+ bestfs = DOS_3;
+ iBest = g_pFs->GetInvalidPercent();
+ }
+ delete g_pFs;
+ }
+
+ if ( ( bestfs == DOS_AUTO ) || iBest )
+ {
+ fprintf( stderr, "\nUnable to guess best filesystem (Best was %s: %d%%). Exiting.\n", GetFSName( bestfs ), iBest );
+ delete g_pDisk;
+ return 1;
+ }
+ else
+ {
+ printf( "\nBest guess:\n" );
+
+ if ( !InitializeFs( bestfs, TRUE ) )
+ {
+ delete g_pDisk;
+ return 1;
+ }
+ }
+
+ }
+ else
+ {
+ if ( !InitializeFs( g_dostype, TRUE ) )
+ {
+ delete g_pDisk;
+ return 1;
+ }
+ }
+
+ CDirEntry* pEntry = g_pFs->GetRoot();
+
+ if ( !pEntry )
+ {
+ fprintf( stderr, "No files found!\n" );
+ delete g_pFs;
+ delete g_pDisk;
+ return 1;
+ }
+
+ {
+ struct stat sbuf;
+ if(stat(g_szPath, &sbuf) != 0)
+ mkdir(g_szPath, 0777);
+ }
+ ReadDir( NULL, pEntry );
+
+ delete g_pFs;
+ delete g_pDisk;
+
+ return 0;
+}
+
+BOOL InitializeFs( DOS_TYPE dostype, BOOL bVerbose )
+{
+ switch( dostype )
+ {
+ case DOS_2:
+ g_pFs = new CDos2();
+ break;
+
+ case DOS_3:
+ g_pFs = new CDos3();
+ break;
+
+ case DOS_MY:
+ g_pFs = new CDosM();
+ break;
+
+ case DOS_SP:
+ g_pFs = new CDosS();
+ break;
+
+ case DOS_KBOOT:
+ g_pFs = new CKBoot();
+ break;
+
+ case DOS_B2B:
+ g_pFs = new CBas2Boot();
+ break;
+
+ case DOS_JONW:
+ g_pFs = new CJonw();
+ break;
+
+ case DOS_HOWF:
+ g_pFs = new CHowf();
+ break;
+
+ case DOS_ROBC:
+ g_pFs = new CRobc();
+ break;
+
+ case DOS_BOOT:
+ g_pFs = new CBoot();
+ break;
+
+ default:
+ if ( bVerbose )
+ fprintf( stderr, "Invalid filesystem specified!\n" );
+ return FALSE;
+ }
+
+ if ( !g_pFs )
+ {
+ if ( bVerbose )
+ fprintf( stderr, "Can't initialize filesystem driver!\n" );
+ return FALSE;
+ }
+
+ if ( !g_pFs->Mount( g_pDisk ) )
+ {
+ if ( bVerbose )
+ fprintf( stderr, "Mount failed because:\n%s\n", g_pFs->GetLastError() );
+ delete g_pFs;
+ return FALSE;
+ }
+
+ printf( "Mounting as %s: Invalid %d%%\n", GetFSName( dostype ), g_pFs->GetInvalidPercent() );
+
+ return TRUE;
+}
+
+void ReadDir( char* szDirName, CDirEntry* pEntry )
+{
+ char szCurrEntryName[ 256 ];
+
+ do
+ {
+ strcpy( szCurrEntryName, pEntry->m_szFname );
+
+ char szFullAtariPath[ 256 ];
+
+ if ( szDirName )
+ MakePath( szFullAtariPath, szDirName, szCurrEntryName );
+ else
+ strcpy( szFullAtariPath, szCurrEntryName );
+
+ char szFullOsPath[ 256 ];
+ MakePath( szFullOsPath, g_szPath, szFullAtariPath );
+
+ if ( CheckMask( szCurrEntryName, g_szMask ) )
+ {
+
+ if ( pEntry->m_dwFlags & DIRE_SUBDIR )
+ {
+ if ( !g_bListOnly )
+ {
+ printf( "Creating dir %s\n", szCurrEntryName );
+ mkdir( szFullOsPath, 0777 );
+ }
+
+ if ( pEntry->m_pSubdir )
+ ReadDir( szFullAtariPath, pEntry->m_pSubdir );
+
+ }
+ else
+ {
+ printf( "%s %s ", pEntry->m_szAscData, szFullAtariPath );
+
+ if ( !g_bListOnly )
+ {
+ BOOL bRes = g_pFs->ExportFile( szFullOsPath, pEntry );
+
+ if ( bRes )
+ {
+ printf( "exported\n" );
+ }
+ else
+ {
+ printf( "invalid because:\n%s\n", g_pFs->GetLastError() );
+ }
+ }
+ else
+ {
+ printf( "\n" );
+ }
+ }
+ }
+
+ pEntry = pEntry->m_pNext;
+
+ } while( pEntry );
+
+ return;
+}
+
+BOOL CheckMask( char* szFname, char* szMask )
+{
+ return fnmatch( szMask, szFname, FNM_NOESCAPE ) ? FALSE : TRUE;
+}
+
+void MakePath( char* szDest, char* szDir, char* szFileName )
+{
+ int iLength;
+
+ if ( szDest != szDir )
+ strcpy ( szDest, szDir );
+
+ iLength = strlen( szDest );
+
+ if ( iLength )
+ {
+ if ( szDest[ iLength - 1 ] != '/' )
+ {
+ szDest[ iLength + 1 ] = '\0';
+ szDest[ iLength ] = '/';
+ }
+ }
+ strcat( szDest, szFileName );
+}
+
+/*
+BOOL SWFN_DOST( void* p )
+{
+ g_dostype = (DOS_TYPE)(int)p;
+
+ return TRUE;
+}
+*/
+
+//returns ptr to filesystem name
+char* GetFSName( DOS_TYPE dostype )
+{
+ switch( dostype )
+ {
+ case DOS_2:
+ return "Dos2";
+
+ case DOS_3:
+ return "Dos3";
+
+ case DOS_MY:
+ return "MyDos";
+
+ case DOS_SP:
+ return "SpartaDos";
+
+ case DOS_KBOOT:
+ return "KBoot";
+
+ case DOS_B2B:
+ return "Bas2Boot";
+
+ case DOS_HOWF:
+ return "HowFen";
+
+ case DOS_ROBC:
+ return "RobC";
+
+ case DOS_BOOT:
+ return "Boot";
+
+ case DOS_JONW:
+ return "JonW";
+
+ default:
+ return "None";
+ }
+}
+
+//returns ptr to disk type name
diff --git a/jindroush/adir/pub.def b/jindroush/adir/pub.def
new file mode 100644
index 0000000..6ec4a31
--- /dev/null
+++ b/jindroush/adir/pub.def
@@ -0,0 +1,31 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define PRG_NAME "adir"
+#define PRG_VERSION "0.67"
+#define PRG_COPYRIGHT "1999-2001"
+#define PRG_UNDERGPL "1"
+#define PRG_AUTHOR "Jindrich Kubec <kubecj@asw.cz>"
+
+#define PRG_URL "http://www.asw.cz/~kubecj"
+
+#define PRG_DESC "Extracts files from Atari disk images."
+#define PRG_USAGE "[options] sourcefile [mask]"
+
+#define PRG_ARCH "PC"
+#define PRG_TOOLS "PERL"
+
+#define PRG_SRCS "!GENERATED!"
+#define PRG_BINS "rel/adir.exe"
diff --git a/jindroush/adir/readme.txt b/jindroush/adir/readme.txt
new file mode 100644
index 0000000..520c067
--- /dev/null
+++ b/jindroush/adir/readme.txt
@@ -0,0 +1,112 @@
+Adir v0.67 (c) 1999-2001 Jindrich Kubec <kubecj@asw.cz>
+Latest version can be found at http://www.asw.cz/~kubecj
+
+This program is provided 'as is', no warranty will be taken
+for any damage caused by it or by any use of it.
+
+The whole package is placed under the GNU Public License, for further
+information on redistribution see the included file "GPL.TXT".
+
+
+Description:
+------------
+Extracts files from Atari disk images.
+Originally based on ATR2UNIX from Preston Crow, now rewritten totally using
+virtual CFs and CDisk classes.
+
+Currently supported are:
+Atari DOS 2.0/2.5 and compatibles
+Atari DOS 3.0
+MyDOS
+Sparta DOS and compatibles (BeWe)
+K-Boot images
+HowFen DOS
+JonW multiboot
+RobC multiboot
+Bas2Boot images
+boot images (extracts boot sector only)
+
+Adir tries to guess the best filesystem. Could be of course overriden by
+switch.
+
+
+Usage:
+------
+Adir [options] sourcefile [mask]
+
+sourcefile is Atari disk image.
+
+-? prints switches
+
+
+History:
+--------
+Date, Author, Version
+4/5/1999, kubecj, 0.10
+First version
+
+5/11/1999, kubecj, 0.20
+Added DOS3 filesystem
+
+5/17/1999, kubecj, 0.30
+Added SpartaDos filesystem
+
+5/22/1999, kubecj, 0.40
+Added KBoot filesystem
+
+5/23/1999, kubecj, 0.50
+Added SCP & DCM disk drivers
+
+6/3/1999, kubecj, 0.55
+Disk drivers synchronized
+
+6/11/1999, kubecj, 0.60
+Added HowFen Dos filesystem
+
+6/12/1999, kubecj, 0.61
+Added Boot filesystem (virtual)
+
+10/10/1999, kubecj, 0.62
+Changed switches processing.
+
+3/30/2000, kubecj, 0.63
+Added autorepair.
+Added Bas2Boot filesystem.
+
+2/26/2001, kubecj, 0.64
+Added handling of DI files.
+
+3/1/2001, kubecj, 0.65
+Compatibility macros for big-endian systems.
+
+3/8/2001, kubecj, 0.66
+Double side support for DI files.
+
+6/12/2001, kubecj, 0.67
+Added RobC fs.
+
+
+To Do:
+------
+Add other file systems. (DOS4)
+Add volume information (useful for Sparta only?)
+Add write capability (after a long time).
+
+
+Known Bugs:
+-----------
+None.
+
+
+Compiling Tools:
+----------------
+For scripts: Perl.
+URL: http://www.perl.com
+
+For PC executables: DJGPP.
+Sources were written/tested on GCC/Intel only. There should be only
+minor problems to port it to different architectures/environments.
+Makefile should need only minor changes.
+URL: http://www.delorie.com
+
+
diff --git a/jindroush/adir/switches.def b/jindroush/adir/switches.def
new file mode 100644
index 0000000..fe61c43
--- /dev/null
+++ b/jindroush/adir/switches.def
@@ -0,0 +1,64 @@
+dos2
+mount as Dos2
+=g_dostype = DOS_2;
+=
+
+dos3
+mount as Dos3
+=g_dostype = DOS_3;
+=
+
+mydos, dosm
+mount as MyDos
+=g_dostype = DOS_MY;
+=
+
+spdos, sparta, doss
+mount as SpartaDos
+=g_dostype = DOS_SP;
+=
+
+kboot
+mount as Kboot
+=g_dostype = DOS_KBOOT;
+=
+
+bas2boot, b2b
+mount as Bas2Boot
+=g_dostype = DOS_B2B;
+=
+
+jonw
+mount as JonW
+=g_dostype = DOS_JONW;
+=
+
+robc
+mount as RobC
+=g_dostype = DOS_ROBC;
+=
+
+howf, howfen
+mount as HowFen Dos
+=g_dostype = DOS_HOWF;
+=
+
+boot
+mount as boot
+=g_dostype = DOS_BOOT;
+=
+
+e
+export files
+=g_bListOnly = FALSE;
+=
+
+dir
+export to directory
+path=bRet = SWFN_GETPATH( g_szPath );
+=
+
+dontrepair
+don't repair invalid files automatically
+=g_bRepairAuto = FALSE;
+=
diff --git a/jindroush/aext/Makefile b/jindroush/aext/Makefile
new file mode 100644
index 0000000..4d016e6
--- /dev/null
+++ b/jindroush/aext/Makefile
@@ -0,0 +1,49 @@
+#=====================================================================
+PRGNAME = aext
+
+DESTDIR=
+PREFIX=/usr
+
+LDLIBS=-L../lib -ljindroush
+INCPATH=-I../include
+
+all: $(PRGNAME)
+
+release:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall -D__CDISK_SAVE__" LDFLAGS=""
+ @echo RELEASE: Compiled.
+
+rel_strip: release
+ @strip $(PRGNAME)
+
+install: rel_strip
+ cp $(PRGNAME) $(DESTDIR)/$(PREFIX)/bin/
+ @echo RELEASE: Installed.
+
+debug:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG -D__CDISK_SAVE__" LDFLAGS="-g"
+ @echo DEBUG: Compiled.
+
+clean:
+ rm -rf *.o $(PRGNAME) $(PRGNAME).exe switches.cpp
+ @echo DEBUG: Cleaned.
+
+
+OBJECTS = aext.o
+
+#=====================================================================
+CXX = g++
+LD = g++
+CPPFLAGS=$(COPT)
+COPT=-O2
+
+#=====================================================================
+
+$(PRGNAME) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME)
+
+%.o : %.cpp switches.cpp
+ $(CXX) $(INCPATH) $(CPPFLAGS) -c $< -o $@
+
+switches.cpp : switches.def ../switches.pl
+ perl ../switches.pl $< $@
diff --git a/jindroush/aext/aext.cpp b/jindroush/aext/aext.cpp
new file mode 100644
index 0000000..75c94c3
--- /dev/null
+++ b/jindroush/aext/aext.cpp
@@ -0,0 +1,280 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "pub.def"
+#include "jintypes.h"
+
+int g_iBlkEnd = 0;
+int g_iBlkStart = 0;
+int g_iBlkLength = 0;
+int g_iBlkBase = 0;
+
+char szStart[ MAX_PATH ];
+char szEnd[ MAX_PATH ];
+char szLength[ MAX_PATH ];
+
+BOOL g_bStartUsed = FALSE;
+BOOL g_bEndUsed = FALSE;
+BOOL g_bLenUsed = FALSE;
+
+int g_bOutputIsAtari = FALSE;
+int g_bUseBase = FALSE;
+
+#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n"
+
+#define HEADER SHEADER \
+ PRG_DESC "\n" \
+ " Latest version can be found at " PRG_URL "\n" \
+ " Published under GPL. See GPL.TXT.\n\n"
+
+#define USAGE HEADER "Usage: " PRG_NAME " " PRG_USAGE
+
+#include "switches.cpp"
+
+int ToNum( char*, int );
+
+int main( int argc, char *argv[] )
+{
+ setbuf( stdout, NULL );
+ setbuf( stderr, NULL );
+
+ if ( !SWITCHES_Init( &argc, argv ) )
+ return 1;
+
+ if ( argc < 2 )
+ {
+ SWFN_HELP( USAGE );
+ return 1;
+ }
+
+ fprintf( stderr, SHEADER );
+
+ char* szInfile = argv[ 1 ];
+
+ char szOutfile[ MAX_PATH ];
+
+ if ( argc >= 3 )
+ {
+ strcpy( szOutfile, argv[ 2 ] );
+ }
+ else
+ {
+ strcpy( szOutfile, "prg.axe" );
+ }
+
+ int hIn = open( szInfile, O_RDONLY | O_BINARY );
+
+ if ( hIn == -1 )
+ {
+ fprintf( stderr, "Can't open infile '%s'!\n", szInfile );
+ return -1;
+ }
+
+ if( g_bStartUsed )
+ {
+ g_iBlkStart = ToNum( szStart, 1 );
+ }
+
+ if( g_bEndUsed )
+ {
+ g_iBlkEnd = ToNum( szEnd, 1 );
+ }
+
+ if( g_bLenUsed )
+ {
+ g_iBlkLength = ToNum( szLength, 0 );
+ }
+
+ LONG lLen = lseek( hIn, 0, SEEK_END );
+ lseek( hIn, 0, SEEK_SET );
+
+ if( g_bEndUsed && g_iBlkEnd < 1 )
+ {
+ g_iBlkEnd = lLen - 1 + g_iBlkEnd;
+ }
+
+ if( g_bStartUsed )
+ {
+ if ( g_bEndUsed )
+ {
+ g_iBlkLength = g_iBlkEnd - g_iBlkStart + 1;
+ }
+ else
+ {
+ //START & ?
+ if ( g_bLenUsed )
+ {
+ //start & length
+ g_iBlkEnd = g_iBlkStart + g_iBlkLength - 1;
+ }
+ else
+ {
+ //start & nothing
+ g_iBlkEnd = lLen - 1;
+ g_iBlkLength = g_iBlkEnd - g_iBlkStart + 1;
+ }
+ }
+
+ }
+ else if( g_bEndUsed )
+ {
+ if( g_bLenUsed )
+ {
+ //end & length
+ g_iBlkStart = g_iBlkEnd - g_iBlkLength + 1;
+ }
+ else
+ {
+ //end only
+ g_iBlkStart = 0;
+ g_iBlkLength = g_iBlkEnd - g_iBlkStart + 1;
+ }
+ }
+ else
+ {
+ if( g_bLenUsed )
+ {
+ //length only
+ g_iBlkStart = 0;
+ g_iBlkEnd = g_iBlkStart + g_iBlkLength - 1;
+ }
+ else
+ {
+ //nothing
+ g_iBlkStart = 0;
+ g_iBlkLength = lLen;
+ g_iBlkEnd = g_iBlkStart + g_iBlkLength - 1;
+ }
+ }
+
+ if( ( g_iBlkStart < 0 ) || ( g_iBlkStart >= lLen ) )
+ {
+ fprintf( stderr, "Invalid start ptr!\n" );
+ close( hIn );
+ return -1;
+ }
+
+ if( ( g_iBlkEnd < 0 ) || ( g_iBlkEnd >= lLen ) || ( g_iBlkEnd < g_iBlkStart ) )
+ {
+ fprintf( stderr, "Invalid end ptr!\n" );
+ close( hIn );
+ return -1;
+ }
+
+ int iBlkStartM = g_iBlkStart;
+ int iBlkEndM = g_iBlkEnd;
+
+ if( g_bUseBase )
+ {
+ iBlkStartM = g_iBlkBase;
+ iBlkEndM = g_iBlkBase + g_iBlkLength - 1;
+ }
+
+ if ( ( ( iBlkEndM >= 0x10000 ) || ( iBlkStartM >= 0x10000 ) ) && g_bOutputIsAtari )
+ {
+ fprintf( stderr, "End goes past end of RAM in real Atari!\n" );
+ close( hIn );
+ return -1;
+ }
+
+ int hOut = open( szOutfile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0666 );
+
+ if ( hOut == -1 )
+ {
+ fprintf( stderr, "Can't open outfile '%s'!\n", szOutfile );
+ close( hIn );
+ return -1;
+ }
+
+ #define BUFLEN 0x10000
+
+ BYTE* pbtPtr = new BYTE [ BUFLEN ];
+ lseek( hIn, g_iBlkStart, SEEK_SET );
+
+ if ( g_bOutputIsAtari )
+ {
+ WORD wStart = iBlkStartM;
+ WORD wEnd = iBlkEndM;
+
+ BYTE btPom = 0xFF;
+ write( hOut, &btPom, 1 );
+ write( hOut, &btPom, 1 );
+
+ btPom = wStart & 0xFF;
+ write( hOut, &btPom, 1 );
+
+ btPom = wStart >> 8;
+ write( hOut, &btPom, 1 );
+
+ btPom = wEnd & 0xFF;
+ write( hOut, &btPom, 1 );
+
+ btPom = wEnd >> 8;
+ write( hOut, &btPom, 1 );
+ }
+
+ int iLeft = g_iBlkLength;
+
+ while( iLeft )
+ {
+ int iReadNow = iLeft > BUFLEN ? BUFLEN : iLeft;
+ read( hIn, pbtPtr, iReadNow );
+ write( hOut, pbtPtr, iReadNow );
+ iLeft -= iReadNow;
+ }
+
+ close( hOut );
+ close( hIn );
+
+ printf( "Done!\n" );
+
+ return 0;
+}
+
+int ToNum( char* szString, int iOffs )
+{
+ BOOL bSec = FALSE;
+
+ if( *szString == 's' )
+ {
+ bSec = TRUE;
+ szString++;
+ }
+
+ int iNum;
+ sscanf( szString, "%X", &iNum );
+
+ if( bSec )
+ {
+ if( iNum < iOffs )
+ {
+ printf( "Incorrect sector number %s\n", szString );
+ return -1;
+ }
+
+ iNum -= iOffs;
+ iNum *= 0x80;
+
+ if( iOffs )
+ {
+ //begin & end
+ iNum += 0x10;
+ }
+
+ //whole code assumes SD ATR file!!!
+ }
+
+ return iNum;
+}
diff --git a/jindroush/aext/pub.def b/jindroush/aext/pub.def
new file mode 100644
index 0000000..19e525e
--- /dev/null
+++ b/jindroush/aext/pub.def
@@ -0,0 +1,31 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define PRG_NAME "aext"
+#define PRG_VERSION "1.02"
+#define PRG_COPYRIGHT "1998-2002"
+#define PRG_UNDERGPL "1"
+#define PRG_AUTHOR "Jindrich Kubec <kubecj@asw.cz>"
+
+#define PRG_URL "http://www.asw.cz/~kubecj"
+
+#define PRG_DESC "Atari file extractor."
+#define PRG_USAGE "[options] infile [outfile]"
+
+#define PRG_ARCH "PC"
+#define PRG_TOOLS "PERL"
+
+#define PRG_SRCS "!GENERATED!"
+#define PRG_BINS "rel/aext.exe"
diff --git a/jindroush/aext/readme.txt b/jindroush/aext/readme.txt
new file mode 100644
index 0000000..f73b129
--- /dev/null
+++ b/jindroush/aext/readme.txt
@@ -0,0 +1,76 @@
+AExt v1.02 (c) 1998-2002 Jindrich Kubec <kubecj@asw.cz>
+Latest version can be found at http://www.asw.cz/~kubecj
+
+This program is provided 'as is', no warranty will be taken
+for any damage caused by it or by any use of it.
+
+The whole package is placed under the GNU Public License, for further
+information on redistribution see the included file "GPL.TXT".
+
+
+Description:
+------------
+Atari file extractor.
+This is just simple utility for extracting binary block in binary/atari binary
+block formats.
+
+
+Usage:
+------
+AExt [options] infile [outfile]
+
+If outfile is not specified, prg.axe is assumed.
+
+-s, -e, -n specify start, end or length parameters of block in hexadecimal
+ numbers.
+
+-oa creates atari binary block (start, end, data).
+
+-base is used with -oa to create based binary block. (The number specifies
+ start address of block).
+
+
+History:
+--------
+Date, Author, Version
+8/19/1999, kubecj, 0.10
+First version.
+
+10/10/1999, kubecj, 0.11
+New archive processing, version incremented to avoid version problems.
+
+10/10/1999, kubecj, 1.00
+First release.
+
+12/10/2001, kubecj, 1.01
+Large block processing.
+-e 0 means end ptr now.
+
+1/23/2002, kubecj, 1.02
+Added useful single density extracting parameters. Now include 's' as first
+character in a number, e.g. -s s06 means start from sixth sector. By definition
+works only on ATR files with 0x80 long sectors.
+
+
+To Do:
+------
+Nothing.
+
+
+Known Bugs:
+-----------
+None.
+
+
+Compiling Tools:
+----------------
+For scripts: Perl.
+URL: http://www.perl.com
+
+For PC executables: DJGPP.
+Sources were written/tested on GCC/Intel only. There should be only
+minor problems to port it to different architectures/environments.
+Makefile should need only minor changes.
+URL: http://www.delorie.com
+
+
diff --git a/jindroush/aext/switches.def b/jindroush/aext/switches.def
new file mode 100644
index 0000000..1bcb33b
--- /dev/null
+++ b/jindroush/aext/switches.def
@@ -0,0 +1,25 @@
+e, end
+end
+hexnum= bRet = SWFN_GETPATH( szEnd );g_bEndUsed = TRUE;
+=
+
+s, start
+start
+hexnum=bRet = SWFN_GETPATH( szStart );g_bStartUsed = TRUE;
+=
+
+n, length
+length
+hexnum=bRet = SWFN_GETPATH( szLength );g_bLenUsed = TRUE;
+=
+
+oa, atari
+output is Atari block
+=g_bOutputIsAtari = TRUE;
+=
+
+base
+base
+hexnum=bRet = SWFN_NUMH( &g_iBlkBase );
+=g_bUseBase = TRUE;
+=
diff --git a/jindroush/bas2boot/Makefile b/jindroush/bas2boot/Makefile
new file mode 100644
index 0000000..9c3a3de
--- /dev/null
+++ b/jindroush/bas2boot/Makefile
@@ -0,0 +1,59 @@
+#=====================================================================
+PRGNAME = bas2boot
+
+all: $(PRGNAME)
+
+release:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall -D__CDISK_SAVE__ -D__CDISK_NOLOAD__" LDFLAGS=""
+ @echo RELEASE: Compiled.
+
+rel_strip:
+ @strip $(PRGNAME).exe
+
+rel_inst:
+ @copy $(PRGNAME).exe $(ATAROOT)\\bin
+ @copy bas2boot.boo $(ATAROOT)\\bin
+ @echo RELEASE: Installed.
+
+debug:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG -D__CDISK_SAVE__ -D__CDISK_NOLOAD__" LDFLAGS="-g"
+ @echo DEBUG: Compiled.
+
+clean:
+ rm -f *.o
+ rm -f $(PRGNAME)
+ rm -f $(PRGNAME).exe
+ rm -f switches.cpp
+ rm -rf rel
+ @echo DEBUG: Cleaned.
+
+#=====================================================================
+INCLUDES = makefile \
+ switches.def \
+ pub.def
+
+
+OBJECTS = bas2boot.o \
+
+#=====================================================================
+CC = g++
+LD = g++
+LDLIBS = -lm -L../lib -ljindroush
+CPPFLAGS=-I../include -D__CDISK_SAVE__ $(COPT)
+COPT=-O2
+
+#=====================================================================
+
+$(PRGNAME): $(OBJECTS) bas2boot.boo
+ $(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME)
+
+bas2boot.o: bas2boot.cpp switches.cpp
+
+%.o: %.cpp $(INCLUDES)
+ $(CC) $(CPPFLAGS) -c $< -o $@
+
+switches.cpp: switches.def ../switches.pl
+ perl ../switches.pl $< $@
+
+bas2boot.boo: bas2boot.asm
+ dasm $< -o$@ -f3
diff --git a/jindroush/bas2boot/bas2boot.asm b/jindroush/bas2boot/bas2boot.asm
new file mode 100644
index 0000000..af7752a
--- /dev/null
+++ b/jindroush/bas2boot/bas2boot.asm
@@ -0,0 +1,169 @@
+;Boot stub for loading BASIC programs from short ATR files.
+;(c) 1998-1999 Jindrich Kubec <kubecj@asw.cz>
+
+; 20070524 bkw: modified to assemble with dasm
+ processor 6502
+
+SIOV = $E459
+
+DOSVEC = $0A
+RAMTOP = $6A
+LOMEM = $80
+BOOT = $09
+BASICF = $03F8
+PORTB = $D301
+
+EOPEN = $EF94
+
+BAS_CONT = $A97A
+BAS_EXEC = $B755
+
+LOADER_START = $0700
+LOADER_END = $0800
+
+BASMEMSTART = $0700
+
+BASPTRSLEN = $0E
+BASPTRSSTART = LOADER_END - BASPTRSLEN
+
+ org LOADER_START
+
+BOOTST: .byte 0
+ .byte (ENDBOOT-BOOTST+127)/128
+ .WORD *-2
+ .WORD MAIN_BEG
+
+ CLC
+RTS_INSTR: RTS
+
+ ;used for extractor
+ORI_LEN: .WORD 0
+
+MAIN_BEG:
+ LDX #<header
+ LDY #>header
+ JSR $C642
+
+ LDX #<padding
+ LDY #>padding
+ JSR $C642
+
+ ;copy pointers to correct area, add $700
+ LDX #BASPTRSLEN - 1
+SETVECT: CLC
+ LDA BASPTRSSTART,X
+ ADC #>BASMEMSTART
+ STA LOMEM,X
+ DEX
+ LDA BASPTRSSTART,X
+ STA LOMEM,X
+ DEX
+ BPL SETVECT
+
+ LDA #$31 ;D
+ STA $300
+ LDA #$01 ;1
+ STA $301
+ LDA #$52 ;read
+ STA $302
+ LDA #$80 ;$80 bytes
+ STA $308
+ LDA #$00
+ STA $309
+ STA $30B
+
+ LDA $82 ;buffer address
+ STA $304
+ LDA $83
+ STA $305
+
+ ;starting sector
+ LDA # ( (ENDBOOT-BOOTST+127)/128 ) +1
+ STA $30A
+SIO_CONT:
+ LDA #$40 ;read
+ STA $303
+
+ JSR SIOV
+ LDA $303
+ CMP #$01
+ BEQ NOERR
+ JSR $C63E
+AGAIN: JMP AGAIN ;dynamic halt
+
+ ;move buffer pointer
+NOERR:
+
+ ;LDA $304
+ ;CLC
+ ;ADC $308
+ ;STA $304
+ ;LDA $305
+ ;ADC $309
+ ;STA $305
+
+ ;this does the same as the above, but is shorter
+ CLC
+ LDX #$FE
+LP0: LDA $304 - $FE,X
+ ADC $308 - $FE,X
+ STA $304 - $FE,X
+ INX
+ BNE LP0
+
+ ;increment sector number
+ INC $30A
+ BNE NX1
+ INC $30B
+NX1:
+ ;decrement number of sectors to load
+ LDA SECTORS
+ BNE NX2
+ DEC SECTORS+1
+ BMI BAS_RUN
+NX2: DEC SECTORS
+ JMP SIO_CONT
+
+BAS_RUN: LDX #$FF
+ TXS
+
+ LDA #$0A
+ STA $C9
+ LDA #$00
+ STA BOOT
+ STA BASICF
+
+ ;turn on basic
+ LDA #$FD
+ STA PORTB
+
+ ;set stack
+ LDA #>BAS_CONT
+ PHA
+ LDA #<BAS_CONT - 1
+ PHA
+
+ LDA #>BAS_EXEC
+ PHA
+ LDA #<BAS_EXEC - 1
+ PHA
+
+ LDA RAMTOP
+ BPL STORE_MEMT
+ LDA #$A0
+STORE_MEMT: STA RAMTOP
+
+ JMP EOPEN
+
+header: .byte "BAS2BOOT (c)1999 Jindroush"
+ .byte $1D
+ .byte $9B
+padding: .ds BASPTRSSTART - padding - 2 - 1, " "
+ .byte $9B
+SECTORS: .WORD 0
+BASPTRSSTART2: .ds BASPTRSLEN
+
+ENDBOOT:
+
+ .END
+
diff --git a/jindroush/bas2boot/bas2boot.boo b/jindroush/bas2boot/bas2boot.boo
new file mode 100644
index 0000000..37a6692
--- /dev/null
+++ b/jindroush/bas2boot/bas2boot.boo
Binary files differ
diff --git a/jindroush/bas2boot/bas2boot.cpp b/jindroush/bas2boot/bas2boot.cpp
new file mode 100644
index 0000000..bb8f2f8
--- /dev/null
+++ b/jindroush/bas2boot/bas2boot.cpp
@@ -0,0 +1,286 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "pub.def"
+#include "jintypes.h"
+#include "autil.h"
+#include "adsk.h"
+
+DISK_TYPE g_dtypeOut = DISK_ATR;
+BOOL g_bClassic = FALSE;
+#define MAX_STRING 256
+char g_szMessage[ MAX_STRING ] = "";
+
+typedef struct
+{
+ WORD w1;
+ WORD w2;
+ WORD w3;
+ WORD w4;
+ WORD w5;
+ WORD w6;
+ WORD w7;
+} BASHEAD;
+
+#define BAS_HEAD_SIZE 0x0E
+
+#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n"
+
+#define HEADER SHEADER \
+ PRG_DESC "\n" \
+ " Latest version can be found at " PRG_URL "\n" \
+ " Published under GPL. See GPL.TXT.\n\n"
+
+#define USAGE HEADER "Usage: " PRG_NAME " " PRG_USAGE
+
+#include "switches.cpp"
+
+int main( int argc, char* argv[] )
+{
+ setbuf( stdout, NULL );
+ setbuf( stderr, NULL );
+
+ if ( !SWITCHES_Init( &argc, argv ) )
+ return 1;
+
+ if ( argc < 2 )
+ {
+ SWFN_HELP( USAGE );
+ return 1;
+ }
+
+ fprintf( stderr, SHEADER );
+
+ char* szInFile = argv[ 1 ];
+ char szOutFile[ MAX_STRING ];
+
+ //setting the message
+ char szMessage[ MAX_STRING ];
+ strcpy( szMessage, g_szMessage );
+
+ //if not present, set to 'Loading prgname'
+ if ( ! *szMessage )
+ {
+ strcpy( szMessage, "Loading " );
+ strcat( szMessage, szInFile );
+ }
+
+ //and pad it with spaces
+ memset( szMessage + strlen( szMessage), 0x20, MAX_STRING - strlen( szMessage ) );
+ szMessage[ MAX_STRING - 1 ] = '\0';
+
+ //get output filename
+ if ( argc >= 3 )
+ {
+ strcpy( szOutFile, argv[ 2 ] );
+ }
+ else
+ {
+ GuessBestFnameFromPC( szOutFile, szInFile, GetDiskTypeExt( g_dtypeOut ) );
+ }
+
+ ADisk* pDisk = NULL;
+ switch( g_dtypeOut )
+ {
+ case DISK_ATR:
+ pDisk = new CAtr();
+ break;
+
+ case DISK_XFD:
+ pDisk = new CXfd();
+ break;
+
+ case DISK_SCP:
+ pDisk = new CScp();
+ break;
+
+ case DISK_DCM:
+ pDisk = new CDcm();
+ break;
+
+ case DISK_DI:
+ pDisk = new CDi();
+ break;
+
+ default:
+ break;
+ }
+
+ if ( !pDisk )
+ {
+ printf( "Can't create such image!\n" );
+ return FALSE;
+ }
+
+ //reads boot stub
+ char szBootName[ MAX_STRING ];
+ strcpy( szBootName, argv[ 0 ] );
+ char* szWhere = strrchr( szBootName, '/' );
+
+ if ( szWhere )
+ szWhere++;
+ else
+ szWhere = szBootName;
+
+ strcpy( szWhere, "bas2boot.boo" );
+
+ CFile cf;
+
+ if ( !cf.Open( szBootName ) )
+ {
+ printf( "Can't open boot image: %s\n", szBootName );
+ return 1;
+ }
+
+ long lBootLen = cf.GetLength();
+
+ if ( lBootLen % 0x80 )
+ {
+ printf( "Invalid boot image: %s\n", szBootName );
+ cf.Close();
+ return 1;
+ }
+
+ BYTE* pbtBoot = new BYTE [ lBootLen ];
+
+ cf.Read( pbtBoot, lBootLen );
+
+ cf.Close();
+
+ int iBootSectors = lBootLen / 0x80;
+
+ if ( pbtBoot[ 1 ] != iBootSectors )
+ {
+ printf( "Invalid boot image: %s\nSize mismatch.\n", szBootName );
+ cf.Close();
+ delete [] pbtBoot;
+ return 1;
+ }
+
+ //open basic file
+ if ( !cf.Open( szInFile ) )
+ {
+ printf( "Can't open source file '%s'!\n", szInFile );
+ return 1;
+ }
+
+ long lBasicLen = cf.GetLength();
+
+ //set real length in header
+ pbtBoot[ 8 ] = lBasicLen & 0xFF;
+ pbtBoot[ 9 ] = lBasicLen >> 8;
+
+ lBasicLen -= BAS_HEAD_SIZE;
+
+ int iBasicSectors = ( lBasicLen + 0x7F ) / 0x80;
+
+ //load and relocate basic header
+ BASHEAD head;
+ head.w1 = cf.readLEw();
+ head.w2 = cf.readLEw() - head.w1;
+ head.w3 = cf.readLEw() - head.w1;
+ head.w4 = cf.readLEw() - head.w1;
+ head.w5 = cf.readLEw() - head.w1;
+ head.w6 = cf.readLEw() - head.w1;
+ head.w7 = cf.readLEw() - head.w1;
+
+ BYTE* pbtHd = pbtBoot + lBootLen - BAS_HEAD_SIZE - 2;
+
+ *( pbtHd++ ) = ( iBasicSectors - 1 ) & 0xFF;
+ *( pbtHd++ ) = ( iBasicSectors - 1 ) >>8;
+
+ *( pbtHd++ ) = head.w1 & 0xFF;
+ *( pbtHd++ ) = head.w1 >> 8;
+
+ *( pbtHd++ ) = head.w2 & 0xFF;
+ *( pbtHd++ ) = head.w2 >> 8;
+
+ *( pbtHd++ ) = head.w3 & 0xFF;
+ *( pbtHd++ ) = head.w3 >> 8;
+
+ *( pbtHd++ ) = head.w4 & 0xFF;
+ *( pbtHd++ ) = head.w4 >> 8;
+
+ *( pbtHd++ ) = head.w5 & 0xFF;
+ *( pbtHd++ ) = head.w5 >> 8;
+
+ *( pbtHd++ ) = head.w6 & 0xFF;
+ *( pbtHd++ ) = head.w6 >> 8;
+
+ *( pbtHd++ ) = head.w7 & 0xFF;
+ *( pbtHd++ ) = head.w7 >> 8;
+
+ //find empty space at the end of boot
+ BYTE* pbtString = pbtBoot + lBootLen - BAS_HEAD_SIZE - 2 - 2;
+ BYTE* pbtStringEnd = pbtString;
+
+ while( *pbtString == 0x20 )
+ pbtString--;
+
+ pbtString++;
+
+ int iStringLen = pbtStringEnd - pbtString;
+
+ //put the message there
+ memcpy( pbtString, szMessage, iStringLen + 1 );
+
+ //read basic program
+ BYTE* pbtBas = new BYTE [ iBasicSectors * 0x80 ];
+ memset( pbtBas, 0, iBasicSectors * 0x80 );
+
+ cf.Read( pbtBas, lBasicLen );
+
+ cf.Close();
+
+ //format disk
+ DISK_GEOMETRY dg;
+
+ if ( g_bClassic )
+ ForceClassicSize( iBasicSectors + iBootSectors, 0x80, &dg );
+ else
+ GuessClassicSizes( iBasicSectors + iBootSectors, 0x80, &dg );
+
+ if ( !pDisk->Format( &dg ) )
+ {
+ delete pDisk;
+ delete[] pbtBoot;
+ delete [] pbtBas;
+ return 1;
+ }
+
+ //write boot & body
+ pDisk->WriteSectors( 1, pbtBoot, iBootSectors );
+ pDisk->WriteSectors( 1 + iBootSectors, pbtBas, iBasicSectors );
+
+ //save it to disk
+ if ( !pDisk->Save( szOutFile, FALSE ) )
+ {
+ printf( "Error! %s\n", pDisk->GetLastError() );
+ delete pDisk;
+ delete [] pbtBoot;
+ delete [] pbtBas;
+ return 1;
+ }
+
+ delete pDisk;
+
+ delete [] pbtBoot;
+ delete [] pbtBas;
+
+ printf( "Written to %s (%s)\n", szOutFile, GetDiskTypeName( g_dtypeOut ) );
+
+ return 0;
+}
+
diff --git a/jindroush/bas2boot/pub.def b/jindroush/bas2boot/pub.def
new file mode 100644
index 0000000..0993bbd
--- /dev/null
+++ b/jindroush/bas2boot/pub.def
@@ -0,0 +1,31 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define PRG_NAME "bas2boot"
+#define PRG_VERSION "1.02"
+#define PRG_COPYRIGHT "1998-2001"
+#define PRG_UNDERGPL "1"
+#define PRG_AUTHOR "Jindrich Kubec <kubecj@asw.cz>"
+
+#define PRG_URL "http://www.asw.cz/~kubecj"
+
+#define PRG_DESC "Converts Basic files to disk images."
+#define PRG_USAGE "[options] basicfile [diskfile]"
+
+#define PRG_ARCH "PC ATARI"
+#define PRG_TOOLS "PERL"
+
+#define PRG_SRCS "!GENERATED!"
+#define PRG_BINS "rel/bas2boot.exe rel/bas2boot.boo"
diff --git a/jindroush/bas2boot/readme.txt b/jindroush/bas2boot/readme.txt
new file mode 100644
index 0000000..010d3fc
--- /dev/null
+++ b/jindroush/bas2boot/readme.txt
@@ -0,0 +1,72 @@
+Bas2Boot v1.02 (c) 1998-2001 Jindrich Kubec <kubecj@asw.cz>
+Latest version can be found at http://www.asw.cz/~kubecj
+
+This program is provided 'as is', no warranty will be taken
+for any damage caused by it or by any use of it.
+
+The whole package is placed under the GNU Public License, for further
+information on redistribution see the included file "GPL.TXT".
+
+
+Description:
+------------
+Converts Basic files to disk images.
+
+
+
+Usage:
+------
+Bas2Boot [options] basicfile [diskfile]
+
+basicfile is source basic filename.
+
+diskfile is output filename. If not specified it's guessed from input filename.
+
+-atr -xfd -scp -dcm -di specify output file format. Default is ATR.
+
+-long forces to use 'classic' disk sizes (SD,DD,ED)
+
+-message text -sets message displayed while loading program
+
+
+History:
+--------
+Date, Author, Version
+4/5/1999, kubecj, 0.92
+First version
+
+6/14/1999, kubecj, 1.00
+First public version
+
+10/10/1999, kubecj, 1.01
+Only version number increment because of different archive processing.
+
+2/26/2001, kubecj, 1.02
+Added DI file format.
+
+
+To Do:
+------
+Nothing.
+
+
+Known Bugs:
+-----------
+None.
+
+
+Compiling Tools:
+----------------
+For scripts: Perl.
+URL: http://www.perl.com
+
+For PC executables: DJGPP.
+Sources were written/tested on GCC/Intel only. There should be only
+minor problems to port it to different architectures/environments.
+Makefile should need only minor changes.
+URL: http://www.delorie.com
+
+For Atari assembler sources: XA65 assembler.
+URL: http://stockholm.ptloma.edu/cbm/xa/.
+
+
diff --git a/jindroush/bas2boot/switches.def b/jindroush/bas2boot/switches.def
new file mode 100644
index 0000000..417e1d4
--- /dev/null
+++ b/jindroush/bas2boot/switches.def
@@ -0,0 +1,32 @@
+atr, a
+output is ATR
+=g_dtypeOut = DISK_ATR;
+=
+
+xfd, x
+output is XFD
+=g_dtypeOut = DISK_XFD;
+=
+
+scp, s
+output is SCP
+=g_dtypeOut = DISK_SCP;
+=g_bClassic = TRUE;
+=
+
+dcm, d
+output is DCM
+=g_dtypeOut = DISK_DCM;
+=g_bClassic = TRUE;
+=
+
+long, classic
+output has 'classic' size
+=g_bClassic = TRUE;
+=
+
+message, mess, text
+message to display while loading
+text=SWFN_GETPATH( g_szMessage );
+=
+
diff --git a/jindroush/chkbas/Makefile b/jindroush/chkbas/Makefile
new file mode 100644
index 0000000..18b1d75
--- /dev/null
+++ b/jindroush/chkbas/Makefile
@@ -0,0 +1,61 @@
+#=====================================================================
+PRGNAME = chkbas
+
+all: $(PRGNAME)
+
+release:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall" LDFLAGS=""
+ @echo RELEASE: Compiled.
+
+rel_strip:
+ @strip $(PRGNAME).exe
+
+rel_inst:
+ @copy $(PRGNAME).exe $(ATAROOT)\\bin
+ @echo RELEASE: Installed.
+
+debug:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG" LDFLAGS="-g"
+ @echo DEBUG: Compiled.
+
+clean:
+ rm -f *.o
+ rm -f $(PRGNAME)
+ rm -f $(PRGNAME).exe
+ rm -f switches.cpp
+ rm -rf rel
+ @echo DEBUG: Cleaned.
+
+#=====================================================================
+INCLUDES = makefile \
+ basic.h \
+ basic_tb.h \
+ basic_xl.h \
+ basic_xe.h \
+ carray.h \
+ wintypes.h
+
+
+OBJECTS = chkbas.o \
+ carray.o \
+ strlwr.o
+
+#=====================================================================
+CC = g++
+LD = g++
+LDLIBS = -lm -L../lib -ljindroush
+CPPFLAGS=-I../include $(COPT)
+COPT=-O2
+
+#=====================================================================
+
+$(PRGNAME) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME)
+
+chkbas.o: chkbas.cpp switches.cpp
+
+%.o:%.cpp $(INCLUDES) switches.cpp
+ $(CC) $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+switches.cpp : switches.def ../switches.pl
+ @perl ../switches.pl $< $@
diff --git a/jindroush/chkbas/basic.h b/jindroush/chkbas/basic.h
new file mode 100644
index 0000000..6fe96fc
--- /dev/null
+++ b/jindroush/chkbas/basic.h
@@ -0,0 +1,152 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+char* aCmdsBasic[] =
+{
+ "REM", //00
+ "DATA", //01
+ "INPUT", //02
+ "COLOR", //03
+ "LIST", //04
+ "ENTER", //05
+ "LET", //06
+ "IF", //07
+ "FOR", //08
+ "NEXT", //09
+ "GOTO", //0a
+ "GO TO", //0b
+ "GOSUB", //0c
+ "TRAP", //0d
+ "BYE", //0e
+ "CONT", //0f
+ "COM", //10
+ "CLOSE", //11
+ "CLR", //12
+ "DEG", //13
+ "DIM", //14
+ "END", //15
+ "NEW", //16
+ "OPEN", //17
+ "LOAD", //18
+ "SAVE", //19
+ "STATUS", //1a
+ "NOTE", //1b
+ "POINT", //1c
+ "XIO", //1d
+ "ON", //1e
+ "POKE", //1f
+ "PRINT", //20
+ "RAD", //21
+ "READ", //22
+ "RESTORE", //23
+ "RETURN", //24
+ "RUN", //25
+ "STOP", //26
+ "POP", //27
+ "?", //28
+ "GET", //29
+ "PUT", //2a
+ "GRAPHICS", //2b
+ "PLOT", //2c
+ "POSITION", //2d
+ "DOS", //2e
+ "DRAWTO", //2f
+ "SETCOLOR", //30
+ "LOCATE", //31
+ "SOUND", //32
+ "LPRINT", //33
+ "CSAVE", //34
+ "CLOAD", //35
+ "", //36 silent let
+ "ERROR -", //37 last Atari Basic command
+};
+
+char* aOpsBasic[] = {
+ "NCONST", //0E
+ "SCONST", //0F
+ "NOUSE", //10
+ "NOUSE", //11
+ ",", //12
+ "$", //13
+ ":", //14
+ ";", //15
+ "EOL", //16
+ " GOTO ", //17
+ " GOSUB ", //18
+ " TO ", //19
+ " STEP ", //1A
+ " THEN ", //1B
+ "#", //1C
+ "<=", //1D
+ "<>", //1E
+ ">=", //1F
+ "<", //20
+ ">", //21
+ "=", //22
+ "^", //23
+ "*", //24
+ "+", //25
+ "-", //26
+ "/", //27
+ " NOT ", //28
+ " OR ", //29
+ " AND ", //2A
+ "(", //2B
+ ")", //2C
+ "=", //2D
+ "=", //2E
+ "<=", //2F
+ "<>", //30
+ ">=", //31
+ "<", //32
+ ">", //33
+ "=", //34
+ "+", //35
+ "-", //36
+ "(", //37
+ "(", //38
+ "(", //39
+ "(", //3A
+ "(", //3B
+ ",", //3C
+ "STR$", //3D
+ "CHR$", //3E
+ "USR", //3F
+ "ASC", //40
+ "VAL", //41
+ "LEN", //42
+ "ADR", //43
+ "ATN", //44
+ "COS", //45
+ "PEEK", //46
+ "SIN", //47
+ "RND", //48
+ "FRE", //49
+ "EXP", //4A
+ "LOG", //4B
+ "CLOG", //4C
+ "SQR", //4D
+ "SGN", //4E
+ "ABS", //4F
+ "INT", //50
+ "PADDLE", //51
+ "STICK", //52
+ "PTRIG", //53
+ "STRIG", //54 last Atari Basic
+};
+
+#define BASIC_CMD_NUM ( sizeof( aCmdsBasic ) / sizeof( aCmdsBasic[ 0 ] ) )
+#define BASIC_OPS_NUM ( sizeof( aOpsBasic ) / sizeof( aOpsBasic[ 0 ] ) )
+
diff --git a/jindroush/chkbas/basic_tb.h b/jindroush/chkbas/basic_tb.h
new file mode 100644
index 0000000..8547948
--- /dev/null
+++ b/jindroush/chkbas/basic_tb.h
@@ -0,0 +1,223 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+char* aCmdsTBasic[] =
+{
+ "REM", //00
+ "DATA", //01
+ "INPUT", //02
+ "COLOR", //03
+ "LIST", //04
+ "ENTER", //05
+ "LET", //06
+ "IF", //07
+ "FOR", //08
+ "NEXT", //09
+ "GOTO", //0a
+ "GO TO", //0b
+ "GOSUB", //0c
+ "TRAP", //0d
+ "BYE", //0e
+ "CONT", //0f
+ "COM", //10
+ "CLOSE", //11
+ "CLR", //12
+ "DEG", //13
+ "DIM", //14
+ "END", //15
+ "NEW", //16
+ "OPEN", //17
+ "LOAD", //18
+ "SAVE", //19
+ "STATUS", //1a
+ "NOTE", //1b
+ "POINT", //1c
+ "XIO", //1d
+ "ON", //1e
+ "POKE", //1f
+ "PRINT", //20
+ "RAD", //21
+ "READ", //22
+ "RESTORE", //23
+ "RETURN", //24
+ "RUN", //25
+ "STOP", //26
+ "POP", //27
+ "?", //28
+ "GET", //29
+ "PUT", //2a
+ "GRAPHICS", //2b
+ "PLOT", //2c
+ "POSITION", //2d
+ "DOS", //2e
+ "DRAWTO", //2f
+ "SETCOLOR", //30
+ "LOCATE", //31
+ "SOUND", //32
+ "LPRINT", //33
+ "CSAVE", //34
+ "CLOAD", //35
+ "", //36 silent let
+ "ERROR -", //37 last Atari Basic command
+ "DPOKE", //38
+ "MOVE", //39
+ "-MOVE", //3A
+ "*F", //3B
+ "REPEAT", //3C
+ "UNTIL", //3D
+ "WHILE", //3E
+ "WEND", //3F
+ "ELSE", //40
+ "ENDIF", //41
+ "BPUT", //42
+ "BGET", //43
+ "FILLTO", //44
+ "DO", //45
+ "LOOP", //46
+ "EXIT", //47
+ "DIR", //48
+ "LOCK", //49
+ "UNLOCK", //4A
+ "RENAME", //4B
+ "DELETE", //4C
+ "PAUSE", //4D
+ "TIME$=", //4E
+ "PROC", //4F
+ "EXEC", //50
+ "ENDPROC", //51
+ "FCOLOR", //52
+ "*L", //53
+ "------------------------------", //54
+ "RENUM", //55
+ "DEL", //56
+ "DUMP", //57
+ "TRACE", //58
+ "TEXT", //59
+ "BLOAD", //5A
+ "BRUN", //5B
+ "GO#", //5C
+ "#", //5D
+ "*B", //5E
+ "PAINT", //5F
+ "CLS", //60
+ "DSOUND", //61
+ "CIRCLE", //62
+ "\%PUT", //63
+ "\%GET", //64
+};
+
+char* aOpsTBasic[] = {
+ "NHCONST", //0D
+ "NCONST", //0E
+ "SCONST", //0F
+ "NOUSE", //10
+ "NOUSE", //11
+ ",", //12
+ "$", //13
+ ":", //14
+ ";", //15
+ "EOL", //16
+ " GOTO ", //17
+ " GOSUB ", //18
+ " TO ", //19
+ " STEP ", //1A
+ " THEN ", //1B
+ "#", //1C
+ "<=", //1D
+ "<>", //1E
+ ">=", //1F
+ "<", //20
+ ">", //21
+ "=", //22
+ "^", //23
+ "*", //24
+ "+", //25
+ "-", //26
+ "/", //27
+ " NOT ", //28
+ " OR ", //29
+ " AND ", //2A
+ "(", //2B
+ ")", //2C
+ "=", //2D
+ "=", //2E
+ "<=", //2F
+ "<>", //30
+ ">=", //31
+ "<", //32
+ ">", //33
+ "=", //34
+ "+", //35
+ "-", //36
+ "(", //37
+ "(", //38
+ "(", //39
+ "(", //3A
+ "(", //3B
+ ",", //3C
+ "STR$", //3D
+ "CHR$", //3E
+ "USR", //3F
+ "ASC", //40
+ "VAL", //41
+ "LEN", //42
+ "ADR", //43
+ "ATN", //44
+ "COS", //45
+ "PEEK", //46
+ "SIN", //47
+ "RND", //48
+ "FRE", //49
+ "EXP", //4A
+ "LOG", //4B
+ "CLOG", //4C
+ "SQR", //4D
+ "SGN", //4E
+ "ABS", //4F
+ "INT", //50
+ "PADDLE", //51
+ "STICK", //52
+ "PTRIG", //53
+ "STRIG", //54 last Atari Basic
+ "DPEEK", //55
+ "&", //56
+ "!", //57
+ "INSTR", //58
+ "INKEY$", //59
+ " EXOR ", //5A
+ "HEX$", //5B
+ "DEC", //5C
+ " DIV ", //5D
+ "FRAC", //5E
+ "TIME$", //5F
+ "TIME", //60
+ " MOD ", //61
+ " EXEC ", //62
+ "RND", //63
+ "RAND", //64
+ "TRUNC", //65
+ "%0", //66
+ "%1", //67
+ "%2", //68
+ "%3", //69
+ " GO# ", //6A
+ "UINSTR", //6B
+ "ERR", //6C
+ "ERL", //6D
+};
+
+#define TBASIC_CMD_NUM ( sizeof( aCmdsTBasic ) / sizeof( aCmdsTBasic[ 0 ] ) )
+#define TBASIC_OPS_NUM ( sizeof( aOpsTBasic ) / sizeof( aOpsTBasic[ 0 ] ) )
+
diff --git a/jindroush/chkbas/basic_xe.h b/jindroush/chkbas/basic_xe.h
new file mode 100644
index 0000000..fc86131
--- /dev/null
+++ b/jindroush/chkbas/basic_xe.h
@@ -0,0 +1,219 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+char* aCmdsBasicXe[] =
+{
+ "REM", //00
+ "DATA", //01
+ "INPUT", //02
+ "COLOR", //03
+ "LIST", //04
+ "ENTER", //05
+ "LET", //06
+ "IF", //07
+ "FOR", //08
+ "NEXT", //09
+ "GOTO", //0a
+ "GO TO", //0b
+ "GOSUB", //0c
+ "TRAP", //0d
+ "BYE", //0e
+ "CONT", //0f
+ "COM", //10
+ "CLOSE", //11
+ "CLR", //12
+ "DEG", //13
+ "DIM", //14
+ "END", //15
+ "NEW", //16
+ "OPEN", //17
+ "LOAD", //18
+ "SAVE", //19
+ "STATUS", //1a
+ "NOTE", //1b
+ "POINT", //1c
+ "XIO", //1d
+ "ON", //1e
+ "POKE", //1f
+ "PRINT", //20
+ "RAD", //21
+ "READ", //22
+ "RESTORE", //23
+ "RETURN", //24
+ "RUN", //25
+ "STOP", //26
+ "POP", //27
+ "?", //28
+ "GET", //29
+ "PUT", //2a
+ "GRAPHICS", //2b
+ "PLOT", //2c
+ "POSITION", //2d
+ "DOS", //2e
+ "DRAWTO", //2f
+ "SETCOLOR", //30
+ "LOCATE", //31
+ "SOUND", //32
+ "LPRINT", //33
+ "CSAVE", //34
+ "CLOAD", //35
+ "", //36 silent let
+ "ERROR -", //37 last Atari Basic command
+
+ "WHILE", //38
+ "ENDWHILE", //39
+ "TRACEOFF", //3A
+ "TRACE", //3B
+ "ELSE", //3C
+ "ENDIF", //3D
+ "DPOKE", //3E
+ "LOMEM", //3F
+ "DEL", //40
+ "RPUT", //41
+ "RGET", //42
+ "BPUT", //43
+ "BGET", //44
+ "TAB", //45
+ "CP", //46
+ "ERASE", //47
+ "PROTECT", //48
+ "UNPROTECT", //49
+ "DIR", //4A
+ "RENAME", //4B
+ "MOVE", //4C
+ "MISSILE", //4D
+ "PMCLR", //4E
+ "PMCOLOR", //4F
+ "PMGRAPHICS", //50
+ "PMMOVE", //51
+ "PMWIDTH", //52
+ "SET", //53
+ "LVAR", //54
+ "RENUM", //55
+ "FAST", //56
+ "LOCAL", //57
+ "EXTEND", //58
+ "PROCEDURE", //59
+ "?5A?", //5A
+ "CALL", //5B
+ "SORTUP", //5C
+ "SORTDOWN", //5D
+ "EXIT", //5E
+ "NUM", //5F
+ "HITCLR", //60
+ "INVERSE", //61
+ "NORMAL", //62
+ "BLOAD", //63
+ "BSAVE", //64
+};
+
+char* aOpsBasicXe[] = {
+ "NHCONST", //0D
+ "NCONST", //0E
+ "SCONST", //0F
+ "NOUSE", //10
+ "NOUSE", //11
+ ",", //12
+ "$", //13
+ ":", //14
+ ";", //15
+ "EOL", //16
+ " GOTO ", //17
+ " GOSUB ", //18
+ " TO ", //19
+ " STEP ", //1A
+ " THEN ", //1B
+ "#", //1C
+ "<=", //1D
+ "<>", //1E
+ ">=", //1F
+ "<", //20
+ ">", //21
+ "=", //22
+ "^", //23
+ "*", //24
+ "+", //25
+ "-", //26
+ "/", //27
+ " NOT ", //28
+ " OR ", //29
+ " AND ", //2A
+ "(", //2B
+ ")", //2C
+ "=", //2D
+ "=", //2E
+ "<=", //2F
+ "<>", //30
+ ">=", //31
+ "<", //32
+ ">", //33
+ "=", //34
+ "+", //35
+ "-", //36
+ "(", //37
+ "(", //38
+ "(", //39
+ "(", //3A
+ "(", //3B
+ ",", //3C
+ "STR$", //3D
+ "CHR$", //3E
+ "USR", //3F
+ "ASC", //40
+ "VAL", //41
+ "LEN", //42
+ "ADR", //43
+ "ATN", //44
+ "COS", //45
+ "PEEK", //46
+ "SIN", //47
+ "RND", //48
+ "FRE", //49
+ "EXP", //4A
+ "LOG", //4B
+ "CLOG", //4C
+ "SQR", //4D
+ "SGN", //4E
+ "ABS", //4F
+ "INT", //50
+ "PADDLE", //51
+ "STICK", //52
+ "PTRIG", //53
+ "STRIG", //54 last Atari Basic
+ " USING ", //55
+ "%", //56
+ "!", //57
+ "&", //58
+ ";", //59
+ "BUMP(", //5A
+ "FIND(", //5B
+ "HEX$", //5C
+ "RANDOM(", //5D
+ "DPEEK", //5E
+ "SYS", //5F
+ "VSTICK", //60
+ "HSTICK", //61
+ "PMADR", //62
+ "ERR", //63
+ "TAB", //64
+ "PEN", //65
+ "LEFT$", //66
+ "RIGHT$", //67
+ "MID$", //68
+};
+
+#define BASICXE_CMD_NUM ( sizeof( aCmdsBasicXe ) / sizeof( aCmdsBasicXe[ 0 ] ) )
+#define BASICXE_OPS_NUM ( sizeof( aOpsBasicXe ) / sizeof( aOpsBasicXe[ 0 ] ) )
+
diff --git a/jindroush/chkbas/basic_xl.h b/jindroush/chkbas/basic_xl.h
new file mode 100644
index 0000000..a97f8a7
--- /dev/null
+++ b/jindroush/chkbas/basic_xl.h
@@ -0,0 +1,213 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define BXL_EXTEND 0x5A
+
+char* aCmdsBasicXl[] =
+{
+ "REM", //00
+ "DATA", //01
+ "INPUT", //02
+ "COLOR", //03
+ "LIST", //04
+ "ENTER", //05
+ "LET", //06
+ "IF", //07
+ "FOR", //08
+ "NEXT", //09
+ "GOTO", //0a
+ "GO TO", //0b
+ "GOSUB", //0c
+ "TRAP", //0d
+ "BYE", //0e
+ "CONT", //0f
+ "COM", //10
+ "CLOSE", //11
+ "CLR", //12
+ "DEG", //13
+ "DIM", //14
+ "END", //15
+ "NEW", //16
+ "OPEN", //17
+ "LOAD", //18
+ "SAVE", //19
+ "STATUS", //1a
+ "NOTE", //1b
+ "POINT", //1c
+ "XIO", //1d
+ "ON", //1e
+ "POKE", //1f
+ "PRINT", //20
+ "RAD", //21
+ "READ", //22
+ "RESTORE", //23
+ "RETURN", //24
+ "RUN", //25
+ "STOP", //26
+ "POP", //27
+ "?", //28
+ "GET", //29
+ "PUT", //2a
+ "GRAPHICS", //2b
+ "PLOT", //2c
+ "POSITION", //2d
+ "DOS", //2e
+ "DRAWTO", //2f
+ "SETCOLOR", //30
+ "LOCATE", //31
+ "SOUND", //32
+ "LPRINT", //33
+ "CSAVE", //34
+ "CLOAD", //35
+ "", //36 silent let
+ "ERROR -", //37 last Atari Basic command
+
+ "WHILE", //38
+ "ENDWHILE", //39
+ "TRACEOFF", //3A
+ "TRACE", //3B
+ "ELSE", //3C
+ "ENDIF", //3D
+ "DPOKE", //3E
+ "LOMEM", //3F
+ "DEL", //40
+ "RPUT", //41
+ "RGET", //42
+ "BPUT", //43
+ "BGET", //44
+ "TAB", //45
+ "CP", //46
+ "ERASE", //47
+ "PROTECT", //48
+ "UNPROTECT", //49
+ "DIR", //4A
+ "RENAME", //4B
+ "MOVE", //4C
+ "MISSILE", //4D
+ "PMCLR", //4E
+ "PMCOLOR", //4F
+ "PMGRAPHICS", //50
+ "PMMOVE", //51
+ "PMWIDTH", //52
+ "SET", //53
+ "LVAR", //54
+ "RENUM", //55
+ "FAST", //56
+ "NUM", //57
+ "END", //58
+
+ "?59?", //59
+ "BXL_EXTEND", //5A
+
+};
+
+char* aOpsBasicXl[] = {
+ "NHCONST", //0D
+ "NCONST", //0E
+ "SCONST", //0F
+ "NOUSE", //10
+ "NOUSE", //11
+ ",", //12
+ "$", //13
+ ":", //14
+ ";", //15
+ "EOL", //16
+ " GOTO ", //17
+ " GOSUB ", //18
+ " TO ", //19
+ " STEP ", //1A
+ " THEN ", //1B
+ "#", //1C
+ "<=", //1D
+ "<>", //1E
+ ">=", //1F
+ "<", //20
+ ">", //21
+ "=", //22
+ "^", //23
+ "*", //24
+ "+", //25
+ "-", //26
+ "/", //27
+ " NOT ", //28
+ " OR ", //29
+ " AND ", //2A
+ "(", //2B
+ ")", //2C
+ "=", //2D
+ "=", //2E
+ "<=", //2F
+ "<>", //30
+ ">=", //31
+ "<", //32
+ ">", //33
+ "=", //34
+ "+", //35
+ "-", //36
+ "(", //37
+ "(", //38
+ "(", //39
+ "(", //3A
+ "(", //3B
+ ",", //3C
+ "STR$", //3D
+ "CHR$", //3E
+ "USR", //3F
+ "ASC", //40
+ "VAL", //41
+ "LEN", //42
+ "ADR", //43
+ "ATN", //44
+ "COS", //45
+ "PEEK", //46
+ "SIN", //47
+ "RND", //48
+ "FRE", //49
+ "EXP", //4A
+ "LOG", //4B
+ "CLOG", //4C
+ "SQR", //4D
+ "SGN", //4E
+ "ABS", //4F
+ "INT", //50
+ "PADDLE", //51
+ "STICK", //52
+ "PTRIG", //53
+ "STRIG", //54 last Atari Basic
+ " USING ", //55
+ "%", //56
+ "!", //57
+ "&", //58
+ ";", //59
+ "BUMP(", //5A
+ "FIND(", //5B
+ "HEX$", //5C
+ "RANDOM(", //5D
+ "DPEEK", //5E
+ "SYS", //5F
+ "VSTICK", //60
+ "HSTICK", //61
+ "PMADR", //62
+ "ERR", //63
+ "TAB", //64
+ "PEN", //65
+ "LEFT$", //66
+ "RIGHT$", //67
+ "MID$", //68
+};
+
+#define BASICXL_CMD_NUM ( sizeof( aCmdsBasicXl ) / sizeof( aCmdsBasicXl[ 0 ] ) )
+#define BASICXL_OPS_NUM ( sizeof( aOpsBasicXl ) / sizeof( aOpsBasicXl[ 0 ] ) )
+
diff --git a/jindroush/chkbas/carray.cpp b/jindroush/chkbas/carray.cpp
new file mode 100644
index 0000000..212b0f3
--- /dev/null
+++ b/jindroush/chkbas/carray.cpp
@@ -0,0 +1,158 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "carray.h"
+
+//constructs new object - 0 size
+CArray::CArray()
+{
+ m_iAllocatedBlocks = 0;
+ m_iArrayItems = 0;
+ m_pFirstBlock = NULL;
+}
+
+//destructor calls destroy
+CArray::~CArray()
+{
+ Destroy();
+}
+
+//destructs all sub array blocks
+void CArray::Destroy()
+{
+ if ( m_iAllocatedBlocks )
+ {
+ SubArray* pCurr = m_pFirstBlock;
+ SubArray* pNext;
+
+ while ( pCurr )
+ {
+ pNext = pCurr->pNext;
+ delete pCurr;
+ pCurr = pNext;
+ }
+ }
+
+ m_iAllocatedBlocks = 0;
+ m_iArrayItems = 0;
+ m_pFirstBlock = NULL;
+}
+
+//deletes last item
+BOOL CArray::DeleteLast()
+{
+ m_iArrayItems--;
+ return TRUE;
+}
+
+//gets value from array
+void* CArray::GetAt( int iItem )
+{
+ if ( ( iItem + 1 ) > m_iArrayItems )
+ return NULL;
+
+ int iBlockNeeded = iItem / CARRAY_SUB_SIZE;
+
+ int iBlockCurr = 0;
+
+ SubArray* pCurr = m_pFirstBlock;
+
+ while( iBlockCurr < iBlockNeeded )
+ {
+ pCurr = pCurr->pNext;
+ iBlockCurr++;
+
+ if ( !pCurr )
+ return NULL;
+ }
+
+ return pCurr->array[ iItem % CARRAY_SUB_SIZE ];
+}
+
+//sets array's value - must exist before
+BOOL CArray::SetAt( int iItem, void* pPtr )
+{
+ if ( ( iItem + 1 ) > m_iArrayItems )
+ return FALSE;
+
+ int iBlockNeeded = iItem / CARRAY_SUB_SIZE;
+
+ int iBlockCurr = 0;
+
+ SubArray* pCurr = m_pFirstBlock;
+
+ while( iBlockCurr < iBlockNeeded )
+ {
+ pCurr = pCurr->pNext;
+ iBlockCurr++;
+ if ( !pCurr )
+ return FALSE;
+ }
+
+ pCurr->array[ iItem % CARRAY_SUB_SIZE ] = pPtr;
+ return TRUE;
+}
+
+//adds array's value
+BOOL CArray::Add( void* pPtr )
+{
+ if ( ((( m_iArrayItems ) / CARRAY_SUB_SIZE ) + 1 ) > m_iAllocatedBlocks )
+ {
+ //if we need new block, we try to add them
+ if ( !AddNewBlock() )
+ return FALSE;
+ }
+
+ m_iArrayItems++;
+
+ if ( !SetAt( m_iArrayItems - 1, pPtr ) )
+ {
+ m_iArrayItems--;
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+//adds new sub array block
+BOOL CArray::AddNewBlock()
+{
+ SubArray* pCurr = m_pFirstBlock;
+ SubArray* pNext = m_pFirstBlock;
+
+ //find end
+ while ( pNext )
+ {
+ pCurr = pNext;
+ pNext = pCurr->pNext;
+ }
+
+ if ( !( pNext = new SubArray ) )
+ return FALSE;
+
+ memset( pNext, 0, sizeof( SubArray) );
+
+ if ( !m_pFirstBlock )
+ m_pFirstBlock = pNext;
+ else
+ pCurr->pNext = pNext;
+
+ m_iAllocatedBlocks++;
+
+ return TRUE;
+}
+
+
diff --git a/jindroush/chkbas/carray.h b/jindroush/chkbas/carray.h
new file mode 100644
index 0000000..9779cad
--- /dev/null
+++ b/jindroush/chkbas/carray.h
@@ -0,0 +1,49 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "jintypes.h"
+
+#ifndef __CARRAY_H__
+#define __CARRAY_H__
+
+#define CARRAY_SUB_SIZE 16
+
+typedef struct sa
+{
+ struct sa* pPrev;
+ struct sa* pNext;
+ void* array[ CARRAY_SUB_SIZE ];
+
+} SubArray;
+
+class CArray
+{
+public:
+ CArray();
+ ~CArray();
+ void* GetAt( int );
+ BOOL SetAt( int, void* );
+ int GetSize() { return m_iArrayItems; };
+ BOOL Add( void* );
+ BOOL DeleteLast();
+ void Destroy();
+private:
+ BOOL AddNewBlock();
+ int m_iAllocatedBlocks;
+ int m_iArrayItems;
+ SubArray * m_pFirstBlock;
+};
+
+#endif
diff --git a/jindroush/chkbas/chkbas.cpp b/jindroush/chkbas/chkbas.cpp
new file mode 100644
index 0000000..a1ad505
--- /dev/null
+++ b/jindroush/chkbas/chkbas.cpp
@@ -0,0 +1,1009 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "jintypes.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+#include "carray.h"
+#include "cfile.h"
+
+#include "pub.def"
+
+#include "basic.h"
+#include "basic_tb.h"
+#include "basic_xl.h"
+#include "basic_xe.h"
+
+extern void strlwr(char *);
+
+typedef enum
+{
+ BASIC = 0, //standard basic
+ BASIC_TB = 1, //Turbo Basic
+ BASIC_XL = 2, //OSS Basic XL
+ BASIC_XE = 3, //OSS Basic XE
+ BASIC_XEX = 4 //OSS Basic XE in extended mode
+} BASIC_TYPE;
+
+typedef struct
+{
+ char** ppCommands; //array of commands
+ char** ppOperands; //array of operands
+
+ int iCmdNum; //number of commands
+ int iOpNum; //number of operands
+ int iOpFirst; //first operand
+} LANGDESC;
+
+LANGDESC langtbl[] =
+{
+ { aCmdsBasic, aOpsBasic, BASIC_CMD_NUM, BASIC_OPS_NUM, 0x0E },
+ { aCmdsTBasic, aOpsTBasic, TBASIC_CMD_NUM, TBASIC_OPS_NUM, 0x0D },
+ { aCmdsBasicXl, aOpsBasicXl, BASICXL_CMD_NUM, BASICXL_OPS_NUM, 0x0D },
+ { aCmdsBasicXe, aOpsBasicXe, BASICXE_CMD_NUM, BASICXE_OPS_NUM, 0x0D },
+ { aCmdsBasicXe, aOpsBasicXe, BASICXE_CMD_NUM, BASICXE_OPS_NUM, 0x0D },
+};
+
+#define OP_NHCONST 0x0D
+#define OP_NCONST 0x0E
+#define OP_SCONST 0x0F
+#define OP_EOL 0x16
+
+#define VART_SCALAR 0x00
+
+#define VART_ARRAYU 0x40
+#define VART_ARRAY 0x41
+
+#define VART_STRINGU 0x80
+#define VART_STRING 0x81
+
+#define VART_STRINGAU 0x90
+#define VART_STRINGA 0x91
+
+#define VART_PROC 0xC1
+#define VART_LABEL 0xC2
+
+#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n"
+
+#define HEADER SHEADER \
+ PRG_DESC "\n" \
+ " Latest version can be found at " PRG_URL "\n" \
+ " Published under GPL. See GPL.TXT.\n" \
+ " Thanks to Russ Gilbert for his SALVAGE programs.\n\n"
+
+#define USAGE HEADER "Usage: " PRG_NAME " " PRG_USAGE
+
+BOOL GenCode( CFile* pcf, DWORD dwStart, DWORD dwEnd );
+BOOL GenLineCode( CFile* pcf, DWORD dwEnd );
+BOOL GenCmdCode( CFile* pcf, DWORD dwLineStart, DWORD dwLineEnd );
+BOOL GenOpsCode( CFile* pcf, DWORD dwTokEnd );
+double ReadAtariBCD( CFile* pcf );
+
+BOOL Vars_Load( CFile* pcf, WORD wVNT, WORD wVNTL, WORD wVVT, WORD NV );
+void Var_Get( char* szRet, int iNum );
+void Vars_Destroy();
+
+FILE* g_fout = NULL;
+CArray g_aVariables; //array of variables
+
+BOOL g_bVerbose = FALSE; //verbose output
+BOOL g_bAtariOut = FALSE; //atari output
+BOOL g_bExtOut = TRUE; //extended output
+BOOL g_bHasErrors = FALSE; //decode error flag
+BOOL g_bNoInverse = FALSE; //don't emit inverse
+BASIC_TYPE g_Type = BASIC; //basic type. Default is Atari Basic
+
+char** g_aBasicCmds; //array of commands
+char** g_aBasicOps; //array of operands
+int g_iCmdNum; //number of commands
+int g_iOpsNum; //number of operands
+int g_iOpFirst; //first operand
+
+#include "switches.cpp"
+
+int main( int argc, char* argv[] )
+{
+ setbuf( stdout, NULL );
+ setbuf( stderr, NULL );
+
+ if ( !SWITCHES_Init( &argc, argv ) )
+ return 1;
+
+ if(strstr(argv[0], "listbas"))
+ g_bExtOut = FALSE;
+
+ if ( argc < 2 )
+ {
+ SWFN_HELP( USAGE );
+ return 1;
+ }
+
+ if ( g_bExtOut )
+ fprintf( stderr, SHEADER "\n" );
+ else
+ fprintf( stderr, HEADER );
+
+ char* szInfile = argv[ 1 ];
+ char* szOutfile = NULL;
+
+ if ( argc > 2 )
+ szOutfile = argv[ 2 ];
+
+ CFile cf;
+
+ if ( !cf.Open( szInfile ) )
+ {
+ fprintf( stderr, "Can't open input file '%s'\n", szInfile );
+ return 1;
+ }
+
+ if ( szOutfile )
+ {
+ if( g_bAtariOut )
+ g_fout = fopen( szOutfile, "wb" ); //opening as binary because of
+ //atascii
+ else
+ g_fout = fopen( szOutfile, "wt" );
+ }
+
+ if ( !g_fout )
+ g_fout = stdout;
+
+ //Don't emit additional info if you are in Atari mode
+ if ( g_bAtariOut )
+ g_bExtOut = FALSE;
+
+ if ( g_bExtOut )
+ {
+ fprintf( g_fout, HEADER );
+ fprintf( g_fout, "Input file: %s\n\n", szInfile );
+ }
+
+ //initialize globals depending on language set
+ g_aBasicCmds = langtbl[ g_Type ].ppCommands;
+ g_aBasicOps = langtbl[ g_Type ].ppOperands;
+ g_iCmdNum = langtbl[ g_Type ].iCmdNum;
+ g_iOpsNum = langtbl[ g_Type ].iOpNum;
+ g_iOpFirst = langtbl[ g_Type ].iOpFirst;
+
+ DWORD dwFileLen = cf.GetLength();
+
+ //read head
+ WORD wLOMEM = cf.readLEw();
+ WORD wVNT = cf.readLEw();
+ WORD wVNTE = cf.readLEw();
+ WORD wVVT = cf.readLEw();
+ WORD wSTMTAB = cf.readLEw();
+ WORD wSTMCUR = cf.readLEw();
+ WORD wSTARP = cf.readLEw();
+
+ if( ( wLOMEM == 0x00DD ) && ( g_Type == BASIC_XE ) )
+ {
+ //extended mode of Basic XE
+ wLOMEM = 0;
+ g_Type = BASIC_XEX;
+ }
+
+ WORD wCOR = wVNT - wLOMEM - 0x0E;
+
+ wVNT -= wCOR;
+ wVNTE -= wCOR;
+ wVVT -= wCOR;
+ wSTMTAB -= wCOR;
+ wSTMCUR -= wCOR;
+ wSTARP -= wCOR;
+
+ WORD wVNTL = wVNTE - wVNT + 1;
+ WORD wVVTE = wSTMTAB - 1;
+ WORD wVVTL = wVVTE - wVVT + 1;
+ WORD NV = wVVTL / 8;
+
+ WORD wCodeLen = wSTMCUR - wSTMTAB;
+ WORD wCodeLenCur = wSTARP - wSTMCUR;
+
+ long lLenDiff = (long)dwFileLen - (long)wSTARP;
+
+ if ( g_bExtOut )
+ {
+ fprintf( g_fout, "Constants & pointers:\n" );
+ fprintf( g_fout, "Start of Name Table (VNT) : %04X\n", wVNT );
+ fprintf( g_fout, "End of Name Table (VNTE) : %04X\n", wVNTE );
+ fprintf( g_fout, "Lenght of Name Table (VNTL) : %04X\n", wVNTL );
+
+ fprintf( g_fout, "Start of Variable Table (VVT) : %04X\n", wVVT );
+ fprintf( g_fout, "End of Variable Table (VVTE) : %04X\n", wVVTE );
+ fprintf( g_fout, "Length of Variable Table (VVTL) : %04X\n", wVVTL );
+
+ fprintf( g_fout, "Number of Variables (NV) : %04X\n", NV );
+
+ fprintf( g_fout, "Start of Code (STMTAB): %04X\n", wSTMTAB );
+ fprintf( g_fout, "Length of Code : %04X\n", wCodeLen );
+ fprintf( g_fout, "Current command (STMCUR): %04X\n", wSTMCUR );
+ fprintf( g_fout, "Length of current command : %04X\n", wCodeLenCur );
+ fprintf( g_fout, "First byte after program (STARP) : %04X\n", wSTARP );
+
+ if( g_Type != BASIC_XEX )
+ {
+ fprintf( g_fout, "Length of file : %04lX\n", dwFileLen );
+ fprintf( g_fout, "File len difference : %08lX\n", (DWORD)lLenDiff );
+ }
+ fputc( '\n', g_fout );
+ }
+
+ //records must be 8 bytes long
+ if ( NV * 8 != wVVTL )
+ {
+ fprintf( stderr, "Variable Table Length Mismatch!\n" );
+ return 1;
+ }
+
+ if ( lLenDiff <0 )
+ {
+ fprintf( stderr, "File Length Incorrect!\n" );
+ return 1;
+ }
+
+ if ( !Vars_Load( &cf, wVNT, wVNTL, wVVT, NV ) )
+ return 1;
+
+ if ( g_bExtOut )
+ {
+ fprintf( g_fout, "Main code starts here:\n" );
+ }
+
+ GenCode( &cf, wSTMTAB, wSTMCUR );
+
+ if ( g_bExtOut )
+ {
+ fputc( '\n', g_fout );
+
+ fprintf( g_fout, "Immediate code starts here:\n" );
+ GenCode( &cf, wSTMCUR, wSTARP );
+ fputc( '\n', g_fout );
+ }
+ else
+ {
+ cf.Seek( wSTARP, SEEK_SET );
+ }
+
+ //if extended mode of Basic XE
+ if( g_Type == BASIC_XEX )
+ {
+ //code is stored in 4 extended memory banks
+ for( int iBank = 0; iBank < 4; iBank++ )
+ {
+ //read the end of code in bank
+ WORD wLen = cf.readLEw();
+
+ //because bank starts at 0x4000, the value must be GE
+ if( wLen < 0x4000 )
+ {
+ fprintf( stderr, "Bank end too low! %04X\n", wLen );
+ g_bHasErrors = TRUE;
+ break;
+ }
+
+ wLen -= 0x4000;
+
+ if ( g_bExtOut )
+ {
+ fprintf( g_fout, "\nBank %d code:\n", iBank );
+ }
+
+ if ( wLen )
+ {
+ //if we have anything to process, we do so
+ long lNow = cf.Tell();
+ GenCode( &cf, lNow, lNow + wLen );
+ }
+ else
+ {
+ //else we skip one byte (error in BXE?) in empty bank
+ cf.skip( 1 );
+ }
+
+ if ( g_bExtOut )
+ {
+ fputc( '\n', g_fout );
+ }
+ }
+ }
+
+ cf.Close();
+
+ if ( g_bHasErrors )
+ fprintf( stderr, "File may contain some errors!\n" );
+
+ if ( g_fout != stdout )
+ fclose( g_fout );
+
+ fprintf( stderr, "Done!\n" );
+
+ Vars_Destroy();
+
+ return 0;
+}
+
+BOOL GenCode( CFile* pcf, DWORD dwStart, DWORD dwEnd )
+{
+ pcf->Seek( dwStart, SEEK_SET );
+
+ //going thru the bank
+ while( pcf->Tell() < (long)dwEnd )
+ {
+ //generating line
+ if ( !GenLineCode( pcf, dwEnd ) )
+ {
+ g_bHasErrors = TRUE;
+ return FALSE;
+ }
+
+ //output the correct line terminator
+ if ( g_bAtariOut )
+ fputc( 0x9B, g_fout );
+ else
+ fputc( '\n', g_fout );
+ }
+
+ return TRUE;
+}
+
+BOOL GenLineCode( CFile* pcf, DWORD dwEnd )
+{
+ DWORD dwLineStart = pcf->Tell();
+
+ //some debug info
+ if ( g_bVerbose )
+ fprintf( g_fout, "[O:%08lX]", dwLineStart );
+
+ //line number
+ WORD wLineNum = pcf->readLEw();
+
+ //end of line
+ BYTE btLEnd = pcf->readb();
+ DWORD dwLineEnd = dwLineStart + btLEnd;
+
+ //don't print immediate line in BASIC XE extended (already filtered in
+ // other versions
+
+ if( g_Type == BASIC_XEX )
+ {
+ if( wLineNum == 0x8000 )
+ {
+ pcf->Seek( dwLineEnd, SEEK_SET );
+ return TRUE;
+ }
+ }
+
+ fprintf( g_fout, "%d ", wLineNum );
+
+ if ( g_bVerbose )
+ {
+ fprintf( g_fout, "[S:%04lX E:%04lX]", dwLineStart, dwLineEnd );
+ }
+
+ //if the line goes the end of buffer, croak
+ if ( ( dwLineStart > dwEnd ) || ( dwLineEnd > dwEnd ) )
+ {
+ fprintf( g_fout, "***Line size mismatch. (%04lX-%04lX)\n", dwLineEnd, dwEnd );
+ return FALSE;
+ }
+
+ //and generate the output for commands
+ while( pcf->Tell() < (long)dwLineEnd )
+ {
+ if ( !GenCmdCode( pcf, dwLineStart, dwLineEnd ) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL GenCmdCode( CFile* pcf, DWORD dwLineStart, DWORD dwLineEnd )
+{
+ //end of token
+ BYTE btTEnd = pcf->readb();
+
+ DWORD dwTokStart = pcf->Tell();
+ DWORD dwTokEnd = dwLineStart + btTEnd;
+
+ if ( g_bVerbose )
+ {
+ fprintf( g_fout, "[C:%04lX E:%04lX]", dwTokStart, dwTokEnd );
+ }
+
+ //could this ever happen?
+ if ( dwTokStart >= dwTokEnd )
+ {
+ fprintf( g_fout, "***Command size problem!\n" );
+ return FALSE;
+ }
+
+ //if token goes behind the eol
+ if ( dwTokEnd > dwLineEnd )
+ {
+ fprintf( g_fout, "***Command size mismatch. (%04lX-%04lX)\n", dwTokEnd, dwLineEnd );
+ return FALSE;
+ }
+
+ //which token
+ BYTE btTok = pcf->readb();
+
+ //token buffer
+ char szTok[ 50 ];
+
+ //if known token
+ if ( btTok < g_iCmdNum )
+ {
+ //sub table for BXL extended commands
+ if( ( btTok == BXL_EXTEND ) && ( g_Type == BASIC_XL ) )
+ {
+ BYTE btTok = pcf->readb();
+
+ switch( btTok )
+ {
+ case 0x10:
+ strcpy( szTok, "LOCAL" );
+ break;
+
+ case 0x11:
+ strcpy( szTok, "EXIT" );
+ break;
+
+ case 0x12:
+ strcpy( szTok, "PROCEDURE" );
+ break;
+
+ case 0x13:
+ strcpy( szTok, "CALL" );
+ break;
+
+ case 0x14:
+ strcpy( szTok, "SORTUP" );
+ break;
+
+ case 0x15:
+ strcpy( szTok, "SORTDOWN" );
+ break;
+
+ default:
+ sprintf( szTok, "EXTEND?%02X", btTok );
+ g_bHasErrors = TRUE;
+ break;
+
+ }
+ }
+ else
+ strcpy( szTok, g_aBasicCmds[ btTok ] );
+ }
+ else
+ {
+ sprintf( szTok, "COM%02X", btTok );
+ fprintf( stderr, "Unknown command %02X!!!\n", btTok );
+ g_bHasErrors = TRUE;
+ }
+
+ if ( *szTok )
+ {
+ //lower case for some dialects
+ if( ( g_Type == BASIC_XL ) || ( g_Type == BASIC_XE ) || ( g_Type == BASIC_XEX ) )
+ {
+ strlwr( szTok + 1 );
+ }
+
+ fprintf( g_fout, "%s ", szTok );
+ }
+
+ //special handling for REM & DATA (first two statements)
+ if ( btTok < 2 )
+ {
+ BYTE c;
+
+ int iSecure = 0x100;
+
+ for( ;; )
+ {
+ c = pcf->readb();
+
+ if ( c == 0x9B )
+ break;
+
+ if ( g_bNoInverse )
+ c &= 0x7F;
+
+ fputc( c, g_fout );
+
+ iSecure--;
+
+ if( !iSecure )
+ {
+ fprintf( stderr, "Runaway in Rem/Data code!\n" );
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+ }
+
+ //generate operands for remain of command
+ while( pcf->Tell() < (long)dwTokEnd )
+ {
+ if ( !GenOpsCode( pcf, dwTokEnd ) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL GenOpsCode( CFile* pcf, DWORD dwTokEnd )
+{
+ //get operand
+ BYTE btTok = pcf->readb();
+
+ if ( btTok == OP_EOL )
+ {
+ //new line
+ return TRUE;
+ }
+
+ if ( btTok == OP_NCONST )
+ {
+ //bcd num
+
+ fprintf( g_fout, "%.10g", ReadAtariBCD( pcf ) );
+
+ return TRUE;
+ }
+
+ if ( btTok == OP_NHCONST )
+ {
+ if ( g_Type == BASIC_TB )
+ {
+ //hex num TBASIC
+ fprintf( g_fout, "$%X", (unsigned short)ReadAtariBCD( pcf ) );
+ return TRUE;
+ }
+
+ if( ( g_Type == BASIC_XL ) || ( g_Type == BASIC_XE ) || ( g_Type == BASIC_XEX ) )
+ {
+ //hex num BASIC XL
+ WORD wNum = (unsigned short)ReadAtariBCD( pcf );
+
+ if( wNum > 0xFF )
+ fprintf( g_fout, "$%04X", wNum );
+ else
+ fprintf( g_fout, "$%02X", wNum );
+
+ return TRUE;
+ }
+ }
+
+ if ( btTok == OP_SCONST )
+ {
+ //string
+ BYTE c;
+
+ BYTE btLen = pcf->readb();
+
+ fprintf( g_fout, "\"" );
+ while( btLen-- )
+ {
+ c = pcf->readb();
+
+ if ( c == 0x9B )
+ {
+ break;
+ }
+
+ //is this for TBASIC only?
+ if ( c == '\"' )
+ {
+ fprintf( g_fout, "\"\"" );
+ }
+ else
+ fputc( c, g_fout );
+
+ }
+ fprintf( g_fout, "\"" );
+ return TRUE;
+ }
+
+ //and now for variables
+ if ( btTok & 0x80 )
+ {
+ char szPom[ 255 ];
+
+ Var_Get( szPom, btTok & 0x7F );
+
+ if( ( g_Type == BASIC_XL ) || ( g_Type == BASIC_XE ) || ( g_Type == BASIC_XEX ) )
+ {
+ strlwr( szPom + 1 );
+ }
+
+ fprintf( g_fout, szPom );
+
+ return TRUE;
+ }
+
+ //func or op
+ if ( ( btTok < g_iOpFirst ) || ( btTok - g_iOpFirst + 1 > (BYTE)g_iOpsNum ) )
+ {
+ fprintf( g_fout, "UNKOP%02X", btTok );
+ fprintf( stderr, "Unknown operand %02X!!!\n", btTok );
+ g_bHasErrors = TRUE;
+ }
+ else
+ {
+ char szPom[ 100 ];
+ strcpy( szPom, g_aBasicOps[ btTok - g_iOpFirst ] );
+
+ if( ( g_Type == BASIC_XL ) || ( g_Type == BASIC_XE ) || ( g_Type == BASIC_XEX ) )
+ {
+ strlwr( szPom + 1 );
+ }
+
+ fprintf( g_fout, "%s", szPom );
+ }
+
+ return TRUE;
+
+}
+
+//code for reading Atari BCD format
+double ReadAtariBCD( CFile* pcf )
+{
+ double dRes = 0;
+
+ //reads exponent
+ BYTE btExp = pcf->readb();
+
+ int iExp;
+
+ if ( !btExp )
+ {
+ //if Exp==0, we're skipping it! (silently!)
+ iExp = 0;
+ pcf->skip( 5 );
+ }
+ else
+ {
+ //compute exponent
+ iExp = ( btExp - 68 ) * 2;
+
+ int i = 5;
+
+ //read 5 pairs of numbers and combine 'em
+ while ( i-- )
+ {
+ BYTE btPom = pcf->readb();
+
+ BYTE btNum = ( btPom >> 4 ) * 10 + ( btPom &0xf );
+
+ dRes *= 100;
+ dRes += btNum;
+ }
+
+ }
+
+ dRes *= pow( 10, iExp );
+
+ return dRes;
+}
+
+BOOL Vars_Load( CFile* pcf, WORD wVNT, WORD wVNTL, WORD wVVT, WORD NV )
+{
+ char szVarTemp[ 256 ];
+ char szVarGen[ 256 ];
+
+ char* pStr = NULL;
+
+ BOOL bTog = FALSE;
+
+ pcf->Seek( wVNT, SEEK_SET );
+
+ for( int i = 0; i < wVNTL; i++ )
+ {
+ if ( !pStr )
+ pStr = szVarTemp;
+
+ char c = pcf->readb();
+
+ if ( c & 0x80 )
+ {
+ c &= 0x7F;
+ bTog = TRUE;
+ }
+
+ *( pStr++ ) = c;
+ *pStr = '\0';
+
+ //this is for correcting the runaway
+ if ( pStr - szVarTemp > 254 )
+ {
+ *szVarTemp = '\0';
+ bTog = TRUE;
+ }
+
+ if ( bTog )
+ {
+ int iVar = g_aVariables.GetSize();
+
+ sprintf( szVarGen, "VAR%d", iVar );
+
+ pStr = szVarTemp;
+
+ int iLength = strlen( szVarTemp );
+
+ if ( iLength )
+ {
+ for( int i = 0; i < iLength; i++ )
+ {
+ if ( !isprint( *( pStr++ ) ) )
+ {
+ strcpy( szVarTemp, szVarGen );
+ break;
+ }
+ }
+
+ if ( iVar )
+ {
+ for( int i = 0; i < iVar; i++ )
+ {
+ if( !strcmp( (char*)g_aVariables.GetAt( i ), szVarTemp ) )
+ {
+ fprintf( g_fout, "Dupped varname: %s\n", szVarTemp );
+ strcpy( szVarTemp, szVarGen );
+ break;
+ }
+ }
+ }
+
+ }
+ else
+ {
+ strcpy( szVarTemp, szVarGen );
+ }
+
+ pStr = new char [ strlen( szVarTemp ) + 1 ];
+
+ if ( pStr )
+ {
+ strcpy( pStr, szVarTemp );
+ g_aVariables.Add( pStr );
+ }
+ else
+ {
+ printf( "Not enough memory!\n" );
+ return FALSE;
+ }
+
+ bTog = FALSE;
+ pStr = NULL;
+ }
+ }
+
+ if ( g_bExtOut )
+ {
+ fprintf( g_fout, "Variable table:\n" );
+ }
+
+ pcf->Seek( wVVT, SEEK_SET );
+
+ for( int i = 0 ; i < NV; i++ )
+ {
+ BYTE btType = pcf->readb();
+ BYTE btNumber = pcf->readb();
+
+ char* szType;
+
+ char szText[ 50 ];
+
+ switch( btType )
+ {
+ case VART_SCALAR:
+ {
+ szType = "SCALAR ";
+ sprintf( szText, "%.10g", ReadAtariBCD( pcf ) );
+ break;
+ }
+
+ case VART_ARRAYU:
+ {
+ szType = "ARRAYu ";
+ char* szP = szText;
+ szP += sprintf( szP, "SPoff: %04X ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim1: %d ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim2: %d ", pcf->readLEw() );
+ break;
+ }
+
+ case VART_ARRAY:
+ {
+ szType = "ARRAY ";
+ char* szP = szText;
+ szP += sprintf( szP, "SPoff: %04X ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim1: %d ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim2: %d ", pcf->readLEw() );
+ break;
+ }
+
+ case VART_STRINGAU:
+ {
+ //BASIC_XL / XE
+ szType = "STRINGAu";
+ char* szP = szText;
+ szP += sprintf( szP, "SPoff: %04X ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim1: %d ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim2: %d ", pcf->readLEw() );
+ break;
+ }
+
+ case VART_STRINGA:
+ {
+ //BASIC_XL / XE
+ szType = "STRINGA ";
+ char* szP = szText;
+ szP += sprintf( szP, "SPoff: %04X ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim1: %d ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim2: %d ", pcf->readLEw() );
+ break;
+ }
+
+ case VART_STRINGU:
+ {
+ szType = "STRINGu ";
+ char* szP = szText;
+ szP += sprintf( szP, "SPoff: %04X ", pcf->readLEw() );
+ szP += sprintf( szP, "Len: %d ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim: %d ", pcf->readLEw() );
+ break;
+ }
+
+ case VART_STRING:
+ {
+ szType = "STRING ";
+ char* szP = szText;
+ szP += sprintf( szP, "SPoff: %04X ", pcf->readLEw() );
+ szP += sprintf( szP, "Len: %d ", pcf->readLEw() );
+ szP += sprintf( szP, "Dim: %d ", pcf->readLEw() );
+ break;
+ }
+
+ case VART_PROC:
+ {
+ //TBASIC
+ szType = "PROC ";
+ char* szP = szText;
+ for( int i = 0 ; i < 6; i++ )
+ {
+ szP += sprintf( szP, "%02X ", pcf->readb() );
+ }
+ break;
+ }
+
+ case VART_LABEL:
+ {
+ //TBASIC
+ szType = "LABEL ";
+ char* szP = szText;
+ for( int i = 0 ; i < 6; i++ )
+ {
+ szP += sprintf( szP, "%02X ", pcf->readb() );
+ }
+ break;
+ }
+
+ default:
+ {
+ szType = "UNKNOWN ";
+ char* szP = szText;
+ for( int i = 0 ; i < 6; i++ )
+ {
+ szP += sprintf( szP, "%02X ", pcf->readb() );
+ }
+ g_bHasErrors = TRUE;
+ }
+ }
+
+ char szName[ 255 ];
+ Var_Get( szName, btNumber );
+
+ char cLastChar = szName[ strlen( szName ) - 1 ];
+
+ switch( btType )
+ {
+ case VART_STRING:
+ case VART_STRINGU:
+ {
+ if ( cLastChar != '$' )
+ {
+ strcat( szName, "$" );
+ char* szStr = new char [ strlen( szName ) + 1 ];
+ strcpy( szStr, szName );
+ char* szOld = (char*) g_aVariables.GetAt( btNumber );
+
+ if ( szOld )
+ delete [] szOld;
+
+ g_aVariables.SetAt( btNumber, szStr );
+
+ }
+
+ break;
+ }
+
+ case VART_ARRAY:
+ case VART_ARRAYU:
+ {
+ if ( cLastChar == '(' )
+ {
+ szName[ strlen( szName ) - 1 ] = '\0';
+ char* szStr = new char [ strlen( szName ) + 1 ];
+ strcpy( szStr, szName );
+ char* szOld = (char*) g_aVariables.GetAt( btNumber );
+
+ if ( szOld )
+ delete [] szOld;
+
+ g_aVariables.SetAt( btNumber, szStr );
+
+ }
+
+ break;
+ }
+
+ }
+
+ if ( g_bExtOut )
+ {
+ fprintf( g_fout, "%04X %s (%02X) %02X: %s %s\n",
+ i+1,
+ szType,
+ btType,
+ btNumber,
+ szText,
+ szName );
+ }
+
+ }
+
+ if ( g_bExtOut )
+ fputc( '\n', g_fout );
+
+ return TRUE;
+}
+
+void Var_Get( char* szRet, int iNum )
+{
+ char* szVar = (char*) g_aVariables.GetAt( iNum );
+
+ if ( szVar )
+ strcpy( szRet, szVar );
+ else
+ sprintf( szRet, "VAR%d", iNum );
+}
+
+void Vars_Destroy()
+{
+ for( int i = 0; i < g_aVariables.GetSize(); i++ )
+ {
+ if ( g_aVariables.GetAt( i ) )
+ delete [] ( char* ) g_aVariables.GetAt( i );
+ }
+}
+
diff --git a/jindroush/chkbas/listbas b/jindroush/chkbas/listbas
new file mode 120000
index 0000000..8b02192
--- /dev/null
+++ b/jindroush/chkbas/listbas
@@ -0,0 +1 @@
+chkbas \ No newline at end of file
diff --git a/jindroush/chkbas/pub.def b/jindroush/chkbas/pub.def
new file mode 100644
index 0000000..790db8c
--- /dev/null
+++ b/jindroush/chkbas/pub.def
@@ -0,0 +1,31 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define PRG_NAME "chkbas"
+#define PRG_VERSION "1.10"
+#define PRG_COPYRIGHT "1999-2001"
+#define PRG_UNDERGPL "1"
+#define PRG_AUTHOR "Jindrich Kubec <kubecj@asw.cz>"
+
+#define PRG_URL "http://www.asw.cz/~kubecj"
+
+#define PRG_DESC "Atari Basic/Turbo Basic/Basic XL/Basic XE decompiler."
+#define PRG_USAGE "[options] sourcefile [lstfile]"
+
+#define PRG_ARCH "PC"
+#define PRG_TOOLS "PERL"
+
+#define PRG_SRCS "!GENERATED!"
+#define PRG_BINS "rel/chkbas.exe"
diff --git a/jindroush/chkbas/readme.txt b/jindroush/chkbas/readme.txt
new file mode 100644
index 0000000..a9a1b86
--- /dev/null
+++ b/jindroush/chkbas/readme.txt
@@ -0,0 +1,87 @@
+ChkBas v1.10 (c) 1999-2001 Jindrich Kubec <kubecj@asw.cz>
+Latest version can be found at http://www.asw.cz/~kubecj
+
+This program is provided 'as is', no warranty will be taken
+for any damage caused by it or by any use of it.
+
+The whole package is placed under the GNU Public License, for further
+information on redistribution see the included file "GPL.TXT".
+
+
+Description:
+------------
+Atari Basic/Turbo Basic/Basic XL/Basic XE decompiler.
+
+
+
+Usage:
+------
+ChkBas [options] sourcefile [lstfile]
+
+sourcefile is Atari basic file.
+
+lstfile is output text file
+
+-atari - exports source only in Atari format
+-short - exports source only in PC format
+-verbose - prints verbose information
+-tbs - decodes Turbo Basic file
+-bxl - decodes Basic XL file
+-bxe - decodes Basic XE file
+
+The export is by default more verbose and in PC format.
+
+
+History:
+--------
+Date, Author, Version
+4/5/1999, kubecj, 0.90
+First version
+
+4/20/1999, kubecj, 1.00
+First public version
+
+4/20/1999, kubecj, 1.01
+BCD error bugfix
+
+7/7/1999, kubecj, 1.02
+Atari output file bugfix (it did break lines on 0x0A char)
+
+9/5/1999, kubecj, 1.03
+'Hacked' variable table bugfix (overflow when filled with chars under 0x80)
+
+10/10/1999, kubecj, 1.04
+Changed switches processing.
+
+7/5/2001, kubecj, 1.05
+Added Basic XL.
+
+7/6/2001, kubecj, 1.06
+Added Basic XE.
+
+7/7/2001, kubecj, 1.10
+Added Basic XE extended mode. Code cleanup.
+
+
+To Do:
+------
+Add other basic dialects?
+
+
+Known Bugs:
+-----------
+None.
+
+
+Compiling Tools:
+----------------
+For scripts: Perl.
+URL: http://www.perl.com
+
+For PC executables: DJGPP.
+Sources were written/tested on GCC/Intel only. There should be only
+minor problems to port it to different architectures/environments.
+Makefile should need only minor changes.
+URL: http://www.delorie.com
+
+
diff --git a/jindroush/chkbas/strlwr.cpp b/jindroush/chkbas/strlwr.cpp
new file mode 100644
index 0000000..10c3f84
--- /dev/null
+++ b/jindroush/chkbas/strlwr.cpp
@@ -0,0 +1,11 @@
+#include <ctype.h>
+
+// 20070524 bkw: Linux and POSIX lack the DOS/Windows strlwr() function,
+// so here's an implementation.
+
+void strlwr(char *s) {
+ while(*s) {
+ *s = tolower(*s);
+ s++;
+ }
+}
diff --git a/jindroush/chkbas/switches.def b/jindroush/chkbas/switches.def
new file mode 100644
index 0000000..bb09a46
--- /dev/null
+++ b/jindroush/chkbas/switches.def
@@ -0,0 +1,34 @@
+verbose, v
+verbose info
+=g_bVerbose = TRUE;
+=
+
+atari
+Atari output file (only lst is created)
+=g_bAtariOut = TRUE;
+=
+
+short
+PC - lst only output (full output otherwise)
+=g_bExtOut = FALSE;
+=
+
+noinverse
+no inverse characters in DATA or REMs
+=g_bNoInverse = TRUE;
+=
+
+bxl
+Basic XL
+=g_Type = BASIC_XL;
+=
+
+bxe
+Basic XE
+=g_Type = BASIC_XE;
+=
+
+tbs
+Turbo Basic
+=g_Type = BASIC_TB;
+=
diff --git a/jindroush/chkexe/Makefile b/jindroush/chkexe/Makefile
new file mode 100644
index 0000000..04ef5f7
--- /dev/null
+++ b/jindroush/chkexe/Makefile
@@ -0,0 +1,55 @@
+#=====================================================================
+PRGNAME = chkexe
+
+all: $(PRGNAME)
+
+release:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall" LDFLAGS=""
+ @echo RELEASE: Compiled.
+
+rel_strip:
+ @strip $(PRGNAME).exe
+
+rel_inst:
+ @copy $(PRGNAME).exe $(ATAROOT)\\bin
+ @echo RELEASE: Installed.
+
+debug:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG" LDFLAGS="-g"
+ @echo DEBUG: Compiled.
+
+clean:
+ rm -f *.o
+ rm -f $(PRGNAME)
+ rm -f $(PRGNAME).exe
+ rm -f switches.cpp
+ rm -rf rel
+ @echo DEBUG: Cleaned.
+
+#=====================================================================
+INCLUDES = makefile \
+ switches.def \
+ pub.def
+
+
+OBJECTS = chkexe.o
+
+#=====================================================================
+CC = g++
+LD = g++
+LDLIBS = -lm -L../lib -ljindroush
+CPPFLAGS=-I../include $(COPT)
+COPT=-O2
+
+#=====================================================================
+
+$(PRGNAME) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME)
+
+chkexe.o: switches.cpp
+
+%.o : %.cpp $(INCLUDES) switches.cpp
+ $(CC) $(CPPFLAGS) -c $< -o $@
+
+switches.cpp : switches.def ../switches.pl
+ perl ../switches.pl $< $@
diff --git a/jindroush/chkexe/chkexe.cpp b/jindroush/chkexe/chkexe.cpp
new file mode 100644
index 0000000..4d651f0
--- /dev/null
+++ b/jindroush/chkexe/chkexe.cpp
@@ -0,0 +1,504 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "pub.def"
+
+#include "jintypes.h"
+
+#include "at_dis.h"
+#include "cfile.h"
+
+#define AT_HEADER 0xFFFF
+
+#define AT_RUNL 0x02E0
+#define AT_RUNH 0x02E1
+#define AT_RUNPREV ( AT_RUNL - 1 )
+
+#define AT_INITL 0x02E2
+#define AT_INITH 0x02E3
+#define AT_INITPAST ( AT_INITH + 1 )
+
+#define AT_HWSTART 0xD000
+#define AT_HWEND 0xD7FF
+
+typedef struct block
+{
+ struct block *pNext;
+ WORD wBlkStart;
+ WORD wBlkEnd;
+} FILE_BLOCK;
+
+
+BOOL BlockRead( CFile&, CFile& );
+void BlockInsert( WORD, WORD );
+void BlocksWrite( CFile& );
+void PrintOffset( CFile& );
+void BlockDisassemble( WORD, WORD );
+
+FILE_BLOCK *g_pBlocks = NULL;
+BYTE *g_pbtPool;
+BOOL g_bHasRunAddress = FALSE;
+LONG g_lFileLen;
+BOOL g_bDisassemble = FALSE;
+BOOL g_bSilent = FALSE;
+BOOL g_bIsNotOk = TRUE;
+BOOL g_bSplit = FALSE;
+BOOL g_bOut = FALSE;
+
+WORD g_iSplitNum = 0;
+
+WORD g_wGapFill = 0;
+
+char* g_szInfile = NULL;
+char* g_szOutfile = NULL;
+
+#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n"
+
+#define HEADER SHEADER \
+ PRG_DESC "\n" \
+ " Latest version can be found at " PRG_URL "\n" \
+ " Published under GPL. See GPL.TXT.\n\n"
+
+#define USAGE HEADER "Usage: " PRG_NAME " " PRG_USAGE
+
+#include "switches.cpp"
+
+int main (int argc,char *argv[])
+{
+ setbuf( stdout, NULL );
+ setbuf( stderr, NULL );
+
+ if ( !SWITCHES_Init( &argc, argv ) )
+ return 1;
+
+ if ( ( argc < 2 ) )
+ {
+ SWFN_HELP( USAGE );
+ return 1;
+ }
+
+ fprintf( stderr, SHEADER );
+
+ g_szInfile = argv[ 1 ];
+
+ if ( argc == 3 )
+ g_szOutfile = argv[ 2 ];
+
+ CFile cfIn;
+ CFile cfOut;
+
+ if ( !cfIn.Open( g_szInfile ) )
+ {
+ fprintf( stderr, "Unable to open file\n\n%s", g_szInfile );
+ return -1;
+ }
+
+ if ( AT_HEADER != cfIn.readLEw() )
+ {
+ printf( "%s: Not an Atari 8-bit binary load format file\n", g_szInfile );
+ cfIn.Close();
+ return -1;
+ }
+
+ if ( g_bSilent )
+ printf( "%s: ", g_szInfile );
+ else
+ printf( "Binary file: %s\n", g_szInfile );
+
+ if ( argc > 2 )
+ {
+ if ( !cfOut.Create( g_szOutfile ) )
+ {
+ fprintf( stderr, "Unable to open file\n\n%s", g_szOutfile );
+ return -1;
+ }
+ g_bOut = TRUE;
+ }
+
+ if ( g_bOut )
+ {
+ cfOut.writeLEw( AT_HEADER );
+ }
+
+ g_pbtPool = new BYTE [ 0x10000 ];
+ memset( g_pbtPool,0, 0x10000 );
+
+ if ( !g_pbtPool )
+ {
+ fprintf( stderr, "Unable to allocate memory for address space.\n" );
+ return -1;
+ }
+
+ g_lFileLen = cfIn.GetLength();
+
+ cfIn.Seek( 2, SEEK_SET );
+
+ while ( cfIn.Tell() < g_lFileLen )
+ {
+ if ( ( g_bIsNotOk = !BlockRead( cfIn, cfOut ) ) )
+ break;
+ }
+
+ cfIn.Close();
+
+ if ( g_bHasRunAddress )
+ BlockInsert( AT_RUNL, AT_RUNH );
+
+ if ( g_bOut )
+ {
+ BlocksWrite( cfOut ); // Write all blocks since last init
+ cfOut.Close();
+ }
+
+ delete [] g_pbtPool;
+
+ if ( !g_bIsNotOk )
+ printf( "Ok!\n" );
+
+ return 0;
+}
+
+
+BOOL BlockRead( CFile& cfIn, CFile& cfOut )
+{
+ WORD wBlkStart;
+ WORD wBlkEnd;
+ WORD wBlkLen;
+
+ do
+ {
+ PrintOffset( cfIn );
+
+ if ( cfIn.Tell() >= g_lFileLen )
+ {
+ printf( "Error: Unexpected end of file\n" );
+ return FALSE;
+ }
+
+ wBlkStart = cfIn.readLEw();
+
+ if ( wBlkStart == AT_HEADER )
+ {
+ if ( !g_bSilent )
+ printf( " : Unexpected second 0xffff format header\n" );
+ }
+
+ } while ( wBlkStart == AT_HEADER );
+
+ if ( cfIn.Tell() >= g_lFileLen )
+ {
+ printf( "Error: Unexpected end of file in load range start address\n" );
+ return FALSE;
+ }
+
+ wBlkEnd = cfIn.readLEw();
+
+ wBlkLen = wBlkEnd - wBlkStart + 1;
+
+ if ( cfIn.Tell() >= g_lFileLen )
+ {
+ printf( "Error: Unexpected end of file in load range end address\n" );
+ return FALSE;
+ }
+
+ if ( ( wBlkStart == wBlkEnd ) && ( ( wBlkStart >> 8 ) == ( wBlkStart & 0xFF ) ) )
+ {
+ WORD wLen = g_lFileLen - cfIn.Tell() + 4;
+
+ //garbage was limited to be max $500 long, run address must exist!
+ if ( ( wLen < 0x500 ) && ( wBlkStart ) )
+ {
+ printf( "Error: Apparent garbage fill at end of file (%04X bytes)\n", wLen );
+ return FALSE;
+ }
+
+ }
+
+ if ( wBlkEnd < wBlkStart )
+ {
+ if ( !g_bSilent )
+ printf( "Block: %04X-%04X (%04X)\n", wBlkStart, wBlkEnd, wBlkLen );
+
+ printf( "Error: %ld bytes in file after invalid load range\n", g_lFileLen - cfIn.Tell() );
+ return FALSE;
+ }
+
+ if ( g_lFileLen < cfIn.Tell() + wBlkLen )
+ {
+ if ( !g_bSilent )
+ printf( "Block: %04X-%04X (%04X)\n", wBlkStart, wBlkEnd, wBlkLen );
+
+ printf( "Error: Truncated file: missing data in load block (%04lX bytes missing)\n", cfIn.Tell() + wBlkLen - g_lFileLen );
+ return FALSE;
+ }
+
+ // Read in the data for this block
+ cfIn.Read( &g_pbtPool[wBlkStart], wBlkLen );
+
+ // Check for run address
+ if ( wBlkStart <= AT_RUNH && wBlkStart + wBlkLen >= AT_RUNL )
+ {
+ if (wBlkStart==AT_RUNH || wBlkStart+wBlkLen==AT_RUNL)
+ {
+ if ( !g_bSilent )
+ printf( " : Partial run address\n" );
+ }
+ if ( g_bHasRunAddress )
+ if ( !g_bSilent )
+ printf( " : Unexpected second run address\n" );
+
+ g_bHasRunAddress = TRUE;
+
+ if ( !g_bSilent )
+ printf( "Run : %04X\n", g_pbtPool[ AT_RUNL ] + 256 * g_pbtPool[ AT_RUNH ] );
+
+ if ( ( wBlkStart >= AT_RUNL ) && ( wBlkEnd <= AT_RUNH ) )
+ return TRUE;
+
+ // Other data in this block
+ if ( wBlkStart == AT_RUNL || wBlkStart == AT_RUNH )
+ {
+ // Run and init in the same block--split
+ wBlkStart = AT_INITL;
+ wBlkLen = wBlkEnd - wBlkStart + 1;
+ }
+ else if ( wBlkEnd == AT_RUNL || wBlkEnd==AT_RUNH)
+ {
+ // other stuff before the run address--split
+ wBlkEnd = AT_RUNPREV;
+ wBlkLen = wBlkEnd - wBlkStart + 1;
+ }
+ else
+ {
+ // Run address in the middle of the block
+ if ( !g_bSilent )
+ printf( "Block: %04X-%04X (%04X)\n", wBlkStart, AT_RUNPREV, AT_RUNPREV - wBlkStart + 1 );
+
+ BlockInsert( wBlkStart, AT_RUNPREV );
+ wBlkStart = AT_INITL;
+ wBlkLen = wBlkEnd - wBlkStart + 1;
+ }
+ }
+
+ // Check for init address
+ // We know there's nothing before the address in the block,
+ // as we would have split it off above as a run address.
+ if ( wBlkStart <= AT_INITH && wBlkStart + wBlkLen >= AT_INITL )
+ {
+ if ( wBlkStart == AT_INITH || wBlkStart + wBlkLen == AT_INITL )
+ {
+ if ( !g_bSilent )
+ printf( " : Partial init address\n" );
+ }
+ if ( !g_bSilent )
+ printf( "Init : %04X\n", g_pbtPool[ AT_INITL ] + 256 * g_pbtPool[ AT_INITH ] );
+
+ // Other data in this block?
+ if ( wBlkEnd > AT_INITH )
+ {
+ // More stuff past init--split
+ if ( !g_bSilent )
+ printf( "Block: %04X-%04X (%04X)\n", AT_INITPAST, wBlkEnd, wBlkLen );
+
+ BlockInsert( AT_INITPAST, wBlkEnd );
+ wBlkEnd = AT_INITH;
+ wBlkLen = wBlkEnd - wBlkStart + 1;
+ }
+
+ BlockInsert( wBlkStart, wBlkEnd );
+
+ if ( g_bDisassemble )
+ BlockDisassemble( wBlkStart, wBlkEnd );
+
+ // Write everything out to avoid cross-init merges
+ BlocksWrite( cfOut );
+ return TRUE;
+ }
+
+ // Print data block load message
+ if ( !g_bSilent )
+ printf( "Block: %04X-%04X (%04X)\n", wBlkStart, wBlkEnd, wBlkLen );
+
+ if ( ( !wBlkStart ) && ( !wBlkEnd ) )
+ return TRUE;
+
+ BlockInsert( wBlkStart, wBlkEnd );
+
+ if ( g_bDisassemble )
+ BlockDisassemble( wBlkStart, wBlkEnd );
+
+ return TRUE;
+}
+
+
+void BlockInsert(WORD wBlkStart,WORD wBlkEnd)
+{
+ if ( g_bSplit )
+ {
+ char szPom[ 255 ];
+ sprintf( szPom, "blk%04X.blk", g_iSplitNum );
+
+ CFile cf;
+ if ( cf.Create( szPom ) )
+ {
+ cf.writeLEw( AT_HEADER );
+ cf.writeLEw( wBlkStart );
+ cf.writeLEw( wBlkEnd );
+ cf.Write( g_pbtPool + wBlkStart, wBlkEnd - wBlkStart + 1 );
+ cf.Close();
+ }
+
+ g_iSplitNum++;
+ }
+
+ FILE_BLOCK *b,*bp;
+
+ bp = NULL; // previous block
+ b = g_pBlocks;
+
+ while( b )
+ {
+ //this fills the ultra short blks
+ if ( ( ( b->wBlkEnd + 1 ) >= 0x400 ) && ( b->wBlkStart < 0xC000 ) )
+ {
+ if ( ( b->wBlkEnd + 1 ) < wBlkStart )
+ {
+ if ( ( wBlkStart - ( b->wBlkEnd + 1 ) ) < g_wGapFill )
+ {
+ if ( !g_bSilent )
+ printf( "\t\tBlock merges with a previous block (gap fill)\n" );
+
+ b->wBlkEnd = wBlkEnd;
+ return;
+ }
+ }
+
+ }
+
+ // Check for merge
+ if ( b->wBlkEnd + 1 == wBlkStart )
+ {
+ if ( !g_bSilent )
+ printf( "\t\tBlock merges with a previous block\n" );
+
+ b->wBlkEnd = wBlkEnd;
+ return;
+ }
+ if ( b->wBlkStart - 1 == wBlkEnd )
+ {
+ if ( !g_bSilent )
+ printf( "\t\tBlock merges with a previous block (unexpected ordering)\n" );
+
+ b->wBlkStart = wBlkStart;
+ return;
+ }
+ // Check for overlap
+ if ( b->wBlkStart <= wBlkStart && wBlkEnd <= b->wBlkEnd )
+ {
+ if ( !g_bSilent )
+ printf( "\t\tWarning: Completely overlaps a previous block--merged\n" );
+
+ return;
+ }
+ if (b->wBlkStart <= wBlkEnd && b->wBlkStart >= wBlkStart)
+ {
+ b->wBlkStart = wBlkStart;
+ if (b->wBlkEnd<wBlkEnd) b->wBlkEnd = wBlkEnd;
+ if ( !g_bSilent )
+ printf( "\t\tWarning: Partially overlaps a previous block--merged\n" );
+
+ return;
+ }
+ if ( b->wBlkEnd <= wBlkEnd && b->wBlkEnd >= wBlkStart )
+ {
+ b->wBlkEnd = wBlkEnd;
+
+ if ( b->wBlkStart > wBlkStart )
+ b->wBlkStart = wBlkStart;
+
+ if ( !g_bSilent )
+ printf( "\t\tWarning: Partially overlaps a previous block--merged\n" );
+
+ return;
+ }
+ bp = b;
+ b = b->pNext;
+ }
+
+ // Add this block to the end of the list
+ b = new FILE_BLOCK;
+
+ if( !b )
+ {
+ fprintf(stderr,"Unable to alloc memory--aborted\n" );
+ }
+
+ b->wBlkStart = wBlkStart;
+ b->wBlkEnd = wBlkEnd;
+ b->pNext = NULL;
+
+ if (bp)
+ bp->pNext = b;
+ else
+ g_pBlocks = b;
+}
+
+
+void BlocksWrite( CFile& cf )
+{
+ FILE_BLOCK* b;
+ FILE_BLOCK* bp;
+
+ b = g_pBlocks;
+ while (b)
+ {
+ if ( g_bOut)
+ {
+ cf.writeLEw( b->wBlkStart );
+ cf.writeLEw( b->wBlkEnd );
+
+ cf.Write( &g_pbtPool[ b->wBlkStart ], b->wBlkEnd - b->wBlkStart + 1 );
+ }
+ bp = b; // To allow free call after last use
+ b = b->pNext;
+ delete bp;
+ }
+ g_pBlocks = NULL;
+}
+
+
+void BlockDisassemble(WORD wBlkStart,WORD wBlkEnd)
+{
+ //don't disassemble run & init block
+ if ( ( wBlkStart >= AT_RUNL ) && ( wBlkEnd <= AT_INITH ) )
+ goto BDEND;
+
+ //don't disassemble hw addresses
+ if ( ( wBlkStart >= AT_HWSTART ) && ( wBlkEnd <= AT_HWEND ) )
+ goto BDEND;
+
+ OutputBlockDiss( g_pbtPool + wBlkStart, wBlkStart, wBlkEnd );
+
+BDEND:
+ printf( "\n" );
+ return;
+}
+
+void PrintOffset( CFile& cf )
+{
+ if ( !g_bSilent )
+ printf( "[%04lX] ", cf.Tell() );
+}
+
diff --git a/jindroush/chkexe/pub.def b/jindroush/chkexe/pub.def
new file mode 100644
index 0000000..eb3d2fb
--- /dev/null
+++ b/jindroush/chkexe/pub.def
@@ -0,0 +1,31 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define PRG_NAME "chkexe"
+#define PRG_VERSION "2.62"
+#define PRG_COPYRIGHT "1998-1999"
+#define PRG_UNDERGPL "1"
+#define PRG_AUTHOR "Jindrich Kubec <kubecj@asw.cz>"
+
+#define PRG_URL "http://www.asw.cz/~kubecj"
+
+#define PRG_DESC "Atari executable checker/decompiler."
+#define PRG_USAGE "[options] sourcefile [destfile]"
+
+#define PRG_ARCH "PC"
+#define PRG_TOOLS "PERL"
+
+#define PRG_SRCS "!GENERATED!"
+#define PRG_BINS "rel/chkexe.exe"
diff --git a/jindroush/chkexe/readme.txt b/jindroush/chkexe/readme.txt
new file mode 100644
index 0000000..7d92c8f
--- /dev/null
+++ b/jindroush/chkexe/readme.txt
@@ -0,0 +1,100 @@
+ChkExe v2.62 (c) 1998-1999 Jindrich Kubec <kubecj@asw.cz>
+Latest version can be found at http://www.asw.cz/~kubecj
+
+This program is provided 'as is', no warranty will be taken
+for any damage caused by it or by any use of it.
+
+The whole package is placed under the GNU Public License, for further
+information on redistribution see the included file "GPL.TXT".
+
+
+Description:
+------------
+Atari executable checker/decompiler.
+Based on Preston Crow's binload utility. Better command line switches,
+better disassembler and gap filing.
+
+Disassembler is only very simple - single pass, no data recognition.
+
+
+Usage:
+------
+ChkExe [options] sourcefile [destfile]
+
+sourcefile is Atari DOS exe file.
+
+destfile is optional output file with changed blocks.
+
+gaps is for changing the size of maximum 'gap' fill. It's the destination
+ of two blocks under which blocks will be 'glued' together by zeroes.
+
+silent outputs only OK/errors
+
+split creates also blkXXXX.blk files with only one block inside
+
+d creates also disassembly of each block
+
+
+History:
+--------
+Date, Author, Version
+6/2/1995, crow, 1.00
+Initial public release
+
+6/4/1995, crow, 2.00
+Create fixed version of the file
+
+6/7/1995, crow, 2.10
+Use separate functions
+Merge overlapping and adjacent blocks
+
+6/9/1995, cmwagner, 2.20
+Ported to MS-DOS machines, should compile and work under
+MS-DOS,compile in COMPACT model.
+
+11/11/1995, cmwagner, 2.30
+Added d switch, which allow disassembly of blocks to stdout
+disassemble_block() function added, outins() function added, instable[] added
+
+11/16/1995, cmwagner, 2.40
+Fixed bogus operands on output when operands extend beyond
+end of block, just puts out a bogus instruction symbol now (???).
+
+9/24/1998, kubecj, 2.50
+Modularized, added symbol resolving in disassembler
+Added -silent switch for batch processing
+Added gap filling
+Rewritten in CPP under DJGPP only, no portability
+
+7/7/1999, kubecj, 2.60
+Added file blocks splitting
+
+8/20/1999, kubecj, 2.61
+Fixed signedness bug concerning branches :(
+
+10/10/1999, kubecj, 2.62
+Changed switches processing.
+
+
+To Do:
+------
+Maybe better disassembler.
+
+
+Known Bugs:
+-----------
+None.
+
+
+Compiling Tools:
+----------------
+For scripts: Perl.
+URL: http://www.perl.com
+
+For PC executables: DJGPP.
+Sources were written/tested on GCC/Intel only. There should be only
+slight problems to port it to different architectures/environments.
+Makefile should need only slight changes.
+URL: http://www.delorie.com
+
+
diff --git a/jindroush/chkexe/switches.def b/jindroush/chkexe/switches.def
new file mode 100644
index 0000000..4c2bf20
--- /dev/null
+++ b/jindroush/chkexe/switches.def
@@ -0,0 +1,21 @@
+d, dis
+disassembles
+=g_bDisassemble = TRUE;
+=
+
+silent, s
+silent operation
+=g_bSilent = TRUE;
+=
+
+gaps
+length of gap fill (hexadecimal)
+=int iTemp;
+hexnum=bRet = SWFN_NUMH( &iTemp );
+=g_wGapFill = iTemp;
+=
+
+split
+split into blocks
+=g_bSplit = TRUE;
+=
diff --git a/jindroush/chkrom/Makefile b/jindroush/chkrom/Makefile
new file mode 100644
index 0000000..19bf6f4
--- /dev/null
+++ b/jindroush/chkrom/Makefile
@@ -0,0 +1,56 @@
+#=====================================================================
+PRGNAME = chkrom
+
+all: $(PRGNAME)
+
+release:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -O2 -Wall" LDFLAGS=""
+ @echo RELEASE: Compiled.
+
+rel_strip:
+ @strip $(PRGNAME).exe
+
+rel_inst:
+ @copy $(PRGNAME).exe $(ATAROOT)\\bin
+ @echo RELEASE: Installed.
+
+debug:
+ @$(MAKE) $(PRGNAME) CFLAGS="-c -g -Wall -D_DEBUG" LDFLAGS="-g"
+ @echo DEBUG: Compiled.
+
+clean:
+ rm -f *.o
+ rm -f $(PRGNAME)
+ rm -f $(PRGNAME).exe
+ rm -f switches.cpp
+ rm -rf rel
+ @echo DEBUG: Cleaned.
+
+#=====================================================================
+INCLUDES = makefile \
+ pub.def \
+ switches.def
+
+
+OBJECTS = chkrom.o
+
+#=====================================================================
+CC = g++
+LD = g++
+LDLIBS = -lm -L../lib -ljindroush
+CPPFLAGS=-I../include $(COPT)
+COPT=-O2
+
+#=====================================================================
+
+$(PRGNAME) : $(OBJECTS)
+ $(LD) $(LDFLAGS) $(OBJECTS) $(LDLIBS) -o $(PRGNAME)
+
+chkrom.o: chkrom.cpp switches.cpp
+
+%.o : %.cpp $(INCLUDES)
+ $(CC) $(CPPFLAGS) -c $< -o $@
+
+switches.cpp : switches.def ../switches.pl
+ perl ../switches.pl $< $@
+
diff --git a/jindroush/chkrom/chkrom.cpp b/jindroush/chkrom/chkrom.cpp
new file mode 100644
index 0000000..32c8979
--- /dev/null
+++ b/jindroush/chkrom/chkrom.cpp
@@ -0,0 +1,119 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+//#include <unistd.h>
+#include "pub.def"
+#include "jintypes.h"
+#include "at_dis.h"
+
+BOOL g_bDisassemble = FALSE;
+
+int hIn = -1;
+
+char* g_szInfile = NULL;
+
+#define SHEADER PRG_NAME " v" PRG_VERSION " (c) " PRG_COPYRIGHT " " PRG_AUTHOR "\n"
+
+#define HEADER SHEADER \
+ PRG_DESC "\n" \
+ " Latest version can be found at " PRG_URL "\n" \
+ " Published under GPL. See GPL.TXT.\n\n"
+
+#define USAGE HEADER "Usage: " PRG_NAME " " PRG_USAGE
+
+#include "switches.cpp"
+
+int main (int argc,char *argv[])
+{
+ setbuf( stdout, NULL );
+ setbuf( stderr, NULL );
+
+ if ( !SWITCHES_Init( &argc, argv ) )
+ return 1;
+
+ if ( argc < 2 )
+ {
+ SWFN_HELP( USAGE );
+ return 1;
+ }
+
+ fprintf( stderr, SHEADER );
+
+ g_szInfile = argv[ 1 ];
+
+ hIn = open( g_szInfile, O_RDONLY | O_BINARY );
+
+ if ( hIn == -1 )
+ {
+ fprintf(stderr, "Unable to open file\n\n%s", g_szInfile );
+ exit( 1 );
+ }
+
+ LONG lFileLen = lseek( hIn, 0, SEEK_END );
+
+ lseek( hIn, 0, SEEK_SET );
+
+ if ( ( lFileLen != 0x2000 ) && ( lFileLen != 0x4000 ) )
+ {
+ printf( "%s: Unknown ROM size\n", g_szInfile );
+ close( hIn );
+ exit( 1 );
+ }
+
+ printf( "ROM file: %s\n", g_szInfile );
+
+ BYTE pbtMem[ 0x4000 ];
+
+ read( hIn, pbtMem, lFileLen );
+
+ WORD wInit = pbtMem[ lFileLen - 2 ] + ( pbtMem[ lFileLen - 1 ] << 8 );
+ WORD wFlags = pbtMem[ lFileLen - 4 ] + ( pbtMem[ lFileLen - 3 ] << 8 );
+ WORD wRun = pbtMem[ lFileLen - 6 ] + ( pbtMem[ lFileLen - 5 ] << 8 );
+
+ WORD wStart = ( lFileLen == 0x2000 ) ? 0xA000 : 0x8000;
+
+ printf( "Init Addr :%04X\n", wInit );
+ printf( "Run Addr :%04X\n", wRun );
+ printf( "Flags :%04X ( ", wFlags );
+
+ if ( wFlags & 0x0400 )
+ {
+ printf( "INIT&RUN " );
+ }
+ else
+ printf( "INIT " );
+
+ if ( wFlags & 0x0100 )
+ printf( "BOOT " );
+
+ if ( wFlags & 0x8000 )
+ printf( "TESTMOD " );
+
+ printf( ")\n" );
+
+ if ( g_bDisassemble )
+ {
+ printf( "\n" );
+ OutputBlockDiss( pbtMem, wStart, wStart + lFileLen - 1 - 6 );
+ printf( "\n" );
+ }
+
+ printf( "Ok!\n" );
+
+ close( hIn );
+
+ return 0;
+}
+
diff --git a/jindroush/chkrom/pub.def b/jindroush/chkrom/pub.def
new file mode 100644
index 0000000..f888d12
--- /dev/null
+++ b/jindroush/chkrom/pub.def
@@ -0,0 +1,31 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#define PRG_NAME "chkrom"
+#define PRG_VERSION "1.00"
+#define PRG_COPYRIGHT "1998-1999"
+#define PRG_UNDERGPL "1"
+#define PRG_AUTHOR "Jindrich Kubec <kubecj@asw.cz>"
+
+#define PRG_URL "http://www.asw.cz/~kubecj"
+
+#define PRG_DESC "Atari cartridge ROM 8/16 decompiler."
+#define PRG_USAGE "[options] sourcefile"
+
+#define PRG_ARCH "PC"
+#define PRG_TOOLS "PERL"
+
+#define PRG_SRCS "!GENERATED!"
+#define PRG_BINS "rel/chkrom.exe"
diff --git a/jindroush/chkrom/readme.txt b/jindroush/chkrom/readme.txt
new file mode 100644
index 0000000..7f3c12b
--- /dev/null
+++ b/jindroush/chkrom/readme.txt
@@ -0,0 +1,56 @@
+ChkRom v1.00 (c) 1998-1999 Jindrich Kubec <kubecj@asw.cz>
+Latest version can be found at http://www.asw.cz/~kubecj
+
+This program is provided 'as is', no warranty will be taken
+for any damage caused by it or by any use of it.
+
+The whole package is placed under the GNU Public License, for further
+information on redistribution see the included file "GPL.TXT".
+
+
+Description:
+------------
+Atari cartridge ROM 8/16 decompiler.
+
+
+
+Usage:
+------
+ChkRom [options] sourcefile
+
+sourcefile is Atari ROM image.
+
+
+History:
+--------
+Date, Author, Version
+4/5/1999, kubecj, 0.95
+First version
+
+10/10/1999, kubecj, 1.00
+Changed switches processing.
+First release.
+
+
+To Do:
+------
+Maybe better disassembler.
+
+
+Known Bugs:
+-----------
+None.
+
+
+Compiling Tools:
+----------------
+For scripts: Perl.
+URL: http://www.perl.com
+
+For PC executables: DJGPP.
+Sources were written/tested on GCC/Intel only. There should be only
+slight problems to port it to different architectures/environments.
+Makefile should need only slight changes.
+URL: http://www.delorie.com
+
+
diff --git a/jindroush/chkrom/switches.def b/jindroush/chkrom/switches.def
new file mode 100644
index 0000000..827d5b4
--- /dev/null
+++ b/jindroush/chkrom/switches.def
@@ -0,0 +1,5 @@
+d, dis, disassemble
+disassemble
+=g_bDisassemble = TRUE;
+=
+
diff --git a/jindroush/gpl.txt b/jindroush/gpl.txt
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/jindroush/gpl.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/jindroush/include/adsk.h b/jindroush/include/adsk.h
new file mode 100644
index 0000000..6786d8a
--- /dev/null
+++ b/jindroush/include/adsk.h
@@ -0,0 +1,75 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __ADSK_H__
+#define __ADSK_H__
+
+#include "jintypes.h"
+#include "cobj.h"
+#include "cdsk.h"
+
+#define MAX_ATARI_SECTOR_LEN 0x100
+
+typedef enum
+{
+ DISK_AUTO,
+ DISK_ATR,
+ DISK_ATRb,
+ DISK_XFD,
+ DISK_XFDb,
+ DISK_SCP,
+ DISK_DCM,
+ DISK_DI
+} DISK_TYPE;
+
+typedef enum
+{
+ DI_RET_OK,
+ DI_RET_CANT_CONTINUE,
+ DI_RET_CONTINUE
+} DISKINIT_RETCODE;
+
+class ADisk : public CDisk
+{
+public:
+ ADisk();
+ ~ADisk();
+
+ BOOL ReadSectors( void*, int, int );
+ BOOL WriteSectors( int, void*, int );
+
+ int GetBootSectorCount();
+ int GetBootSectorSize();
+ BOOL GetBootSector( BYTE* );
+};
+
+void GuessClassicSizes( int, int, DISK_GEOMETRY* );
+void ForceClassicSize( int, int, DISK_GEOMETRY* );
+void ForceClassicSize( DISK_GEOMETRY* );
+
+char* GetDiskTypeName( DISK_TYPE disktype );
+char* GetDiskTypeExt( DISK_TYPE disktype );
+
+DISKINIT_RETCODE InitializeDisk( ADisk**, DISK_TYPE, char*, BOOL bVerbose, BOOL, BOOL );
+
+
+#include "adsk_atr.h"
+#include "adsk_xfd.h"
+#include "adsk_scp.h"
+#include "adsk_dcm.h"
+#include "adsk_di.h"
+
+#endif //_ADSK_H__
+
diff --git a/jindroush/include/adsk_atr.h b/jindroush/include/adsk_atr.h
new file mode 100644
index 0000000..189b030
--- /dev/null
+++ b/jindroush/include/adsk_atr.h
@@ -0,0 +1,38 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CATR_H__
+#define __CATR_H__
+
+#include "jintypes.h"
+#include "errbase.h"
+#include "adsk.h"
+
+#define CATR_FORMAT_VIOLATED ( CATR_BASE + 0 )
+
+class CAtr : public ADisk
+{
+public:
+ CAtr();
+ ~CAtr();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+
+ BOOL Save( char*, BOOL );
+private:
+};
+
+#endif
+
diff --git a/jindroush/include/adsk_dcm.h b/jindroush/include/adsk_dcm.h
new file mode 100644
index 0000000..4e5ca3e
--- /dev/null
+++ b/jindroush/include/adsk_dcm.h
@@ -0,0 +1,72 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDCM_H__
+#define __CDCM_H__
+
+#include "errbase.h"
+#include "jintypes.h"
+#include "adsk.h"
+#include "cfile.h"
+#include "cprefile.h"
+
+#define CDCM_FORMAT_VIOLATED ( CDCM_BASE + 0 )
+
+class CDcm : public ADisk
+{
+public:
+ CDcm();
+ ~CDcm();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+
+ BOOL Save( char*, BOOL );
+
+private:
+
+ BOOL DecodeRec41( CGenFile& );
+ BOOL DecodeRec42( CGenFile& );
+ BOOL DecodeRec43( CGenFile& );
+ BOOL DecodeRec44( CGenFile& );
+ BOOL DecodeRec46( CGenFile& );
+ BOOL DecodeRec47( CGenFile& );
+ BOOL DecodeRecFA( CGenFile& );
+ WORD ReadOffset( CGenFile& );
+
+ void EncodeRec41( BYTE*, int*, BYTE*, BYTE*, int );
+ void EncodeRec43( BYTE*, int*, BYTE*, int );
+ void EncodeRec44( BYTE*, int*, BYTE*, BYTE*, int );
+
+ void EncodeRec45();
+ void EncodeRec46();
+ void EncodeRec( BOOL );
+ void EncodeRecFA( BOOL, int, int, int );
+
+ BOOL m_bLastPass;
+ BYTE m_abtCurrBuff[ 0x100 ];
+ BYTE m_abtPrevBuff[ 0x100 ];
+ int m_iSectorSize;
+ WORD m_wCurrentSector;
+ long m_lFileLength;
+ BOOL m_bAlreadyFormatted;
+
+
+ BYTE* m_pbtCurr;
+ BYTE* m_pbtPass;
+ BYTE* m_pbtLastRec;
+};
+
+#endif
+
diff --git a/jindroush/include/adsk_di.h b/jindroush/include/adsk_di.h
new file mode 100644
index 0000000..fb1a527
--- /dev/null
+++ b/jindroush/include/adsk_di.h
@@ -0,0 +1,38 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDI_H__
+#define __CDI_H__
+
+#include "jintypes.h"
+#include "errbase.h"
+#include "adsk.h"
+
+#define CDI_FORMAT_VIOLATED ( CDI_BASE + 0 )
+
+class CDi : public ADisk
+{
+public:
+ CDi();
+ ~CDi();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+
+ BOOL Save( char*, BOOL );
+private:
+};
+
+#endif
+
diff --git a/jindroush/include/adsk_scp.h b/jindroush/include/adsk_scp.h
new file mode 100644
index 0000000..933fc68
--- /dev/null
+++ b/jindroush/include/adsk_scp.h
@@ -0,0 +1,37 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CSCP_H__
+#define __CSCP_H__
+
+#include "jintypes.h"
+#include "adsk.h"
+
+#define CSCP_FORMAT_VIOLATED ( CSCP_BASE + 0 )
+
+class CScp : public ADisk
+{
+public:
+ CScp();
+ ~CScp();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+ BOOL Save( char*, BOOL );
+
+private:
+};
+
+#endif
+
diff --git a/jindroush/include/adsk_xfd.h b/jindroush/include/adsk_xfd.h
new file mode 100644
index 0000000..1870b70
--- /dev/null
+++ b/jindroush/include/adsk_xfd.h
@@ -0,0 +1,38 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CXFD_H__
+#define __CXFD_H__
+
+#include "jintypes.h"
+#include "adsk.h"
+#include "errbase.h"
+
+#define CXFD_FORMAT_VIOLATED ( CXFD_BASE + 0 )
+
+class CXfd : public ADisk
+{
+public:
+ CXfd();
+ ~CXfd();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+ BOOL Save( char*, BOOL );
+
+private:
+};
+
+#endif
+
diff --git a/jindroush/include/at_dis.h b/jindroush/include/at_dis.h
new file mode 100644
index 0000000..c489e60
--- /dev/null
+++ b/jindroush/include/at_dis.h
@@ -0,0 +1,25 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __AT_DIS_H__
+#define __AT_DIS_H__
+
+#include "jintypes.h"
+
+void OutputBlockDiss( BYTE*, WORD, WORD );
+char* SymbolFind( WORD, BOOL );
+
+#endif
+
diff --git a/jindroush/include/autil.h b/jindroush/include/autil.h
new file mode 100644
index 0000000..66c569c
--- /dev/null
+++ b/jindroush/include/autil.h
@@ -0,0 +1,35 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __AUTIL_H__
+#define __AUTIL_H__
+
+#include "jintypes.h"
+
+void ADos2MsDos( char*, char* );
+void GuessBestFnameFromPC( char* szDest, char* szSrc, char* szExt, char* szAdd = NULL );
+void GuessBestFnameFromAtari( char* szDest, char* szSrc, char* szExt );
+
+BOOL IsBlockEmpty( BYTE*, int );
+
+#define MGET_B( p ) ( *(p++ ) );
+#define MGET_LEW( p ) ( *p + ((*(p+1) ) <<8) ),p+=2;
+#define MGET_BEW( p ) ( *(p+1) + ((*(p) ) <<8) ),p+=2;
+
+#define MREAD_B( p ) ( *p );
+#define MREAD_LEW( p ) ( *p + ((*(p+1) ) <<8) );
+#define MREAD_BEW( p ) ( *(p+1) + ((*(p) ) <<8) );
+
+#endif
diff --git a/jindroush/include/cdisk.h b/jindroush/include/cdisk.h
new file mode 100644
index 0000000..4542ccd
--- /dev/null
+++ b/jindroush/include/cdisk.h
@@ -0,0 +1,95 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDISK_H__
+#define __CDISK_H__
+
+#include "jintypes.h"
+#include "cobj.h"
+
+#define CDISK_ERROR_CANT_OPEN ( CDISK_BASE + 0 )
+
+typedef enum
+{
+ DISK_AUTO,
+ DISK_ATR,
+ DISK_ATRb,
+ DISK_XFD,
+ DISK_XFDb,
+ DISK_SCP,
+ DISK_DCM
+} DISK_TYPE;
+
+typedef enum
+{
+ DI_RET_OK,
+ DI_RET_CANT_CONTINUE,
+ DI_RET_CONTINUE
+} DISKINIT_RETCODE;
+
+typedef struct
+{
+ int iSides;
+ int iTracks;
+ int iSectorsPerTrack;
+ int iBytesPerSector;
+ int iSectors;
+} DISK_GEOMETRY;
+
+class CDisk : public CObj
+{
+public:
+ CDisk();
+ virtual ~CDisk();
+
+ virtual BOOL Load( char*, BOOL = FALSE, BOOL = FALSE ) = 0;
+
+ #ifdef __CDISK_WRITE__
+ virtual BOOL Save( char*, BOOL ) = 0;
+ #endif
+
+ BOOL Format( DISK_GEOMETRY* );
+
+ DISK_GEOMETRY* GetGeometry() { return &m_geometry; };
+ int GetSectorSize() { return m_geometry.iBytesPerSector; };
+ int GetSectorCount() { return m_geometry.iSectors; };
+
+ BOOL ReadSector( void*, int );
+ BOOL WriteSector( int, void* );
+
+ BOOL ReadSectors( void*, int, int );
+ BOOL WriteSectors( int, void*, int );
+
+ BOOL Duplicate( CDisk* );
+
+ char* GetImageName() { return m_szFname; };
+
+protected:
+ DISK_GEOMETRY m_geometry;
+ BOOL m_bOpened;
+ BYTE *m_pbtMemory;
+ int m_iAllocated;
+
+ char m_szFname[ 255 ];
+};
+
+void GuessClassicSizes( int, int, DISK_GEOMETRY* );
+
+char* GetDiskTypeName( DISK_TYPE disktype );
+char* GetDiskTypeExt( DISK_TYPE disktype );
+
+DISKINIT_RETCODE InitializeDisk( CDisk**, DISK_TYPE, char*, BOOL bVerbose, BOOL, BOOL );
+
+#endif
diff --git a/jindroush/include/cdsk.h b/jindroush/include/cdsk.h
new file mode 100644
index 0000000..50461e2
--- /dev/null
+++ b/jindroush/include/cdsk.h
@@ -0,0 +1,72 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDISK_H__
+#define __CDISK_H__
+
+#include "jintypes.h"
+#include "cobj.h"
+
+#define CDISK_ERROR_CANT_OPEN ( CDISK_BASE + 0 )
+
+typedef struct
+{
+ int iSides;
+ int iTracks;
+ int iSectorsPerTrack;
+ int iBytesPerSector;
+ int iSectors;
+} DISK_GEOMETRY;
+
+class CDisk : public CObj
+{
+public:
+ CDisk();
+ virtual ~CDisk();
+
+ #ifndef __CDISK_NOLOAD__
+ virtual BOOL Load( char*, BOOL = FALSE, BOOL = FALSE ) = 0;
+ #endif
+
+ #ifdef __CDISK_SAVE__
+ virtual BOOL Save( char*, BOOL ) = 0;
+ #endif
+
+ BOOL Format( DISK_GEOMETRY* );
+
+ DISK_GEOMETRY* GetGeometry() { return &m_geometry; };
+ int GetSectorSize() { return m_geometry.iBytesPerSector; };
+ int GetSectorCount() { return m_geometry.iSectors; };
+
+ BOOL ReadSector( void*, int );
+ BOOL WriteSector( int, void* );
+
+ BOOL Duplicate( CDisk*, DISK_GEOMETRY* = NULL );
+
+ char* GetImageName() { return m_szFname; };
+
+protected:
+ DISK_GEOMETRY m_geometry;
+ BOOL m_bHasData;
+ BYTE *m_pbtMemory;
+ int m_iAllocated;
+
+ char m_szFname[ 255 ];
+
+ int m_iMaxSectorWritten;
+
+};
+
+#endif
diff --git a/jindroush/include/cdsk_atr.h b/jindroush/include/cdsk_atr.h
new file mode 100644
index 0000000..3f4ac11
--- /dev/null
+++ b/jindroush/include/cdsk_atr.h
@@ -0,0 +1,38 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CATR_H__
+#define __CATR_H__
+
+#include "jintypes.h"
+#include "errbase.h"
+#include "cdisk.h"
+
+#define CATR_FORMAT_VIOLATED ( CATR_BASE + 0 )
+
+class CAtr : public CDisk
+{
+public:
+ CAtr();
+ ~CAtr();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+
+ BOOL Save( char*, BOOL );
+private:
+};
+
+#endif
+
diff --git a/jindroush/include/cdsk_dcm.h b/jindroush/include/cdsk_dcm.h
new file mode 100644
index 0000000..c891852
--- /dev/null
+++ b/jindroush/include/cdsk_dcm.h
@@ -0,0 +1,72 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDCM_H__
+#define __CDCM_H__
+
+#include "errbase.h"
+#include "jintypes.h"
+#include "cdisk.h"
+#include "cfile.h"
+#include "cprefile.h"
+
+#define CDCM_FORMAT_VIOLATED ( CDCM_BASE + 0 )
+
+class CDcm : public CDisk
+{
+public:
+ CDcm();
+ ~CDcm();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+
+ BOOL Save( char*, BOOL );
+
+private:
+
+ BOOL DecodeRec41( CGenFile& );
+ BOOL DecodeRec42( CGenFile& );
+ BOOL DecodeRec43( CGenFile& );
+ BOOL DecodeRec44( CGenFile& );
+ BOOL DecodeRec46( CGenFile& );
+ BOOL DecodeRec47( CGenFile& );
+ BOOL DecodeRecFA( CGenFile& );
+ WORD ReadOffset( CGenFile& );
+
+ void EncodeRec41( BYTE*, int*, BYTE*, BYTE*, int );
+ void EncodeRec43( BYTE*, int*, BYTE*, int );
+ void EncodeRec44( BYTE*, int*, BYTE*, BYTE*, int );
+
+ void EncodeRec45();
+ void EncodeRec46();
+ void EncodeRec( BOOL );
+ void EncodeRecFA( BOOL, int, int, int );
+
+ BOOL m_bLastPass;
+ BYTE m_abtCurrBuff[ 0x100 ];
+ BYTE m_abtPrevBuff[ 0x100 ];
+ int m_iSectorSize;
+ WORD m_wCurrentSector;
+ long m_lFileLength;
+ BOOL m_bAlreadyFormatted;
+
+
+ BYTE* m_pbtCurr;
+ BYTE* m_pbtPass;
+ BYTE* m_pbtLastRec;
+};
+
+#endif
+
diff --git a/jindroush/include/cdsk_scp.h b/jindroush/include/cdsk_scp.h
new file mode 100644
index 0000000..7d43f6b
--- /dev/null
+++ b/jindroush/include/cdsk_scp.h
@@ -0,0 +1,37 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CSCP_H__
+#define __CSCP_H__
+
+#include "jintypes.h"
+#include "cdisk.h"
+
+#define CSCP_FORMAT_VIOLATED ( CSCP_BASE + 0 )
+
+class CScp : public CDisk
+{
+public:
+ CScp();
+ ~CScp();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+ BOOL Save( char*, BOOL );
+
+private:
+};
+
+#endif
+
diff --git a/jindroush/include/cdsk_xfd.h b/jindroush/include/cdsk_xfd.h
new file mode 100644
index 0000000..3acadc5
--- /dev/null
+++ b/jindroush/include/cdsk_xfd.h
@@ -0,0 +1,38 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CXFD_H__
+#define __CXFD_H__
+
+#include "jintypes.h"
+#include "cdisk.h"
+#include "errbase.h"
+
+#define CXFD_FORMAT_VIOLATED ( CXFD_BASE + 0 )
+
+class CXfd : public CDisk
+{
+public:
+ CXfd();
+ ~CXfd();
+
+ BOOL Load( char*, BOOL = FALSE, BOOL = FALSE );
+ BOOL Save( char*, BOOL );
+
+private:
+};
+
+#endif
+
diff --git a/jindroush/include/cfile.h b/jindroush/include/cfile.h
new file mode 100644
index 0000000..4f65e9e
--- /dev/null
+++ b/jindroush/include/cfile.h
@@ -0,0 +1,54 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "jintypes.h"
+#include "cgenfile.h"
+
+#ifndef __CFILE_H__
+#define __CFILE_H__
+
+
+class CFile : public CGenFile
+{
+public:
+ CFile();
+ ~CFile();
+
+ BOOL Open( char* );
+ BOOL Create( char* );
+
+ BOOL Read( void*, int, int* = NULL );
+ BOOL Write( void*, int, int* = NULL );
+
+ BOOL Seek( long, int );
+ long GetLength() { return m_lLength; };
+ DWORD GetLastError() { return m_dwLastError; };
+ void Close();
+
+ BOOL IsDirty() { return m_bIsDirty; };
+
+private:
+ BOOL m_bOpened;
+ BOOL m_bIsDirty;
+
+ int m_hFile;
+
+ DWORD m_dwLastError;
+
+ LONG m_lLength;
+
+};
+
+#endif //__CFILE_H__
diff --git a/jindroush/include/cfs.h b/jindroush/include/cfs.h
new file mode 100644
index 0000000..c7b1651
--- /dev/null
+++ b/jindroush/include/cfs.h
@@ -0,0 +1,65 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CFS_H__
+#define __CFS_H__
+
+#include "adsk.h"
+#include "cobj.h"
+
+#define DIRE_DELETED 0x00000001
+#define DIRE_SUBDIR 0x00000002
+
+class CDirEntry
+{
+public:
+ CDirEntry();
+ ~CDirEntry();
+
+ char m_szFname[ 256 ];
+ char m_szAscData[ 256 ];
+ DWORD m_dwFlags;
+ CDirEntry* m_pSubdir;
+ CDirEntry* m_pNext;
+ CDirEntry* m_pPrev;
+};
+
+class CFs : public CObj
+{
+public:
+
+ CFs();
+ virtual ~CFs();
+
+ virtual BOOL Mount( ADisk* ) = 0;
+ virtual void Dismount() = 0;
+ virtual BOOL ExportFile( char*, CDirEntry* ) = 0;
+ CDirEntry* GetRoot() { return m_pRoot; };
+
+ int GetInvalidPercent() { return (m_iFilesInvalid+m_iFilesValid) ? ( m_iFilesInvalid * 100 ) / ( m_iFilesValid + m_iFilesInvalid ) : 0; };
+
+ void DeleteList( CDirEntry* );
+
+protected:
+ int m_iFilesValid;
+ int m_iFilesInvalid;
+
+
+ CDirEntry* m_pRoot;
+ ADisk* m_pDisk;
+};
+
+#endif
+
diff --git a/jindroush/include/cfs_b2b.h b/jindroush/include/cfs_b2b.h
new file mode 100644
index 0000000..2b838bb
--- /dev/null
+++ b/jindroush/include/cfs_b2b.h
@@ -0,0 +1,42 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CBAS2BOOT_H__
+#define __CBAS2BOOT_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+class CBas2BootDirEntry : public CDirEntry
+{
+public:
+ DWORD m_dwFileLen;
+};
+
+class CBas2Boot : public CFs
+{
+public:
+ CBas2Boot();
+ ~CBas2Boot();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CBas2BootDirEntry* CreateEntry();
+};
+
+#endif
diff --git a/jindroush/include/cfs_boot.h b/jindroush/include/cfs_boot.h
new file mode 100644
index 0000000..e440e67
--- /dev/null
+++ b/jindroush/include/cfs_boot.h
@@ -0,0 +1,42 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CBOOT_H__
+#define __CBOOT_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+class CBootDirEntry : public CDirEntry
+{
+public:
+ int m_iSectorCount;
+};
+
+class CBoot : public CFs
+{
+public:
+ CBoot();
+ ~CBoot();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CBootDirEntry* CreateEntry();
+};
+
+#endif
diff --git a/jindroush/include/cfs_dos2.h b/jindroush/include/cfs_dos2.h
new file mode 100644
index 0000000..867755d
--- /dev/null
+++ b/jindroush/include/cfs_dos2.h
@@ -0,0 +1,67 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDOS2_H__
+#define __CDOS2_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+#pragma pack(1)
+typedef struct
+{
+ BYTE btFlags;
+ WORD wSecCount; //Number of sectors in file
+ WORD wSecStart; //First sector in file
+ CHAR acAtariName[11];
+} DOS2_DIRENT;
+
+#pragma pack()
+
+//flags bits:
+// 0x80 7->deleted
+// 0x40 6->in use
+// 0x20 5->locked
+// 0x10 4->mydos subdir
+// 0x08 3->
+// 0x04 2->
+// 0x02 1->
+// 0x01 0->write open
+
+class CDos2DirEntry : public CDirEntry
+{
+public:
+ WORD m_wFileNumber;
+ BYTE m_btFlags;
+ WORD m_wSecCount; //Number of sectors in file
+ WORD m_wSecStart; //First sector in file
+};
+
+class CDos2 : public CFs
+{
+public:
+ CDos2();
+ ~CDos2();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CDos2DirEntry* CreateEntry( DOS2_DIRENT*, WORD );
+
+};
+
+#endif
diff --git a/jindroush/include/cfs_dos3.h b/jindroush/include/cfs_dos3.h
new file mode 100644
index 0000000..9e7133a
--- /dev/null
+++ b/jindroush/include/cfs_dos3.h
@@ -0,0 +1,59 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDOS3_H__
+#define __CDOS3_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+#pragma pack(1)
+typedef struct
+{
+ BYTE btFlags;
+ CHAR acAtariName[11];
+ BYTE btSecCount;
+ BYTE btSecStart;
+ WORD wFileLen;
+} DOS3_DIRENT;
+
+#pragma pack()
+
+class CDos3DirEntry : public CDirEntry
+{
+public:
+ BYTE m_btSecStart;
+ BYTE m_btSecCount;
+ BYTE m_btFlags;
+ WORD m_wFileLen;
+};
+
+class CDos3 : public CFs
+{
+public:
+ CDos3();
+ ~CDos3();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CDos3DirEntry* CreateEntry( DOS3_DIRENT* );
+
+ BYTE m_abtFat[ 0x0100 ];
+};
+
+#endif
diff --git a/jindroush/include/cfs_dosm.h b/jindroush/include/cfs_dosm.h
new file mode 100644
index 0000000..9ef9262
--- /dev/null
+++ b/jindroush/include/cfs_dosm.h
@@ -0,0 +1,66 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDOSM_H__
+#define __CDOSM_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+#pragma pack(1)
+typedef struct
+{
+ BYTE btFlags;
+ WORD wSecCount; //Number of sectors in file
+ WORD wSecStart; //First sector in file
+ CHAR acAtariName[11];
+} DOSM_DIRENT;
+
+#pragma pack()
+
+//flags bits:
+// 0x80 7->deleted
+// 0x40 6->in use
+// 0x20 5->locked
+// 0x10 4->mydos subdir
+// 0x08 3->
+// 0x04 2->
+// 0x02 1->
+// 0x01 0->write open
+
+class CDosMDirEntry : public CDirEntry
+{
+public:
+ BYTE m_btFlags;
+ WORD m_wSecCount; //Number of sectors in file
+ WORD m_wSecStart; //First sector in file
+};
+
+class CDosM : public CFs
+{
+public:
+ CDosM();
+ ~CDosM();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+ BOOL ReadDir( int, CDosMDirEntry** );
+
+private:
+ CDosMDirEntry* CreateEntry( DOSM_DIRENT* );
+};
+
+#endif
diff --git a/jindroush/include/cfs_doss.h b/jindroush/include/cfs_doss.h
new file mode 100644
index 0000000..31b5124
--- /dev/null
+++ b/jindroush/include/cfs_doss.h
@@ -0,0 +1,70 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CDOSS_H__
+#define __CDOSS_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+#pragma pack(1)
+typedef struct
+{
+ BYTE btFlags;
+ WORD wSector;
+ WORD wSizeLo;
+ BYTE btSizeHi;
+ CHAR acAtariName[11];
+ BYTE btDay;
+ BYTE btMonth;
+ BYTE btYear;
+ BYTE btHour;
+ BYTE btMinute;
+ BYTE btSecond;
+} DOSS_DIRENT;
+
+#pragma pack()
+
+class CDosSDirEntry : public CDirEntry
+{
+public:
+ BYTE m_btFlags;
+ int m_iLength;
+ int m_iLinkSector;
+};
+
+class CDosS : public CFs
+{
+public:
+ CDosS();
+ ~CDosS();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+ BOOL ReadDir( int, CDosSDirEntry** );
+
+private:
+ CDosSDirEntry* CreateEntry( DOSS_DIRENT* );
+ int GetSectorLinkEntry( int, int );
+
+ BYTE* MapFile( int, int );
+ void UnMapFile( BYTE* );
+
+ WORD m_wMainDirStart;
+ WORD m_wSectorSize;
+};
+
+#endif
diff --git a/jindroush/include/cfs_howf.h b/jindroush/include/cfs_howf.h
new file mode 100644
index 0000000..9705ad9
--- /dev/null
+++ b/jindroush/include/cfs_howf.h
@@ -0,0 +1,43 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CHOWF_H__
+#define __CHOWF_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+class CHowfDirEntry : public CDirEntry
+{
+public:
+ int m_iStartSec;
+ int m_iSecCount;
+};
+
+class CHowf : public CFs
+{
+public:
+ CHowf();
+ ~CHowf();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CHowfDirEntry* CreateEntry( WORD, BYTE* );
+};
+
+#endif
diff --git a/jindroush/include/cfs_jonw.h b/jindroush/include/cfs_jonw.h
new file mode 100644
index 0000000..6131c76
--- /dev/null
+++ b/jindroush/include/cfs_jonw.h
@@ -0,0 +1,43 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CJONW_H__
+#define __CJONW_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+class CJonwDirEntry : public CDirEntry
+{
+public:
+ int m_iStartSec;
+ int m_iSecCount;
+};
+
+class CJonw : public CFs
+{
+public:
+ CJonw();
+ ~CJonw();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CJonwDirEntry* CreateEntry( BYTE, WORD, BYTE* );
+};
+
+#endif
diff --git a/jindroush/include/cfs_kboo.h b/jindroush/include/cfs_kboo.h
new file mode 100644
index 0000000..c0df3e1
--- /dev/null
+++ b/jindroush/include/cfs_kboo.h
@@ -0,0 +1,42 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CKBOOT_H__
+#define __CKBOOT_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+class CKBootDirEntry : public CDirEntry
+{
+public:
+ DWORD m_dwFileLen;
+};
+
+class CKBoot : public CFs
+{
+public:
+ CKBoot();
+ ~CKBoot();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CKBootDirEntry* CreateEntry();
+};
+
+#endif
diff --git a/jindroush/include/cfs_robc.h b/jindroush/include/cfs_robc.h
new file mode 100644
index 0000000..1e4b412
--- /dev/null
+++ b/jindroush/include/cfs_robc.h
@@ -0,0 +1,43 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __CROBC_H__
+#define __CROBC_H__
+
+#include "jintypes.h"
+#include "cfs.h"
+
+class CRobcDirEntry : public CDirEntry
+{
+public:
+ int m_iStartSec;
+ int m_iSecCount;
+};
+
+class CRobc : public CFs
+{
+public:
+ CRobc();
+ ~CRobc();
+
+ BOOL Mount( ADisk* );
+ void Dismount();
+ BOOL ExportFile( char*, CDirEntry* );
+
+private:
+ CRobcDirEntry* CreateEntry( BYTE, WORD, BYTE* );
+};
+
+#endif
diff --git a/jindroush/include/cgenfile.h b/jindroush/include/cgenfile.h
new file mode 100644
index 0000000..c97e214
--- /dev/null
+++ b/jindroush/include/cgenfile.h
@@ -0,0 +1,55 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "jintypes.h"
+
+#ifndef __CGENFILE_H__
+#define __CGENFILE_H__
+
+class CGenFile
+{
+public:
+ virtual ~CGenFile() {};
+
+ virtual BOOL Read( void*, int, int* = NULL ) = 0;
+ virtual BOOL Write( void*, int, int* = NULL ) = 0;
+
+ virtual BOOL Seek( long, int ) = 0;
+
+ virtual void Close() = 0;
+
+ void writeb( BYTE );
+ void writeLEw( WORD );
+ void writeBEw( WORD );
+ void writeLEdw( DWORD );
+
+ BYTE readb();
+ WORD readLEw();
+ WORD readBEw();
+ DWORD readLEdw();
+
+ WORD readw();
+ DWORD readd();
+
+ BOOL skip( long );
+
+ long Tell();
+
+ LONG m_lCurrPtr;
+
+private:
+};
+
+#endif
diff --git a/jindroush/include/cobj.h b/jindroush/include/cobj.h
new file mode 100644
index 0000000..0d39ea9
--- /dev/null
+++ b/jindroush/include/cobj.h
@@ -0,0 +1,34 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __COBJ_H__
+#define __COBJ_H__
+
+#include "jintypes.h"
+
+class CObj
+{
+public:
+ CObj();
+ const char* GetLastError( char* p = NULL ) { if ( p ) strcpy( p, m_szLastError ); return m_szLastError; };
+ void SetLastError( char* p ) { strcpy( m_szLastError, p ); };
+ int GetErrorCode() { return m_iErrorCode; };
+
+protected:
+ char m_szLastError[ 4096 ];
+ int m_iErrorCode;
+};
+
+#endif
diff --git a/jindroush/include/cprefile.h b/jindroush/include/cprefile.h
new file mode 100644
index 0000000..1e748bb
--- /dev/null
+++ b/jindroush/include/cprefile.h
@@ -0,0 +1,56 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "jintypes.h"
+#include "cgenfile.h"
+
+#ifndef __CPREFILE_H__
+#define __CPREFILE_H__
+
+
+class CPreFile : public CGenFile
+{
+public:
+ CPreFile();
+ ~CPreFile();
+
+ BOOL Open( CGenFile*, int );
+
+ BOOL Read( void*, int, int* = NULL );
+ BOOL Write( void*, int, int* = NULL );
+
+ BOOL Seek( long, int );
+ long GetLength() { return m_lLength; };
+ DWORD GetLastError() { return m_dwLastError; };
+ void Close();
+
+private:
+ BOOL PreRead();
+
+ BOOL m_bOpened;
+
+ DWORD m_dwLastError;
+
+ long m_lCacheStartOffset;
+ long m_lCacheEndOffset;
+
+ long m_lLength;
+ BYTE* m_pbtCache;
+ long m_lCacheLen;
+
+ CGenFile* m_pcf;
+};
+
+#endif //__CPreFILE_H__
diff --git a/jindroush/include/errbase.h b/jindroush/include/errbase.h
new file mode 100644
index 0000000..8c16c0c
--- /dev/null
+++ b/jindroush/include/errbase.h
@@ -0,0 +1,26 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __ERRBASE_H__
+#define __ERRBASE_H__
+
+#define CDISK_BASE 0x1000
+#define CATR_BASE 0x2000
+#define CDCM_BASE 0x3000
+#define CSCP_BASE 0x4000
+#define CXFD_BASE 0x5000
+#define CDI_BASE 0x6000
+
+#endif
diff --git a/jindroush/include/jintypes.h b/jindroush/include/jintypes.h
new file mode 100644
index 0000000..fab787a
--- /dev/null
+++ b/jindroush/include/jintypes.h
@@ -0,0 +1,95 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#ifndef __WINTYPES_H__
+#define __WINTYPES_H__
+
+#include <errno.h>
+#include <time.h>
+#include <sys/timeb.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifndef MAX_PATH
+#define MAX_PATH 256
+#endif
+
+#ifdef __DJGPP__
+ #include <conio.h>
+ #include <direct.h>
+ #include <io.h>
+ #include <dos.h>
+#else
+ #define tell(x) lseek(x,0,SEEK_CUR)
+ #define _fixpath(x,y) strcpy(y,x)
+ #define getch() getchar()
+
+#endif
+
+#ifndef _WINDOWS
+typedef int BOOL;
+#define TRUE ( 1==1 )
+#define FALSE ( !TRUE )
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+
+typedef unsigned char UBYTE;
+typedef unsigned short UWORD;
+typedef unsigned long UDWORD;
+
+typedef char CHAR;
+typedef long LONG;
+typedef short SHORT;
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+
+typedef char SBYTE;
+typedef short SWORD;
+typedef long SDWORD;
+
+typedef WORD WCHAR;
+typedef CHAR TCHAR;
+
+// typedef WORD wchar_t;
+
+typedef const char* LPCSTR;
+typedef const WCHAR* LPCWSTR;
+typedef const TCHAR* LPCTSTR;
+
+typedef TCHAR* LPTSTR;
+typedef CHAR LPSTR;
+
+#define PASCAL pascal
+#else
+
+#include <windows.h>
+#endif
+
+#endif //
diff --git a/jindroush/lib/Makefile b/jindroush/lib/Makefile
new file mode 100644
index 0000000..bafe06c
--- /dev/null
+++ b/jindroush/lib/Makefile
@@ -0,0 +1,23 @@
+OBJS=adsk.o adsk_atr.o adsk_dcm.o adsk_di.o \
+ adsk_scp.o adsk_xfd.o at_dis.o autil.o \
+ cdsk.o cdsk_atr.o cdsk_dcm.o cdsk_scp.o \
+ cdsk_xfd.o cfile.o cgenfile.o cobj.o cprefile.o \
+ cdisk.o cfs.o cfs_b2b.o cfs_boot.o cfs_dos2.o \
+ cfs_dos3.o cfs_dosm.o cfs_doss.o cfs_howf.o \
+ cfs_jonw.o cfs_kboo.o cfs_robc.o
+
+COPT=-O2
+CXX=g++
+CXXFLAGS=$(COPT) -D__CDISK_SAVE__ -D__CDISK_WRITE__
+
+all: libjindroush.a
+
+libjindroush.a: $(OBJS)
+ ar r libjindroush.a $(OBJS)
+ ranlib libjindroush.a
+
+clean:
+ rm -f *.o *.a
+
+%.o : %.cpp
+ $(CXX) -I../include $(CXXFLAGS) -c $<
diff --git a/jindroush/lib/adsk.cpp b/jindroush/lib/adsk.cpp
new file mode 100644
index 0000000..e5d0b5a
--- /dev/null
+++ b/jindroush/lib/adsk.cpp
@@ -0,0 +1,319 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk.h"
+
+ADisk::ADisk() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "ADisk constructed: %p\n", this );
+ #endif
+}
+
+ADisk::~ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "ADisk destructed: %p\n", this );
+ #endif
+}
+
+void GuessClassicSizes( int iSectors, int iSectorSize, DISK_GEOMETRY* pGeometry )
+{
+ pGeometry->iSides = 1;
+ pGeometry->iBytesPerSector = iSectorSize;
+
+ pGeometry->iTracks = 1;
+ pGeometry->iSectorsPerTrack = iSectors;
+
+ switch( iSectors )
+ {
+ case 720:
+ switch( iSectorSize )
+ {
+ case 0x80:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+
+ case 0x100:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+ }
+ break;
+
+ case 1040:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ break;
+
+ }
+
+}
+
+void ForceClassicSize( DISK_GEOMETRY* pGeometry )
+{
+ ForceClassicSize( pGeometry->iSectors, pGeometry->iBytesPerSector, pGeometry );
+}
+
+void ForceClassicSize( int iSectors, int iSectorSize, DISK_GEOMETRY* pGeometry )
+{
+ pGeometry->iSides = 1;
+ pGeometry->iBytesPerSector = iSectorSize;
+
+ pGeometry->iTracks = 1;
+ pGeometry->iSectorsPerTrack = iSectors;
+
+ switch( iSectorSize )
+ {
+ case 0x80:
+ if ( iSectors <= 720 )
+ {
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ }
+ else if ( ( iSectors > 720 ) && ( iSectors <= 1040 ) )
+ {
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ }
+ else
+ {
+ GuessClassicSizes( iSectors, iSectorSize, pGeometry );
+ }
+ break;
+
+ case 0x100:
+ default:
+ if ( iSectors <= 720 )
+ {
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ }
+ else
+ {
+ GuessClassicSizes( iSectors, iSectorSize, pGeometry );
+ }
+ break;
+ }
+
+ switch( iSectors )
+ {
+ case 720:
+ switch( iSectorSize )
+ {
+ case 0x80:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+
+ case 0x100:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+ }
+ break;
+
+ case 1040:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ break;
+
+ }
+
+}
+
+
+//returns ptr to disk type name
+char* GetDiskTypeName( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ return "XFD";
+
+ case DISK_ATR:
+ return "ATR";
+
+ case DISK_XFDb:
+ return "XFDb";
+
+ case DISK_ATRb:
+ return "ATRb";
+
+ case DISK_DCM:
+ return "DCM";
+
+ case DISK_SCP:
+ return "SCP";
+
+ case DISK_DI:
+ return "DI";
+
+ default:
+ return "None";
+ }
+}
+
+//returns ptr to disk type extension
+char* GetDiskTypeExt( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ case DISK_XFDb:
+ return "xfd";
+
+ case DISK_ATR:
+ case DISK_ATRb:
+ return "atr";
+
+ case DISK_DCM:
+ return "dcm";
+
+ case DISK_SCP:
+ return "scp";
+
+ case DISK_DI:
+ return "di";
+
+ default:
+ return "xxx";
+ }
+}
+
+#ifndef __CDISK_NOLOAD__
+DISKINIT_RETCODE InitializeDisk( ADisk** ppDisk, DISK_TYPE disktype, char* szFname, BOOL bVerbose, BOOL bRepair, BOOL bRepairAuto )
+{
+ switch( disktype )
+ {
+ case DISK_ATR:
+ *ppDisk = new CAtr();
+ break;
+
+ case DISK_SCP:
+ *ppDisk = new CScp();
+ break;
+
+ case DISK_DCM:
+ *ppDisk = new CDcm();
+ break;
+
+ case DISK_XFD:
+ *ppDisk = new CXfd();
+ break;
+
+ case DISK_DI:
+ *ppDisk = new CDi();
+ break;
+
+ default:
+ if ( bVerbose )
+ fprintf( stderr, "Invalid disk type specified!\n" );
+ return DI_RET_CANT_CONTINUE;
+ }
+
+ if ( !*ppDisk )
+ {
+ if ( bVerbose )
+ fprintf( stderr, "Can't initialize disk driver!\n" );
+ return DI_RET_CONTINUE;
+ }
+
+ if ( !(*ppDisk)->Load( szFname, bRepair, bRepairAuto ) )
+ {
+ int iError = (*ppDisk)->GetErrorCode();
+
+ DISKINIT_RETCODE ret = DI_RET_CONTINUE;
+
+ switch( iError )
+ {
+ case CATR_FORMAT_VIOLATED:
+ case CXFD_FORMAT_VIOLATED:
+ case CDISK_ERROR_CANT_OPEN:
+ case CDCM_FORMAT_VIOLATED:
+ case CSCP_FORMAT_VIOLATED:
+ case CDI_FORMAT_VIOLATED:
+ ret = DI_RET_CANT_CONTINUE;
+ break;
+ }
+
+ if ( bVerbose || ( ret == DI_RET_CANT_CONTINUE ) )
+ {
+ printf( "Input file '%s' ", szFname );
+ printf( "(%s)\n", GetDiskTypeName( disktype ) );
+ printf( "Load failed because:\n%s\n", (*ppDisk)->GetLastError() );
+ }
+ if ( ret != DI_RET_OK )
+ {
+ delete *ppDisk;
+ return ret;
+ }
+ }
+
+ return DI_RET_OK;
+}
+#endif
+
+BOOL ADisk::ReadSectors( void* pBuf, int iStartSec, int iSecs )
+{
+ while( iSecs )
+ {
+ if ( !ReadSector( pBuf, iStartSec ) )
+ return FALSE;
+
+ pBuf = (BYTE*)pBuf + ( ( iStartSec <= 3 ) ? 0x80 :m_geometry.iBytesPerSector );
+ iStartSec++;
+ iSecs--;
+ }
+
+ return TRUE;
+}
+
+BOOL ADisk::WriteSectors( int iStartSec, void* pBuf, int iSecs )
+{
+ while( iSecs )
+ {
+ if ( !WriteSector( iStartSec, pBuf ) )
+ return FALSE;
+
+ pBuf = (BYTE*)pBuf + ( ( iStartSec <= 3 ) ? 0x80 :m_geometry.iBytesPerSector );
+ iStartSec++;
+ iSecs--;
+ }
+
+ return TRUE;
+}
+
+int ADisk::GetBootSectorCount()
+{
+ return m_pbtMemory[ 1 ];
+}
+
+int ADisk::GetBootSectorSize()
+{
+ int iSecCount = GetBootSectorCount();
+
+ if ( iSecCount > 3 )
+ return ( ( iSecCount - 3 ) * GetSectorSize() + 0x180 );
+ else
+ return iSecCount * 0x80;
+}
+
+BOOL ADisk::GetBootSector( BYTE* pbtData )
+{
+ return ReadSectors( pbtData, 1, GetBootSectorCount() );
+}
+
diff --git a/jindroush/lib/adsk_atr.cpp b/jindroush/lib/adsk_atr.cpp
new file mode 100644
index 0000000..ad7dce6
--- /dev/null
+++ b/jindroush/lib/adsk_atr.cpp
@@ -0,0 +1,483 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_atr.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define ATR_MAGIC 0x0296
+
+typedef struct
+{
+ WORD wMagic;
+ WORD wPars;
+ WORD wSecSize;
+ BYTE btParHigh;
+ DWORD dwCRC;
+ DWORD dwUnused;
+ BYTE btFlags;
+
+} ATRhead;
+
+#define ATR_HEAD_LEN 0x10
+
+CAtr::CAtr() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr constructed: %p\n", this );
+ #endif
+}
+
+CAtr::~CAtr()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr destructed: %p\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3,
+ LOAD_PAD
+} LOAD_VARIANT;
+
+#ifndef __CDISK_NOLOAD__
+BOOL CAtr::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ m_iErrorCode = 0;
+
+ int iFirstSectorsSize = 0x80;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ ATRhead head;
+
+ head.wMagic = cf.readLEw();
+ head.wPars = cf.readLEw();
+ head.wSecSize = cf.readLEw();
+ head.btParHigh = cf.readb();
+ head.dwCRC = cf.readLEdw();
+ head.dwUnused = cf.readLEdw();
+ head.btFlags = cf.readb();
+
+ if ( head.wMagic != ATR_MAGIC )
+ {
+ sprintf( m_szLastError, "ATR: File '%s' is not an ATR file!", szFname );
+ return FALSE;
+ }
+
+ LONG lFileLen = cf.GetLength();
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( head.wSecSize )
+ {
+ case 0x80:
+ case 0x100:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "ATR: Invalid sector size: %04X", head.wSecSize );
+ return FALSE;
+ }
+ }
+
+ DWORD dwPars = head.wPars | ( head.btParHigh << 16 );
+
+ int iSectors = ( dwPars * 0x10 ) / head.wSecSize;
+
+ //BOOL bReadOnly = (head.btFlags & 1) ? TRUE : FALSE;
+
+ if ( head.wSecSize == 0x100 )
+ {
+ //if ( dwPars % head.wSecSize )
+ if ( ( dwPars * 0x10 ) % head.wSecSize )
+ {
+ iSectors = ( ( dwPars * 0x10 - 0x180 ) / head.wSecSize ) + 3;
+ }
+ else
+ {
+ sprintf( m_szLastError, "ATR: Format violated. First three sectors are not $80 long!" );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ #ifdef __CDISK_NOREPAIR__
+ return FALSE;
+ #else
+ if ( !bRepair )
+ {
+ return FALSE;
+ }
+ else
+ {
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ switch( iMethod )
+ {
+ case 1:
+ load_method = LOAD_BAD_DD_1;
+ break;
+ case 2:
+ load_method = LOAD_BAD_DD_2;
+ break;
+ case 3:
+ load_method = LOAD_BAD_DD_3;
+ break;
+ default:
+ case 4:
+ return FALSE;
+ break;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ case LOAD_BAD_DD_2:
+ case LOAD_BAD_DD_3:
+ iFirstSectorsSize = 0x100;
+ break;
+
+ default:
+ break;
+
+ }
+
+ } //end of repair
+
+ #endif
+ }
+ }
+
+ LONG lTotalComputedLen = (LONG) ( ( iSectors - 3 ) * head.wSecSize + ATR_HEAD_LEN + 3 * iFirstSectorsSize );
+
+ if ( lTotalComputedLen != lFileLen )
+ {
+ sprintf( m_szLastError, "ATR: Invalid length! %08lX <> %08lX (%08X)", lTotalComputedLen, lFileLen, iSectors );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ #ifdef __CDISK_NOREPAIR__
+ return FALSE;
+ #else
+ if ( !bRepair || ( load_method != LOAD_OK ) )
+ return FALSE;
+ else
+ {
+ if ( !bRepairAuto )
+ {
+ printf( "ATR with invalid length encountered.\n" );
+ printf( "Should be: $%08lX. Is: $%08lX.\n", lTotalComputedLen, lFileLen );
+ printf( "Choose:\n" );
+ printf( "1) Change file length (shorten/pad)\n" );
+ printf( "2) Change header info\n" );
+ printf( "3) Don't repair\n" );
+
+ int iMethod;
+
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 3 ) );
+
+ switch( iMethod )
+ {
+ case 1:
+ load_method = LOAD_PAD;
+ break;
+
+ case 2:
+ load_method = LOAD_OK;
+ if ( lFileLen > 0x180 )
+ {
+ iSectors = ( ( lFileLen - 0x180 ) / head.wSecSize ) + 3;
+ }
+ else
+ {
+ iSectors = lFileLen / 0x80;
+ }
+
+ break;
+
+ default:
+ case 3:
+ return FALSE;
+ break;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_PAD;
+ }
+
+ }
+ #endif
+
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSectors, head.wSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_PAD:
+ memset( abtBuff, 0, 0x100 );
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ WriteSector( i + 1, abtBuff );
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#endif
+
+#ifdef __CDISK_SAVE__
+
+BOOL CAtr::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "ATR: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ ATRhead head;
+ memset( &head, 0, sizeof( ATRhead ) );
+
+ head.wMagic = ATR_MAGIC;
+ head.wSecSize = m_geometry.iBytesPerSector;
+
+ BOOL bReadOnly = TRUE;
+ head.btFlags |= ( bReadOnly ) ? 0x01 : 0x00;
+
+ DWORD dwLength = 0;
+
+ dwLength = 0x180 + ( m_geometry.iSectors - 3 ) * m_geometry.iBytesPerSector;
+
+ dwLength >>= 4;
+
+ head.wPars = dwLength & 0xFFFF;
+ head.btParHigh = dwLength >> 0x10;
+
+ cf.writeLEw( head.wMagic );
+ cf.writeLEw( head.wPars );
+ cf.writeLEw( head.wSecSize );
+ cf.writeb( head.btParHigh );
+ cf.writeLEdw( head.dwCRC );
+ cf.writeLEdw( head.dwUnused );
+ cf.writeb( head.btFlags );
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ ReadSector( abtBuff, i );
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iToWrite != iWritten ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/adsk_dcm.cpp b/jindroush/lib/adsk_dcm.cpp
new file mode 100644
index 0000000..d664761
--- /dev/null
+++ b/jindroush/lib/adsk_dcm.cpp
@@ -0,0 +1,764 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_dcm.h"
+#include "cfile.h"
+#include "cprefile.h"
+#include "autil.h"
+
+//#define _DCM_DUMP_
+
+#define DCM_CHANGE_BEGIN 0x41 //Change only start of sector
+#define DCM_DOS_SECTOR 0x42 //128 byte compressed sector
+#define DCM_COMPRESSED 0x43 //Uncompressed/compressed pairs
+#define DCM_CHANGE_END 0x44 //Change only end of sector
+#define DCM_PASS_END 0x45 //End of pass
+#define DCM_SAME_AS_BEFORE 0x46 //Same as previous non-zero
+#define DCM_UNCOMPRESSED 0x47 //Uncompressed sector
+
+#define DCM_HEADER_SINGLE 0xFA
+#define DCM_HEADER_MULTI 0xF9
+
+#define DCM_DENSITY_SD 0 //Single density, 90K
+#define DCM_DENSITY_DD 1 //Double density, 180K
+#define DCM_DENSITY_ED 2 //Enhanced density, 130K
+
+CDcm::CDcm() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm constructed: %p\n", this );
+ #endif
+}
+
+CDcm::~CDcm()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm destructed: %p\n", this );
+ #endif
+}
+
+#ifndef __CDISK_NOLOAD__
+BOOL CDcm::Load( char* szFname, BOOL, BOOL )
+{
+ BYTE btArcType = 0; //Block type for first block
+ BYTE btBlkType; //Current block type
+
+ m_bAlreadyFormatted = FALSE;
+ m_bLastPass = FALSE;
+ m_wCurrentSector = 0;
+
+ CFile cfo;
+ CPreFile cf;
+
+ if ( !cfo.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ cf.Open( &cfo, 20 );
+
+ m_lFileLength = cf.GetLength();
+
+ for(;;) //outpass
+ {
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ if ( ( !m_bLastPass ) && ( btArcType == DCM_HEADER_MULTI ) )
+ {
+ sprintf( m_szLastError,"DCM: Multi-part archive error.\n" \
+ "To process these files, you must first combine the files into a single file." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ btArcType = cf.readb();
+
+ switch( btArcType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ if ( !DecodeRecFA( cf ) )
+ return FALSE;
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown header block.\n", btArcType );
+ return FALSE;
+ }
+
+ for(;;) //inpass
+ {
+ btBlkType = cf.readb();
+
+ if ( btBlkType == DCM_PASS_END )
+ break;
+
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ sprintf( m_szLastError, "DCM: EOF before end block." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ BOOL bRes = TRUE;
+
+ *m_szLastError = '\0';
+ switch( btBlkType & 0x7F )
+ {
+ case DCM_CHANGE_BEGIN:
+ bRes = DecodeRec41( cf );
+ break;
+
+ case DCM_DOS_SECTOR:
+ bRes = DecodeRec42( cf );
+ break;
+
+ case DCM_COMPRESSED:
+ bRes = DecodeRec43( cf );
+ break;
+
+ case DCM_CHANGE_END:
+ bRes = DecodeRec44( cf );
+ break;
+
+ case DCM_SAME_AS_BEFORE:
+ //not needed
+ //bRes = DecodeRec46( cf );
+ break;
+
+ case DCM_UNCOMPRESSED:
+ bRes = DecodeRec47( cf );
+ break;
+
+ default:
+ {
+ switch( btBlkType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ sprintf( m_szLastError, "DCM: Trying to start section but last section never had "
+ "an end section block.");
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown block type. File may be "
+ "corrupt.",btBlkType);
+ break;
+ }
+
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ if ( !bRes )
+ {
+ sprintf( m_szLastError, "DCM: Block %02X decode error!", btBlkType );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ if ( !WriteSector( m_wCurrentSector, m_abtCurrBuff ) )
+ return FALSE;
+
+ if ( btBlkType & 0x80 )
+ m_wCurrentSector++;
+ else
+ m_wCurrentSector = cf.readLEw();
+
+ } //infinite for (inpass)
+
+ //End block
+ if ( m_bLastPass )
+ break;
+
+ } //infinite for (outpass)
+
+ cf.Close();
+ cfo.Close();
+ return TRUE;
+
+}
+
+BOOL CDcm::DecodeRec41( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec41: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = cf.readb();
+ BYTE* pbt = m_abtCurrBuff + iOffset;
+
+ do
+ {
+ *( pbt-- ) = cf.readb();
+ } while( iOffset-- );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec42( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec42: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ sprintf( m_szLastError, "DCM: Record type 0x42 untested. Uncomment?" );
+ return FALSE;
+
+ //TODO: uncomment later!
+ //cf.Read( m_abtCurrBuff + 123, 5 );
+ //memset( m_abtCurrBuff, m_abtCurrBuff[ 123 ], 123 );
+ //return TRUE;
+}
+
+BOOL CDcm::DecodeRec43( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec43: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE* pbtP = m_abtCurrBuff;
+ BYTE* pbtE;
+
+ BYTE* pbtEnd = m_abtCurrBuff + m_iSectorSize;
+
+ do
+ {
+ //uncompressed string
+ if ( pbtP != m_abtCurrBuff )
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ else
+ pbtE = m_abtCurrBuff + cf.readb();
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: uncst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE != pbtP )
+ {
+ cf.Read( pbtP, pbtE - pbtP );
+ pbtP = pbtE;
+ }
+
+ if ( pbtP >= pbtEnd )
+ break;
+
+ //rle compressed string
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ BYTE c = cf.readb();
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: cst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ memset( pbtP, c, pbtE - pbtP );
+ pbtP = pbtE;
+
+ } while( pbtP < pbtEnd );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec44( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec44: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = ReadOffset( cf );
+
+ cf.Read( m_abtCurrBuff + iOffset, m_iSectorSize - iOffset );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec46( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec46: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec47( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec47: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ //TODO: Is this TRUE or NOT???
+ //cf.Read( m_abtCurrBuff, ( m_wCurrentSector < 4 ? 128 : m_iSectorSize ) );
+
+ cf.Read( m_abtCurrBuff, m_iSectorSize );
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRecFA( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "decFA: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE btPom = cf.readb();
+
+ BYTE btDensity = ( btPom >> 5 ) & 0x03;
+ //BYTE btPass = btPom & 0x1F;
+ m_bLastPass = ( btPom & 0x80 ) ? TRUE : FALSE;
+
+ int iSpT;
+ int iTracks;
+
+ switch( btDensity )
+ {
+ case DCM_DENSITY_SD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 128;
+ break;
+
+ case DCM_DENSITY_DD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 256;
+ break;
+
+ case DCM_DENSITY_ED:
+ iTracks = 40;
+ iSpT = 26;
+ m_iSectorSize = 128;
+ break;
+
+ default:
+ sprintf( m_szLastError,"DCM: Density type unknown (%02X)\n", btDensity );
+ return FALSE;
+ }
+
+ if ( !m_bAlreadyFormatted )
+ {
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = iTracks;
+ dg.iSectorsPerTrack = iSpT;
+ dg.iBytesPerSector = m_iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ m_bAlreadyFormatted = TRUE;
+ }
+
+ m_wCurrentSector = cf.readLEw();
+
+ return TRUE;
+}
+
+WORD CDcm::ReadOffset( CGenFile& cf )
+{
+ BYTE bt = cf.readb();
+
+ return( bt ? bt : 256 );
+}
+#endif
+
+#ifdef __CDISK_SAVE__
+
+BOOL CDcm::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "DCM: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ int iDensity = -1;
+ m_iSectorSize = m_geometry.iBytesPerSector;
+
+ if ( m_iSectorSize == 0x80 )
+ {
+ if ( m_geometry.iTracks == 40 )
+ {
+ if ( m_geometry.iSectorsPerTrack == 18 )
+ iDensity = DCM_DENSITY_SD;
+
+ if ( m_geometry.iSectorsPerTrack == 26 )
+ iDensity = DCM_DENSITY_ED;
+ }
+ }
+
+ if ( m_iSectorSize == 0x100 )
+ {
+ if ( ( m_geometry.iSectorsPerTrack == 18 ) &&
+ ( m_geometry.iTracks == 40 ) )
+ iDensity = DCM_DENSITY_DD;
+ }
+
+ if ( iDensity == - 1 )
+ {
+ sprintf( m_szLastError, "DCM: Can't work with such density!" );
+ return FALSE;
+ }
+
+ int iPass = 1;
+
+ m_pbtPass = new BYTE [ 0x6500 ];
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't create '%s'", szOutFile );
+ delete [] m_pbtPass;
+ return FALSE;
+ }
+
+ int iFirstSector = 0;
+ int iPrevSector = 0;
+ int iCurrentSector = 1;
+
+ memset( m_abtPrevBuff, 0, m_iSectorSize );
+
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //here should be other compression
+
+ while( iCurrentSector <= m_geometry.iSectors )
+ {
+ iFirstSector = 0;
+
+ while( ( m_pbtCurr - m_pbtPass ) < 0x5EFD )
+ {
+ if ( iCurrentSector > m_geometry.iSectors )
+ break;
+
+ ReadSector( m_abtCurrBuff, iCurrentSector );
+
+ BOOL bSkip = IsBlockEmpty( m_abtCurrBuff, m_iSectorSize );
+
+ //first non empty sector is marked as first, what a surprise! :)
+ if ( !bSkip && !iFirstSector )
+ {
+ iFirstSector = iCurrentSector;
+ iPrevSector = iCurrentSector;
+ }
+
+ //if just skipped, increment sector
+ if ( bSkip )
+ {
+ iCurrentSector++;
+ }
+ else
+ {
+ //if there is a gap, write sector number
+ if ( ( iCurrentSector - iPrevSector ) > 1 )
+ {
+ *( m_pbtCurr++ ) = iCurrentSector;
+ *( m_pbtCurr++ ) = iCurrentSector >> 8;
+ }
+ else
+ {
+ //else mark previous record
+ *m_pbtLastRec |= 0x80;
+ }
+
+ //first sector could be encoded with only some data
+ if ( iCurrentSector == iFirstSector )
+ EncodeRec( TRUE );
+ else
+ {
+ //if are same, encode as record 46
+ if ( !memcmp( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize ) )
+ EncodeRec46();
+ else
+ EncodeRec( FALSE );
+ }
+
+ //store this sector as previous
+ memcpy( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize );
+
+ //and move pointers
+ iPrevSector = iCurrentSector;
+ iCurrentSector++;
+ }
+
+ }
+
+ //mark previous sector
+ *m_pbtLastRec |= 0x80;
+
+ //encode end
+ EncodeRec45();
+
+ BYTE* pEnd = m_pbtCurr;
+
+ //change beginning block
+ if ( iCurrentSector > m_geometry.iSectors )
+ EncodeRecFA( TRUE, iPass, iDensity, iFirstSector );
+ else
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //and write whole pass
+
+ if ( ( pEnd - m_pbtPass ) > 0x6000 )
+ {
+ sprintf( m_szLastError, "DCM: Internal error! Pass too long!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Write( m_pbtPass, pEnd - m_pbtPass ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't write!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ iPass++;
+ }
+
+ cf.Close();
+
+ delete [] m_pbtPass;
+
+ return TRUE;
+}
+
+void CDcm::EncodeRecFA( BOOL bLast, int iPass, int iDensity, int iFirstSec )
+{
+ m_pbtCurr = m_pbtPass;
+
+ #ifdef _DCM_DUMP_
+ printf( "ERFA: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE btType = bLast ? 0x80 : 0;
+
+ btType |= ( iDensity & 3 ) << 5;
+
+ btType |= ( iPass & 0x1F );
+
+ *( m_pbtCurr++ ) = DCM_HEADER_SINGLE;
+ *( m_pbtCurr++ ) = btType;
+ *( m_pbtCurr++ ) = iFirstSec;
+ *( m_pbtCurr++ ) = iFirstSec >> 8;
+
+}
+
+void CDcm::EncodeRec45()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER45: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_PASS_END;
+}
+
+void CDcm::EncodeRec46()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER46: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_SAME_AS_BEFORE;
+}
+
+void CDcm::EncodeRec( BOOL bIsFirstSector )
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE abtBuff41[ 0x300 ];
+ BYTE abtBuff43[ 0x300 ];
+ BYTE abtBuff44[ 0x300 ];
+ BYTE* abtBuff47 = m_abtCurrBuff;
+
+ int iEnd41 = 0x300;
+ int iEnd43 = 0x300;
+ int iEnd44 = 0x300;
+
+ int iBestMethod = DCM_UNCOMPRESSED;
+ int iBestEnd = m_iSectorSize;
+ BYTE* pbtBest = abtBuff47;
+
+ EncodeRec43( abtBuff43, &iEnd43, m_abtCurrBuff, m_iSectorSize );
+
+ if ( !bIsFirstSector )
+ {
+ EncodeRec41( abtBuff41, &iEnd41, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ EncodeRec44( abtBuff44, &iEnd44, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ }
+
+ if ( iEnd41 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_BEGIN;
+ iBestEnd = iEnd41;
+ pbtBest = abtBuff41;
+ }
+
+ if ( iEnd43 < iBestEnd )
+ {
+ iBestMethod = DCM_COMPRESSED;
+ iBestEnd = iEnd43;
+ pbtBest = abtBuff43;
+ }
+
+ if ( iEnd44 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_END;
+ iBestEnd = iEnd44;
+ pbtBest = abtBuff44;
+ }
+
+ *( m_pbtCurr++ ) = iBestMethod;
+ memcpy( m_pbtCurr, pbtBest, iBestEnd );
+ m_pbtCurr += iBestEnd;
+}
+
+void CDcm::EncodeRec41( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc + iSrcLen - 1;
+ pbtSrcOld += iSrcLen - 1;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS-- ) != * ( pbtSrcOld-- ) )
+ break;
+ }
+
+ pbtS++;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+
+ int iBytes = pbtS - pbtSrc + 1;
+
+ while( iBytes-- )
+ {
+ *( pbtD++ ) = *( pbtS-- );
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec43( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, int iSrcLen )
+{
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+ BYTE* pbtCur = pbtSrc;
+
+ BYTE* pbtD = pbtDest;
+
+ while( pbtCur < pbtEnd )
+ {
+ BOOL bFound = FALSE;
+
+ for( BYTE* pbtNow = pbtCur; pbtNow < ( pbtEnd - 2 ); pbtNow++ )
+ {
+
+ if ( ( *pbtNow == *(pbtNow+1) ) && ( *pbtNow == *(pbtNow+2) ) )
+ {
+ int iUnc = pbtNow - pbtCur;
+
+ *( pbtD ++ ) = pbtNow - pbtSrc;
+ if ( iUnc )
+ {
+ memcpy( pbtD, pbtCur, iUnc );
+ pbtD += iUnc;
+ }
+
+ BYTE bt = *pbtNow;
+ BYTE*p;
+ for( p = pbtNow + 1; p < pbtEnd; p++ )
+ {
+ if ( *p != bt )
+ break;
+ }
+
+ if ( p > pbtEnd )
+ p = pbtEnd;
+
+ *( pbtD++ ) = p - pbtSrc;
+ *( pbtD++ ) = bt;
+
+ pbtCur = p;
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if ( ( pbtCur >= pbtEnd - 2 ) || !bFound )
+ {
+ if ( pbtCur < pbtEnd )
+ {
+ *( pbtD++ ) = iSrcLen;
+ memcpy( pbtD, pbtCur, pbtEnd - pbtCur );
+ pbtD += pbtEnd - pbtCur;
+ }
+
+ break;
+ }
+
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec44( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc;
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS++ ) != * ( pbtSrcOld++ ) )
+ break;
+ }
+
+ pbtS--;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+ memcpy( pbtD, pbtS, pbtEnd - pbtS );
+ pbtD += pbtEnd - pbtS;
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+#endif // __CDISK_SAVE__
+
diff --git a/jindroush/lib/adsk_di.cpp b/jindroush/lib/adsk_di.cpp
new file mode 100644
index 0000000..b49bb9d
--- /dev/null
+++ b/jindroush/lib/adsk_di.cpp
@@ -0,0 +1,271 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_di.h"
+#include "autil.h"
+#include "cfile.h"
+
+BYTE di_crc( BYTE* pbt, int iLen )
+{
+ WORD crc = 0;
+
+ while( iLen-- )
+ {
+ crc += *( pbt++ );
+ if( crc >= 0x100 )
+ crc -= 0xFF;
+ }
+
+ return crc;
+}
+
+CDi::CDi() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDi constructed: %p\n", this );
+ #endif
+}
+
+CDi::~CDi()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDi destructed: %p\n", this );
+ #endif
+}
+
+#ifndef __CDISK_NOLOAD__
+BOOL CDi::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ m_iErrorCode = 0;
+
+ CFile cf;
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "DI: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ WORD wMagic = cf.readLEw();
+
+ if ( wMagic != 18756 ) //'DI'
+ {
+ sprintf( m_szLastError, "DI: File '%s' is not an DI file!", szFname );
+ return FALSE;
+ }
+
+ BYTE btVerLo = cf.readb();
+ BYTE btVerHi = cf.readb();
+
+ if( ( btVerLo != 0x20 ) || ( btVerHi != 0x02 ) )
+ {
+ sprintf( m_szLastError, "DI: The file '%s' has strange version!\n"
+ "This program can't work with it now.\n"
+ "Send the file for the analysis.", szFname );
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ int iMax = 200;
+ while( iMax-- )
+ {
+ if( ! cf.readb() )
+ break;
+ }
+
+ if( !iMax )
+ {
+ sprintf( m_szLastError, "DI: Runaway in header ('%s')", szFname );
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ //todo: this need the documentation! Is it number of sides?
+ //BYTE btUnk1 =
+ cf.readb();
+
+ BYTE btTracks = cf.readb();
+ WORD wSectorsPerTrack = cf.readBEw();
+
+ //todo: are these the flags?
+ //WORD wUnk2 =
+ //cf.readBEw();
+ BYTE btSides = cf.readb() + 1;
+ cf.readb();
+
+ WORD wSectorSize = cf.readBEw();
+
+ //todo: and what about this?
+ //BYTE btUnk3 =
+ cf.readb();
+
+ switch( wSectorSize )
+ {
+ case 0x80:
+ case 0x100:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "DI: Invalid sector size: %04X", wSectorSize );
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = btSides;
+ dg.iTracks = btTracks;
+ dg.iSectorsPerTrack = wSectorsPerTrack;
+ dg.iBytesPerSector = wSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ int iSectors = m_geometry.iSectors;
+
+ BYTE* pBuf = new BYTE[ iSectors ];
+ cf.Read( pBuf, iSectors );
+
+ BYTE* p = pBuf;
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ if( *p )
+ {
+ int iSecSize = ( i < 3 ) ? 0x80 : wSectorSize;
+
+ int iRead;
+
+ cf.Read( abtBuff, iSecSize, &iRead );
+
+ if ( iRead != iSecSize )
+ {
+ sprintf( m_szLastError, "DI: Read error. File truncated?" );
+ delete [] pBuf;
+ cf.Close();
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ BYTE crc = di_crc( abtBuff, iSecSize );
+
+ if( *p != crc )
+ {
+ sprintf( m_szLastError, "DI: Sector checksum failed: Sector %d Given: %02X Computed: %02X", i + 1, *p, crc );
+ delete [] pBuf;
+ cf.Close();
+ m_iErrorCode = CDI_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ WriteSector( i + 1, abtBuff );
+ }
+ p++;
+ }
+
+ delete [] pBuf;
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#endif
+
+#ifdef __CDISK_SAVE__
+
+char szDIhd[] = "Jindroush's DI class v1.00";
+//char szDIhd[] = "XL/ST-link 2.2.0› ";
+
+BOOL CDi::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if( ( m_geometry.iTracks > 0xFF ) ||
+ ( m_geometry.iSectorsPerTrack > 0xFFFF ) ||
+ ( m_geometry.iSides > 2 ) )
+ {
+ sprintf( m_szLastError, "DI: Can't create such file! Is it possible? :-)" );
+ return FALSE;
+ }
+
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "DI: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "DI: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ cf.writeb( 'D' );
+ cf.writeb( 'I' );
+ cf.writeb( 0x20 );
+ cf.writeb( 0x02 );
+
+ cf.Write( szDIhd, strlen( szDIhd ) + 1 );
+
+ cf.writeb( 1 );
+ cf.writeb( m_geometry.iTracks );
+ cf.writeBEw( m_geometry.iSectorsPerTrack );
+ cf.writeb( m_geometry.iSides - 1 );
+ cf.writeb( 0 );
+ cf.writeBEw( m_geometry.iBytesPerSector );
+ cf.writeb( 0 );
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ BYTE* pBuf = new BYTE[ m_geometry.iSectors ];
+
+ for( int i = 0; i < m_geometry.iSectors; i++ )
+ {
+ int iSecSize = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ ReadSector( abtBuff, i + 1 );
+ pBuf[ i ] = di_crc( abtBuff, iSecSize );
+ }
+
+ cf.Write( pBuf, m_geometry.iSectors );
+
+ for( int i = 0; i < m_geometry.iSectors; i++ )
+ {
+ int iSecSize = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ ReadSector( abtBuff, i + 1 );
+ if( pBuf[ i ] || !IsBlockEmpty( abtBuff, iSecSize ) )
+ {
+ cf.Write( abtBuff, iSecSize );
+ }
+ }
+
+ delete [] pBuf;
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/adsk_scp.cpp b/jindroush/lib/adsk_scp.cpp
new file mode 100644
index 0000000..51d3dae
--- /dev/null
+++ b/jindroush/lib/adsk_scp.cpp
@@ -0,0 +1,281 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_scp.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define SCP_MAGIC 0xFDFD
+
+CScp::CScp() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp constructed: %p\n", this );
+ #endif
+}
+
+CScp::~CScp()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp destructed: %p\n", this );
+ #endif
+}
+
+#ifndef __CDISK_NOLOAD__
+BOOL CScp::Load( char* szFname, BOOL, BOOL )
+{
+ WORD wMagic;
+ BYTE btSectorSize;
+ BYTE btTracks;
+ BYTE btSectorsPerTrack;
+
+ CFile cf;
+
+ if( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ wMagic = cf.readLEw();
+
+ if ( wMagic != SCP_MAGIC )
+ {
+ sprintf( m_szLastError, "SCP: File '%s' is not an SCP file!", szFname );
+ return FALSE;
+ }
+
+ btSectorSize = cf.readb();
+ btTracks = cf.readb();
+ btSectorsPerTrack = cf.readb();
+
+ int iSectorSize;
+
+ switch( btSectorSize )
+ {
+ case 0x80:
+ iSectorSize = 0x80;
+ break;
+
+ case 0x00:
+ iSectorSize = 0x100;
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "SCP: Invalid sector size: %02X", btSectorSize );
+ return FALSE;
+ }
+ }
+
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = btTracks;
+ dg.iSectorsPerTrack = btSectorsPerTrack;
+ dg.iBytesPerSector = iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE *pbtTable = new BYTE [ btSectorsPerTrack * btTracks ];
+
+ if ( ! pbtTable )
+ {
+ sprintf( m_szLastError, "SCP: Not enough memory for sector table!" );
+ return FALSE;
+ }
+
+ if ( !cf.Read( pbtTable, btSectorsPerTrack * btTracks ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't read sector table!" );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ BYTE* pbtPtr = pbtTable;
+
+ for( int iTrack = 0; iTrack < btTracks; iTrack++ )
+ {
+ for( int iSector = 0; iSector < btSectorsPerTrack; iSector++ )
+ {
+ if ( *pbtPtr )
+ {
+ int iNowRead;
+
+ if ( !iTrack && ( iSector < 3 ) )
+ iNowRead = 0x80;
+ else
+ iNowRead = iSectorSize;
+
+ int iReallyRead;
+
+ if ( !cf.Read( abtBuff, iNowRead, &iReallyRead ) || ( iNowRead != iReallyRead ) )
+ {
+ delete [] pbtTable;
+ sprintf( m_szLastError, "SCP: Image broken!" );
+ return FALSE;
+ }
+
+ if ( !WriteSector( *pbtPtr + iTrack* btSectorsPerTrack, abtBuff ) )
+ {
+ delete [] pbtTable;
+ return FALSE;
+ }
+
+ }
+ pbtPtr++;
+ }
+
+ }
+
+ delete [] pbtTable;
+
+ cf.Close();
+ return TRUE;
+
+}
+#endif
+
+#ifdef __CDISK_SAVE__
+
+BOOL CScp::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "SCP: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE btSize;
+ BYTE btTracks;
+ BYTE btSpT;
+
+ switch ( m_geometry.iBytesPerSector )
+ {
+ case 0x80:
+ btSize = 0x80;
+ break;
+
+ case 0x100:
+ default:
+ btSize = 0x00;
+ break;
+ }
+
+ BOOL bGood = FALSE;
+
+ btTracks = m_geometry.iTracks;
+ btSpT = m_geometry.iSectorsPerTrack;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 18 ) )
+ bGood = TRUE;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 26 ) )
+ bGood = TRUE;
+
+ if ( !bGood )
+ {
+ sprintf( m_szLastError, "SCP: Can't export, because of invalid disk size!" );
+ return FALSE;
+ }
+
+ int iMapSize = m_geometry.iTracks * m_geometry.iSectorsPerTrack;
+
+ BYTE* pMap = new BYTE [ iMapSize ];
+
+ if ( !pMap )
+ {
+ sprintf( m_szLastError, "SCP: Can't allocate memory for map!" );
+ return FALSE;
+ }
+
+ memset( pMap, 0, iMapSize );
+
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't create '%s'", szOutFile );
+ delete [] pMap;
+ return FALSE;
+ }
+
+ WORD wMagic = SCP_MAGIC;
+
+ cf.writeLEw( wMagic );
+ cf.writeb( btSize );
+ cf.writeb( btTracks );
+ cf.writeb( btSpT );
+
+ cf.Seek( iMapSize, SEEK_CUR );
+
+ BYTE abtBuff[ 0x100 ];
+
+ int iSectors = m_geometry.iSectors;
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i + 1 ) )
+ {
+ delete [] pMap;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ int iBytesNow = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ if ( !IsBlockEmpty( abtBuff, iBytesNow ) )
+ {
+ int iWritten;
+ if ( !cf.Write( abtBuff, iBytesNow, &iWritten ) || ( iBytesNow != iWritten ) )
+ {
+ sprintf( m_szLastError, "SCP: Error writing to '%s'", szOutFile );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ pMap[ i ] = ( i % btSpT ) + 1;
+ }
+ }
+
+ cf.Seek( 5, SEEK_SET );
+
+ if ( !cf.Write( pMap, iMapSize ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't write!" );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ delete [] pMap;
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_SAVE__
diff --git a/jindroush/lib/adsk_xfd.cpp b/jindroush/lib/adsk_xfd.cpp
new file mode 100644
index 0000000..870a59b
--- /dev/null
+++ b/jindroush/lib/adsk_xfd.cpp
@@ -0,0 +1,327 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "adsk_xfd.h"
+#include "autil.h"
+#include "cfile.h"
+
+CXfd::CXfd() : ADisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd constructed: %p\n", this );
+ #endif
+}
+
+CXfd::~CXfd()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd destructed: %p\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3
+} LOAD_VARIANT;
+
+#ifndef __CDISK_NOLOAD__
+BOOL CXfd::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ LONG lFileLen = cf.GetLength();
+
+ int iSecs;
+ int iSecSize;
+
+ if ( lFileLen % 0x80 )
+ {
+ sprintf( m_szLastError, "XFD: Strange length!" );
+ cf.Close();
+ return FALSE;
+ }
+
+ if ( ( lFileLen / 0x80 ) > 1040 )
+ {
+ iSecSize = 0x100;
+
+ iSecs = ( ( lFileLen - 0x180 ) / 0x100 ) + 3;
+ }
+ else
+ {
+ iSecSize = 0x80;
+ iSecs = lFileLen / 0x80;
+ }
+
+ if ( ( ( ( iSecs - 3 ) * iSecSize ) + 0x180 ) != lFileLen )
+ {
+ sprintf( m_szLastError, "XFD: Format violated: (%08lX != %08X)", lFileLen, iSecs * iSecSize );
+ m_iErrorCode = CXFD_FORMAT_VIOLATED;
+
+ #ifdef __CDISK_NOREPAIR__
+ cf.Close();
+ return FALSE;
+
+ #else
+ if ( !bRepair )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ else
+ {
+ iSecs = lFileLen / iSecSize;
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ if ( iMethod == 4 )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+ cf.Seek( 0, SEEK_SET );
+ }
+ #endif
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSecs, iSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSecs; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : iSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ if ( !WriteSector( i + 1, abtBuff ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+#endif
+
+
+#ifdef __CDISK_SAVE__
+
+BOOL CXfd::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "XFD: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i ) )
+ return FALSE;
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iWritten != iToWrite ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_SAVE__
diff --git a/jindroush/lib/at_dis.cpp b/jindroush/lib/at_dis.cpp
new file mode 100644
index 0000000..e799258
--- /dev/null
+++ b/jindroush/lib/at_dis.cpp
@@ -0,0 +1,1201 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "jintypes.h"
+#include "at_dis.h"
+
+struct
+{
+ char *instruct;
+ int length;
+ int branch;
+ int immed;
+ int write;
+} instable[] =
+{
+ { "BRK", 0, 0, 1, 0 }, //00
+ { "ORA\t(*,X)", 1, 0, 0, 0 }, //01
+ { "???", 0, 0, 1, 0 }, //02
+ { "???", 0, 0, 1, 0 }, //03
+ { "???", 0, 0, 1, 0 }, //04
+ { "ORA\t*", 1, 0, 0, 0 }, //05
+ { "ASL\t*", 1, 0, 0, 0 }, //06
+ { "???", 0, 0, 1, 0 }, //07
+ { "PHP", 0, 0, 1, 0 }, //08
+ { "ORA\t#*", 1, 0, 1, 0 }, //09
+ { "ASL", 0, 0, 1, 0 }, //0A
+ { "???", 0, 0, 1, 0 }, //0B
+ { "???", 0, 0, 1, 0 }, //0C
+ { "ORA\t*", 2, 0, 0, 0 }, //0D
+ { "ASL\t*", 2, 0, 0, 0 }, //0E
+ { "???", 0, 0, 1, 0 }, //0F
+ { "BPL\t$*", 1, 1, 1, 0 }, //10
+ { "ORA\t(*),Y", 1, 0, 0, 0 }, //11
+ { "???", 0, 0, 1, 0 }, //12
+ { "???", 0, 0, 1, 0 }, //13
+ { "???", 0, 0, 1, 0 }, //14
+ { "ORA\t*,X", 1, 0, 0, 0 }, //15
+ { "ASL\t*,X", 1, 0, 0, 0 }, //16
+ { "???", 0, 0, 1, 0 }, //17
+ { "CLC", 0, 0, 1, 0 }, //18
+ { "ORA\t*,Y", 2, 0, 0, 0 }, //19
+ { "???", 0, 0, 1, 0 }, //1A
+ { "???", 0, 0, 1, 0 }, //1B
+ { "???", 0, 0, 1, 0 }, //1C
+ { "ORA\t*,X", 2, 0, 0, 0 }, //1D
+ { "ASL\t*,X", 2, 0, 0, 0 }, //1E
+ { "???", 0, 0, 1, 0 }, //1F
+ { "JSR\t*", 2, 0, 0, 0 }, //20
+ { "AND\t(*,X)", 1, 0, 0, 0 }, //21
+ { "???", 0, 0, 1, 0 }, //22
+ { "???", 0, 0, 1, 0 }, //23
+ { "BIT\t*", 1, 0, 0, 0 }, //24
+ { "AND\t*", 1, 0, 0, 0 }, //25
+ { "ROL\t*", 1, 0, 0, 0 }, //26
+ { "???", 0, 0, 1, 0 }, //27
+ { "PLP", 0, 0, 1, 0 }, //28
+ { "AND\t#*", 1, 0, 1, 0 }, //29
+ { "ROL", 0, 0, 1, 0 }, //2A
+ { "???", 0, 0, 1, 0 }, //2B
+ { "BIT\t*", 2, 0, 0, 0 }, //2C
+ { "AND\t*", 2, 0, 0, 0 }, //2D
+ { "ROL\t*", 2, 0, 0, 0 }, //2E
+ { "???", 0, 0, 1, 0 }, //2F
+ { "BMI\t$*", 1, 1, 1, 0 }, //30
+ { "AND\t(*),Y", 1, 0, 0, 0 }, //31
+ { "???", 0, 0, 1, 0 }, //32
+ { "???", 0, 0, 1, 0 }, //33
+ { "???", 0, 0, 1, 0 }, //34
+ { "AND\t*,X", 1, 0, 0, 0 }, //35
+ { "ROL\t*,X", 1, 0, 0, 0 }, //36
+ { "???", 0, 0, 1, 0 }, //37
+ { "SEC", 0, 0, 1, 0 }, //38
+ { "AND\t*,Y", 2, 0, 0, 0 }, //39
+ { "???", 0, 0, 1, 0 }, //3A
+ { "???", 0, 0, 1, 0 }, //3B
+ { "???", 0, 0, 1, 0 }, //3C
+ { "AND\t*,X", 2, 0, 0, 0 }, //3D
+ { "ROL\t*,X", 2, 0, 0, 0 }, //3E
+ { "???", 0, 0, 1, 0 }, //3F
+ { "RTI", 0, 0, 1, 0 }, //40
+ { "EOR\t(*,X)", 1, 0, 0, 0 }, //41
+ { "???", 0, 0, 1, 0 }, //42
+ { "???", 0, 0, 1, 0 }, //43
+ { "???", 0, 0, 1, 0 }, //44
+ { "EOR\t*", 1, 0, 0, 0 }, //45
+ { "LSR\t*", 1, 0, 0, 0 }, //46
+ { "???", 0, 0, 1, 0 }, //47
+ { "PHA", 0, 0, 1, 0 }, //48
+ { "EOR\t#*", 1, 0, 1, 0 }, //49
+ { "LSR", 0, 0, 1, 0 }, //4A
+ { "???", 0, 0, 1, 0 }, //4B
+ { "JMP\t*", 2, 0, 0, 0 }, //4C
+ { "EOR\t*", 2, 0, 0, 0 }, //4D
+ { "LSR\t*", 2, 0, 0, 0 }, //4E
+ { "???", 0, 0, 1, 0 }, //4F
+ { "BVC\t$*", 1, 1, 1, 0 }, //50
+ { "EOR\t(*),Y", 1, 0, 0, 0 }, //51
+ { "???", 0, 0, 1, 0 }, //52
+ { "???", 0, 0, 1, 0 }, //53
+ { "???", 0, 0, 1, 0 }, //54
+ { "EOR\t*,X", 1, 0, 0, 0 }, //55
+ { "LSR\t*,X", 1, 0, 0, 0 }, //56
+ { "???", 0, 0, 1, 0 }, //57
+ { "CLI", 0, 0, 1, 0 }, //58
+ { "EOR\t*,Y", 2, 0, 0, 0 }, //59
+ { "???", 0, 0, 1, 0 }, //5A
+ { "???", 0, 0, 1, 0 }, //5B
+ { "???", 0, 0, 1, 0 }, //5C
+ { "EOR\t*,X", 2, 0, 0, 0 }, //5D
+ { "LSR\t*,X", 2, 0, 0, 0 }, //5E
+ { "???", 0, 0, 1, 0 }, //5F
+ { "RTS", 0, 0, 1, 0 }, //60
+ { "ADC\t(*,X)", 1, 0, 0, 0 }, //61
+ { "???", 0, 0, 1, 0 }, //62
+ { "???", 0, 0, 1, 0 }, //63
+ { "???", 0, 0, 1, 0 }, //64
+ { "ADC\t*", 1, 0, 0, 0 }, //65
+ { "ROR\t*", 1, 0, 0, 0 }, //66
+ { "???", 0, 0, 1, 0 }, //67
+ { "PLA", 0, 0, 1, 0 }, //68
+ { "ADC\t#*", 1, 0, 1, 0 }, //69
+ { "ROR", 0, 0, 1, 0 }, //6A
+ { "???", 0, 0, 1, 0 }, //6B
+ { "JMP\t(*)", 2, 0, 0, 0 }, //6C
+ { "ADC\t*", 2, 0, 0, 0 }, //6D
+ { "ROR\t*", 2, 0, 0, 0 }, //6E
+ { "???", 0, 0, 1, 0 }, //6F
+ { "BVS\t$*", 1, 1, 1, 0 }, //70
+ { "ADC\t(*),Y", 1, 0, 0, 0 }, //71
+ { "???", 0, 0, 1, 0 }, //72
+ { "???", 0, 0, 1, 0 }, //73
+ { "???", 0, 0, 1, 0 }, //74
+ { "ADC\t*,X", 1, 0, 0, 0 }, //75
+ { "ROR\t*,X", 1, 0, 0, 0 }, //76
+ { "???", 0, 0, 1, 0 }, //77
+ { "SEI", 0, 0, 1, 0 }, //78
+ { "ADC\t*,Y", 2, 0, 0, 0 }, //79
+ { "???", 0, 0, 1, 0 }, //7A
+ { "???", 0, 0, 1, 0 }, //7B
+ { "SKW", 1, 0, 1, 0 }, //7C
+ { "ADC\t*,X", 2, 0, 1, 0 }, //7D
+ { "ROR\t*,X", 2, 0, 1, 0 }, //7E
+ { "???", 0, 0, 1, 0 }, //7F
+ { "???", 0, 0, 1, 0 }, //80
+ { "STA\t(*,X)", 1, 0, 0, 1 }, //81
+ { "???", 0, 0, 1, 0 }, //82
+ { "???", 0, 0, 1, 0 }, //83
+ { "STY\t*", 1, 0, 0, 1 }, //84
+ { "STA\t*", 1, 0, 0, 1 }, //85
+ { "STX\t*", 1, 0, 0, 1 }, //86
+ { "???", 0, 0, 1, 0 }, //87
+ { "DEY", 0, 0, 1, 0 }, //88
+ { "???", 0, 0, 1, 0 }, //89
+ { "TXA", 0, 0, 1, 0 }, //8A
+ { "???", 0, 0, 1, 0 }, //8B
+ { "STY\t*", 2, 0, 0, 1 }, //8C
+ { "STA\t*", 2, 0, 0, 1 }, //8D
+ { "STX\t*", 2, 0, 0, 1 }, //8E
+ { "???", 0, 0, 1, 0 }, //8F
+ { "BCC\t$*", 1, 1, 1, 0 }, //90
+ { "STA\t(*),Y", 1, 0, 0, 1 }, //91
+ { "???", 0, 0, 1, 0 }, //92
+ { "???", 0, 0, 1, 0 }, //93
+ { "STY\t*,X", 1, 0, 0, 1 }, //94
+ { "STA\t*,X", 1, 0, 0, 1 }, //95
+ { "STX\t*,Y", 1, 0, 0, 1 }, //96
+ { "???", 0, 0, 1, 0 }, //97
+ { "TYA", 0, 0, 1, 0 }, //98
+ { "STA\t*,Y", 2, 0, 0, 1 }, //99
+ { "TXS", 0, 0, 1, 0 }, //9A
+ { "???", 0, 0, 1, 0 }, //9B
+ { "???", 0, 0, 1, 0 }, //9C
+ { "STA\t*,X", 2, 0, 0, 1 }, //9D
+ { "???", 0, 0, 1, 0 }, //9E
+ { "???", 0, 0, 1, 0 }, //9F
+ { "LDY\t#*", 1, 0, 1, 0 }, //A0
+ { "LDA\t(*,X)", 1, 0, 0, 0 }, //A1
+ { "LDX\t#*", 1, 0, 1, 0 }, //A2
+ { "???", 0, 0, 1, 0 }, //A3
+ { "LDY\t*", 1, 0, 0, 0 }, //A4
+ { "LDA\t*", 1, 0, 0, 0 }, //A5
+ { "LDX\t*", 1, 0, 0, 0 }, //A6
+ { "???", 0, 0, 1, 0 }, //A7
+ { "TAY", 0, 0, 1, 0 }, //A8
+ { "LDA\t#*", 1, 0, 1, 0 }, //A9
+ { "TAX", 0, 0, 1, 0 }, //AA
+ { "???", 0, 0, 1, 0 }, //AB
+ { "LDY\t*", 2, 0, 0, 0 }, //AC
+ { "LDA\t*", 2, 0, 0, 0 }, //AD
+ { "LDX\t*", 2, 0, 0, 0 }, //AE
+ { "???", 0, 0, 1, 0 }, //AF
+ { "BCS\t$*", 1, 1, 1, 0 }, //B0
+ { "LDA\t(*),Y", 1, 0, 0, 0 }, //B1
+ { "???", 0, 0, 1, 0 }, //B2
+ { "???", 0, 0, 1, 0 }, //B3
+ { "LDY\t*,X", 1, 0, 0, 0 }, //B4
+ { "LDA\t*,X", 1, 0, 0, 0 }, //B5
+ { "LDX\t*,Y", 1, 0, 0, 0 }, //B6
+ { "???", 0, 0, 1, 0 }, //B7
+ { "CLV", 0, 0, 1, 0 }, //B8
+ { "LDA\t*,Y", 2, 0, 0, 0 }, //B9
+ { "TSX", 0, 0, 1, 0 }, //BA
+ { "???", 0, 0, 1, 0 }, //BB
+ { "LDY\t*,X", 2, 0, 0, 0 }, //BC
+ { "LDA\t*,X", 2, 0, 0, 0 }, //BD
+ { "LDX\t*,Y", 2, 0, 0, 0 }, //BE
+ { "???", 0, 0, 1, 0 }, //BF
+ { "CPY\t#*", 1, 0, 1, 0 }, //C0
+ { "CMP\t(*,X)", 1, 0, 0, 0 }, //C1
+ { "???", 0, 0, 1, 0 }, //C2
+ { "???", 0, 0, 1, 0 }, //C3
+ { "CPY\t*", 1, 0, 0, 0 }, //C4
+ { "CMP\t*", 1, 0, 0, 0 }, //C5
+ { "DEC\t*", 1, 0, 0, 0 }, //C6
+ { "???", 0, 0, 1, 0 }, //C7
+ { "INY", 0, 0, 1, 0 }, //C8
+ { "CMP\t#*", 1, 0, 1, 0 }, //C9
+ { "DEX", 0, 0, 1, 0 }, //CA
+ { "???", 0, 0, 1, 0 }, //CB
+ { "CPY\t*", 2, 0, 0, 0 }, //CC
+ { "CMP\t*", 2, 0, 0, 0 }, //CD
+ { "DEC\t*", 2, 0, 0, 0 }, //CE
+ { "???", 0, 0, 1, 0 }, //CF
+ { "BNE\t$*", 1, 1, 1, 0 }, //D0
+ { "CMP\t(*),Y", 1, 0, 0, 0 }, //D1
+ { "???", 0, 0, 1, 0 }, //D2
+ { "???", 0, 0, 1, 0 }, //D3
+ { "???", 0, 0, 1, 0 }, //D4
+ { "CMP\t*,X", 1, 0, 0, 0 }, //D5
+ { "DEC\t*,X", 1, 0, 0, 0 }, //D6
+ { "???", 0, 0, 1, 0 }, //D7
+ { "CLD", 0, 0, 1, 0 }, //D8
+ { "CMP\t*,Y", 2, 0, 0, 0 }, //D9
+ { "???", 0, 0, 1, 0 }, //DA
+ { "???", 0, 0, 1, 0 }, //DB
+ { "???", 0, 0, 1, 0 }, //DC
+ { "CMP\t*,X", 2, 0, 0, 0 }, //DD
+ { "DEC\t*,X", 2, 0, 0, 0 }, //DE
+ { "???", 0, 0, 1, 0 }, //DF
+ { "CPX\t#*", 1, 0, 1, 0 }, //E0
+ { "SBC\t(*,X)", 1, 0, 0, 0 }, //E1
+ { "???", 0, 0, 1, 0 }, //E2
+ { "???", 0, 0, 1, 0 }, //E3
+ { "CPX\t*", 1, 0, 0, 0 }, //E4
+ { "SBC\t*", 1, 0, 0, 0 }, //E5
+ { "INC\t*", 1, 0, 0, 0 }, //E6
+ { "???", 0, 0, 1, 0 }, //E7
+ { "INX", 0, 0, 1, 0 }, //E8
+ { "SBC\t#*", 1, 0, 1, 0 }, //E9
+ { "NOP", 0, 0, 1, 0 }, //EA
+ { "???", 0, 0, 1, 0 }, //EB
+ { "CPX\t*", 2, 0, 0, 0 }, //EC
+ { "SBC\t*", 2, 0, 0, 0 }, //ED
+ { "INC\t*", 2, 0, 0, 0 }, //EE
+ { "???", 0, 0, 1, 0 }, //EF
+ { "BEQ\t$*", 1, 1, 1, 0 }, //F0
+ { "SBC\t(*),Y", 1, 0, 0, 0 }, //F1
+ { "???", 0, 0, 1, 0 }, //F2
+ { "???", 0, 0, 1, 0 }, //F3
+ { "???", 0, 0, 1, 0 }, //F4
+ { "SBC\t*,X", 1, 0, 0, 0 }, //F5
+ { "INC\t*,X", 1, 0, 0, 0 }, //F6
+ { "???", 0, 0, 1, 0 }, //F7
+ { "SED", 0, 0, 1, 0 }, //F8
+ { "SBC\t*,Y", 2, 0, 0, 0 }, //F9
+ { "???", 0, 0, 1, 0 }, //FA
+ { "???", 0, 0, 1, 0 }, //FB
+ { "???", 0, 0, 1, 0 }, //FC
+ { "SBC\t*,X", 2, 0, 0, 0 }, //FD
+ { "INC\t*,X", 2, 0, 0, 0 }, //FE
+ { "???", 0, 0, 1, 0 }, //FF
+ { "\0", 0, 0, 1, 0 }
+};
+
+typedef struct
+{
+ char* name;
+ WORD addr;
+} symtable_rec;
+
+symtable_rec symtable[] = {
+ { "NGFLAG", 0x0001 },
+ { "CASINI", 0x0002 },
+ { "CASINI+1", 0x0003 },
+ { "RAMLO", 0x0004 },
+ { "RAMLO+1", 0x0005 },
+ { "TRAMSZ", 0x0006 },
+ { "CMCMD", 0x0007 },
+ { "WARMST", 0x0008 },
+ { "BOOT", 0x0009 },
+ { "DOSVEC", 0x000A },
+ { "DOSVEC+1", 0x000B },
+ { "DOSINI", 0x000C },
+ { "DOSINI+1", 0x000D },
+ { "APPMHI", 0x000E },
+ { "APPMHI+1", 0x000F },
+ { "POKMSK", 0x0010 },
+ { "BRKKEY", 0x0011 },
+ { "RTCLOK", 0x0012 },
+ { "RTCLOK+1", 0x0013 },
+ { "RTCLOK+2", 0x0014 },
+ { "BUFADR", 0x0015 },
+ { "BUFADR+1", 0x0016 },
+ { "ICCOMT", 0x0017 },
+ { "DSKFMS", 0x0018 },
+ { "DSKFMS+1", 0x0019 },
+ { "DSKUTL", 0x001A },
+ { "DSKUTL+1", 0x001B },
+ { "ABUFPT", 0x001C },
+ { "ABUFPT+1", 0x001D },
+ { "ABUFPT+2", 0x001E },
+ { "ABUFPT+3", 0x001F },
+ { "ICHIDZ", 0x0020 },
+ { "ICDNOZ", 0x0021 },
+ { "ICCOMZ", 0x0022 },
+ { "ICSTAZ", 0x0023 },
+ { "ICBALZ", 0x0024 },
+ { "ICBAHZ", 0x0025 },
+ { "ICPTLZ", 0x0026 },
+ { "ICPTHZ", 0x0027 },
+ { "ICBLLZ", 0x0028 },
+ { "ICBLHZ", 0x0029 },
+ { "ICAX1Z", 0x002A },
+ { "ICAX2Z", 0x002B },
+ { "ICAX3Z", 0x002C },
+ { "ICAX4Z", 0x002D },
+ { "ICAX5Z", 0x002E },
+ { "ICAX6Z", 0x002F },
+ { "STATUS", 0x0030 },
+ { "CHKSUM", 0x0031 },
+ { "BUFRLO", 0x0032 },
+ { "BUFRHI", 0x0033 },
+ { "BFENLO", 0x0034 },
+ { "BFENHI", 0x0035 },
+ { "LTEMP", 0x0036 },
+ { "LTEMP+1", 0x0037 },
+ { "BUFRFL", 0x0038 },
+ { "RECVDN", 0x0039 },
+ { "XMTDON", 0x003A },
+ { "CHKSNT", 0x003B },
+ { "NOCKSM", 0x003C },
+ { "BPTR", 0x003D },
+ { "FTYPE", 0x003E },
+ { "FEOF", 0x003F },
+ { "FREQ", 0x0040 },
+ { "SOUNDR", 0x0041 },
+ { "CRITIC", 0x0042 },
+ { "FMSZPG", 0x0043 },
+ { "FMSZPG+1", 0x0044 },
+ { "FMSZPG+2", 0x0045 },
+ { "FMSZPG+3", 0x0046 },
+ { "FMSZPG+4", 0x0047 },
+ { "FMSZPG+5", 0x0048 },
+ { "FMSZPG+6", 0x0049 },
+ { "ZCHAIN", 0x004A },
+ { "ZCHAIN+1", 0x004B },
+ { "DSTAT", 0x004C },
+ { "ATRACT", 0x004D },
+ { "DRKMSK", 0x004E },
+ { "COLRSH", 0x004F },
+ { "TEMP", 0x0050 },
+ { "HOLD1", 0x0051 },
+ { "LMARGN", 0x0052 },
+ { "RMARGN", 0x0053 },
+ { "ROWCRS", 0x0054 },
+ { "COLCRS", 0x0055 },
+ { "COLCRS+1", 0x0056 },
+ { "DINDEX", 0x0057 },
+ { "SAVMSC", 0x0058 },
+ { "SAVMSC+1", 0x0059 },
+ { "OLDROW", 0x005A },
+ { "OLDCOL", 0x005B },
+ { "OLDCOL+1", 0x005C },
+ { "OLDCHR", 0x005D },
+ { "OLDADR", 0x005E },
+ { "OLDADR+1", 0x005F },
+ { "FKDEF", 0x0060 },
+ { "FKDEF+1", 0x0061 },
+ { "PALNTS", 0x0062 },
+ { "LOGCOL", 0x0063 },
+ { "ADRESS", 0x0064 },
+ { "ADRESS+1", 0x0065 },
+ { "MLTTMP", 0x0066 },
+ { "MLTTMP+1", 0x0067 },
+ { "SAVADR", 0x0068 },
+ { "SAVADR+1", 0x0069 },
+ { "RAMTOP", 0x006A },
+ { "BUFCNT", 0x006B },
+ { "BUFSTR", 0x006C },
+ { "BUFSTR+1", 0x006D },
+ { "BITMSK", 0x006E },
+ { "SHFAMT", 0x006F },
+ { "ROWAC", 0x0070 },
+ { "ROWAC+1", 0x0071 },
+ { "COLAC", 0x0072 },
+ { "COLAC+1", 0x0073 },
+ { "ENDPT", 0x0074 },
+ { "ENDPT+1", 0x0075 },
+ { "DELTAR", 0x0076 },
+ { "DELTAC", 0x0077 },
+ { "DELTAC+1", 0x0078 },
+ { "KEYDEF", 0x0079 },
+ { "KEYDEF+1", 0x007A },
+ { "SWPFLG", 0x007B },
+ { "HOLDCH", 0x007C },
+ { "INSDAT", 0x007D },
+ { "COUNTR", 0x007E },
+ { "COUNTR+1", 0x007F },
+ { "LOMEM", 0x0080 },
+ { "LOMEM+1", 0x0081 },
+ { "VNTP", 0x0082 },
+ { "VNTP+1", 0x0083 },
+ { "VNTD", 0x0084 },
+ { "VNTD+1", 0x0085 },
+ { "VVTP", 0x0086 },
+ { "VVTP+1", 0x0087 },
+ { "STMTAB", 0x0088 },
+ { "STMTAB+1", 0x0089 },
+ { "STMCUR", 0x008A },
+ { "STMCUR+1", 0x008B },
+ { "STARP", 0x008C },
+ { "STARP+1", 0x008D },
+ { "RUNSTK", 0x008E },
+ { "RUNSTK+1", 0x008F },
+ { "TOPSTK", 0x0090 },
+ { "TOPSTK+1", 0x0091 },
+ { "MEOLFLG", 0x0092 },
+ { "POKADR", 0x0095 },
+ { "POKADR+1", 0x0096 },
+ { "DATAD", 0x00B6 },
+ { "DATALN", 0x00B7 },
+ { "DATALN+1", 0x00B8 },
+ { "STOPLN", 0x00BA },
+ { "STOPLN+1", 0x00BB },
+ { "SAVCUR", 0x00BE },
+ { "IOCMD", 0x00C0 },
+ { "IODVC", 0x00C1 },
+ { "PROMPT", 0x00C2 },
+ { "ERRSAVE", 0x00C3 },
+ { "COLOUR", 0x00C8 },
+ { "PTABW", 0x00C9 },
+ { "LOADFLG", 0x00CA },
+ { "FR0", 0x00D4 },
+ { "FR0+1", 0x00D5 },
+ { "FR0+2", 0x00D6 },
+ { "FR0+3", 0x00D7 },
+ { "FR0+4", 0x00D8 },
+ { "FR0+5", 0x00D9 },
+ { "FRE", 0x00DA },
+ { "FRE+1", 0x00DB },
+ { "FRE+2", 0x00DC },
+ { "FRE+3", 0x00DD },
+ { "FRE+4", 0x00DE },
+ { "FRE+5", 0x00DF },
+ { "FR1", 0x00E0 },
+ { "FR1+1", 0x00E1 },
+ { "FR1+2", 0x00E2 },
+ { "FR1+3", 0x00E3 },
+ { "FR1+4", 0x00E4 },
+ { "FR1+5", 0x00E5 },
+ { "FR2", 0x00E6 },
+ { "FR2+1", 0x00E7 },
+ { "FR2+2", 0x00E8 },
+ { "FR2+3", 0x00E9 },
+ { "FR2+4", 0x00EA },
+ { "FR2+5", 0x00EB },
+ { "FRX", 0x00EC },
+ { "EEXP", 0x00ED },
+ { "NSIGN", 0x00EE },
+ { "ESIGN", 0x00EF },
+ { "FCHRFLG", 0x00F0 },
+ { "DIGRT", 0x00F1 },
+ { "CIX", 0x00F2 },
+ { "INBUFF", 0x00F3 },
+ { "INBUFF+1", 0x00F4 },
+ { "ZTEMP1", 0x00F5 },
+ { "ZTEMP1+1", 0x00F6 },
+ { "ZTEMP4", 0x00F7 },
+ { "ZTEMP4+1", 0x00F8 },
+ { "ZTEMP3", 0x00F9 },
+ { "ZTEMP3+1", 0x00FA },
+ { "RADFLG", 0x00FB },
+ { "FLPTR", 0x00FC },
+ { "FLPTR+1", 0x00FD },
+ { "FPTR2", 0x00FE },
+ { "FPTR2+1", 0x00FF },
+
+ { "VDSLST", 0x0200 },
+ { "VDSLST+1", 0x0201 },
+ { "VPRCED", 0x0202 },
+ { "VPRCED+1", 0x0203 },
+ { "VINTER", 0x0204 },
+ { "VINTER+1", 0x0205 },
+ { "VBREAK", 0x0206 },
+ { "VBREAK+1", 0x0207 },
+ { "VKEYBD", 0x0208 },
+ { "VKEYBD+1", 0x0209 },
+ { "VSERIN", 0x020A },
+ { "VSERIN+1", 0x020B },
+ { "VSEROR", 0x020C },
+ { "VSEROR+1", 0x020D },
+ { "VSEROC", 0x020E },
+ { "VSEROC+1", 0x020F },
+ { "VTIMR1", 0x0210 },
+ { "VTIMR1+1", 0x0211 },
+ { "VTIMR2", 0x0212 },
+ { "VTIMR2+1", 0x0213 },
+ { "VTIMR4", 0x0214 },
+ { "VTIMR4+1", 0x0215 },
+ { "VIMIRQ", 0x0216 },
+ { "VIMIRQ+1", 0x0217 },
+ { "CDTMV1", 0x0218 },
+ { "CDTMV1+1", 0x0219 },
+ { "CDTMV2", 0x021A },
+ { "CDTMV2+1", 0x021B },
+ { "CDTMV3", 0x021C },
+ { "CDTMV3+1", 0x021D },
+ { "CDTMV4", 0x021E },
+ { "CDTMV4+1", 0x021F },
+ { "CDTMV5", 0x0220 },
+ { "CDTMV5+1", 0x0221 },
+ { "VVBLKI", 0x0222 },
+ { "VVBLKI+1", 0x0223 },
+ { "VVBLKD", 0x0224 },
+ { "VVBLKD+1", 0x0225 },
+ { "CDTMA1", 0x0226 },
+ { "CDTMA1+1", 0x0227 },
+ { "CDTMA2", 0x0228 },
+ { "CDTMA2+1", 0x0229 },
+ { "CDTMF3", 0x022A },
+ { "SRTIMR", 0x022B },
+ { "CDTMF4", 0x022C },
+ { "INTEMP", 0x022D },
+ { "CDTMF5", 0x022E },
+ { "SDMCTL", 0x022F },
+ { "SDLSTL", 0x0230 },
+ { "SDLSTH", 0x0231 },
+ { "SSKCTL", 0x0232 },
+ { "SPARE", 0x0233 },
+ { "LPENH", 0x0234 },
+ { "LPENV", 0x0235 },
+ { "BRKKY", 0x0236 },
+ { "BRKKY+1", 0x0237 },
+ { "VPIRQ", 0x0238 },
+ { "VPIRQ+1", 0x0239 },
+ { "CDEVIC", 0x023A },
+ { "CCOMND", 0x023B },
+ { "CAUX1", 0x023C },
+ { "CAUX2", 0x023D },
+ { "TMPSIO", 0x023E },
+ { "ERRFLG", 0x023F },
+ { "DFLAGS", 0x0240 },
+ { "DBSECT", 0x0241 },
+ { "BOOTAD", 0x0242 },
+ { "BOOTAD+1", 0x0243 },
+ { "COLDST", 0x0244 },
+ { "RECLEN", 0x0245 },
+ { "DSKTIM", 0x0246 },
+ { "PDVMSK", 0x0247 },
+ { "SHPDVS", 0x0248 },
+ { "PDMSK", 0x0249 },
+ { "RELADR", 0x024A },
+ { "RELADR+1", 0x024B },
+ { "PPTMPA", 0x024C },
+ { "PPTMPX", 0x024D },
+ { "CHSALT", 0x026B },
+ { "VSFLAG", 0x026C },
+ { "KEYDIS", 0x026D },
+ { "FINE", 0x026E },
+ { "GPRIOR", 0x026F },
+ { "PADDL0", 0x0270 },
+ { "PADDL1", 0x0271 },
+ { "PADDL2", 0x0272 },
+ { "PADDL3", 0x0273 },
+ { "PADDL4", 0x0274 },
+ { "PADDL5", 0x0275 },
+ { "PADDL6", 0x0276 },
+ { "PADDL7", 0x0277 },
+ { "STICK0", 0x0278 },
+ { "STICK1", 0x0279 },
+ { "STICK2", 0x027A },
+ { "STICK3", 0x027B },
+ { "PTRIG0", 0x027C },
+ { "PTRIG1", 0x027D },
+ { "PTRIG2", 0x027E },
+ { "PTRIG3", 0x027F },
+ { "PTRIG4", 0x0280 },
+ { "PTRIG5", 0x0281 },
+ { "PTRIG6", 0x0282 },
+ { "PTRIG7", 0x0283 },
+ { "STRIG0", 0x0284 },
+ { "STRIG1", 0x0285 },
+ { "STRIG2", 0x0286 },
+ { "STRIG3", 0x0287 },
+ { "HIBYTE", 0x0288 },
+ { "WMODE", 0x0289 },
+ { "BLIM", 0x028A },
+ { "IMASK", 0x028B },
+ { "JVECK", 0x028C },
+ { "NEWADR", 0x028E },
+ { "TXTROW", 0x0290 },
+ { "TXTCOL", 0x0291 },
+ { "TXTCOL+1", 0x0292 },
+ { "TINDEX", 0x0293 },
+ { "TXTMSC", 0x0294 },
+ { "TXTMSC+1", 0x0295 },
+ { "TXTOLD", 0x0296 },
+ { "TXTOLD+1", 0x0297 },
+ { "TXTOLD+2", 0x0298 },
+ { "TXTOLD+3", 0x0299 },
+ { "TXTOLD+4", 0x029A },
+ { "TXTOLD+5", 0x029B },
+ { "CRETRY", 0x029C },
+ { "HOLD3", 0x029D },
+ { "SUBTMP", 0x029E },
+ { "HOLD2", 0x029F },
+ { "DMASK", 0x02A0 },
+ { "TMPLBT", 0x02A1 },
+ { "ESCFLG", 0x02A2 },
+ { "TABMAP", 0x02A3 },
+ { "TABMAP+1", 0x02A4 },
+ { "TABMAP+2", 0x02A5 },
+ { "TABMAP+3", 0x02A6 },
+ { "TABMAP+4", 0x02A7 },
+ { "TABMAP+5", 0x02A8 },
+ { "TABMAP+6", 0x02A9 },
+ { "TABMAP+7", 0x02AA },
+ { "TABMAP+8", 0x02AB },
+ { "TABMAP+9", 0x02AC },
+ { "TABMAP+A", 0x02AD },
+ { "TABMAP+B", 0x02AE },
+ { "TABMAP+C", 0x02AF },
+ { "TABMAP+D", 0x02B0 },
+ { "TABMAP+E", 0x02B1 },
+ { "LOGMAP", 0x02B2 },
+ { "LOGMAP+1", 0x02B3 },
+ { "LOGMAP+2", 0x02B4 },
+ { "LOGMAP+3", 0x02B5 },
+ { "INVFLG", 0x02B6 },
+ { "FILFLG", 0x02B7 },
+ { "TMPROW", 0x02B8 },
+ { "TMPCOL", 0x02B9 },
+ { "TMPCOL+1", 0x02BA },
+ { "SCRFLG", 0x02BB },
+ { "HOLD4", 0x02BC },
+ { "DRETRY", 0x02BD },
+ { "SHFLOC", 0x02BE },
+ { "BOTSCR", 0x02BF },
+ { "PCOLR0", 0x02C0 },
+ { "PCOLR1", 0x02C1 },
+ { "PCOLR2", 0x02C2 },
+ { "PCOLR3", 0x02C3 },
+ { "COLOR0", 0x02C4 },
+ { "COLOR1", 0x02C5 },
+ { "COLOR2", 0x02C6 },
+ { "COLOR3", 0x02C7 },
+ { "COLOR4", 0x02C8 },
+ { "RUNADR", 0x02C9 },
+ { "RUNADR+1", 0x02CA },
+ { "HIUSED", 0x02CB },
+ { "HIUSED+1", 0x02CC },
+ { "ZHIUSE", 0x02CD },
+ { "ZHIUSE+1", 0x02CE },
+ { "GBYTEA", 0x02CF },
+ { "GBYTEA+1", 0x02D0 },
+ { "LOADAD", 0x02D1 },
+ { "LOADAD+1", 0x02D2 },
+ { "ZLOADA", 0x02D3 },
+ { "ZLOADA+1", 0x02D4 },
+ { "DSCTLN", 0x02D5 },
+ { "DSCTLN+1", 0x02D6 },
+ { "ACMISR", 0x02D7 },
+ { "ACMISR+1", 0x02D8 },
+ { "KRPDER", 0x02D9 },
+ { "KEYREP", 0x02DA },
+ { "NOCLIK", 0x02DB },
+ { "HELPFG", 0x02DC },
+ { "DMASAV", 0x02DD },
+ { "PBPNT", 0x02DE },
+ { "PBUFSZ", 0x02DF },
+ { "RUNAD", 0x02E0 },
+ { "RUNAD+1", 0x02E1 },
+ { "INITAD", 0x02E2 },
+ { "INITAD+1", 0x02E3 },
+ { "RAMSIZ", 0x02E4 },
+ { "MEMTOP", 0x02E5 },
+ { "MEMTOP+1", 0x02E6 },
+ { "MEMLO", 0x02E7 },
+ { "MEMLO+1", 0x02E8 },
+ { "HNDLOD", 0x02E9 },
+ { "DVSTAT", 0x02EA },
+ { "DVSTAT+1", 0x02EB },
+ { "DVSTAT+2", 0x02EC },
+ { "DVSTAT+3", 0x02ED },
+ { "CBAUDL", 0x02EE },
+ { "CBAUDH", 0x02EF },
+ { "CRSINH", 0x02F0 },
+ { "KEYDEL", 0x02F1 },
+ { "CH1", 0x02F2 },
+ { "CHACT", 0x02F3 },
+ { "CHBAS", 0x02F4 },
+ { "NEWROW", 0x02F5 },
+ { "NEWCOL", 0x02F6 },
+ { "NEWCOL+1", 0x02F7 },
+ { "ROWINC", 0x02F8 },
+ { "COLINC", 0x02F9 },
+ { "CHAR", 0x02FA },
+ { "ATACHR", 0x02FB },
+ { "CH", 0x02FC },
+ { "FILDAT", 0x02FD },
+ { "DSPFLG", 0x02FE },
+ { "SSFLAG", 0x02FF },
+
+
+ { "DDEVIC", 0x0300 },
+ { "DUNIT", 0x0301 },
+ { "DCOMND", 0x0302 },
+ { "DSTATS", 0x0303 },
+ { "DBUFLO", 0x0304 },
+ { "DBUFHI", 0x0305 },
+ { "DTIMLO", 0x0306 },
+ { "DUNUSE", 0x0307 },
+ { "DBYTLO", 0x0308 },
+ { "DBYTHI", 0x0309 },
+ { "DAUX1", 0x030A },
+ { "DAUX2", 0x030B },
+ { "TIMER1", 0x030C },
+ { "TIMER1+1", 0x030D },
+ { "ADDCOR", 0x030E },
+ { "CASFLG", 0x030F },
+ { "TIMER2", 0x0310 },
+ { "TIMER2+1", 0x0311 },
+ { "TEMP1", 0x0312 },
+ { "TEMP1+1", 0x0313 },
+ { "TEMP2", 0x0314 },
+ { "TEMP3", 0x0315 },
+ { "SAVIO", 0x0316 },
+ { "TIMFLG", 0x0317 },
+ { "STACKP", 0x0318 },
+ { "TSTAT", 0x0319 },
+ { "HATABS", 0x031A }, /*HATABS 1-34*/
+ { "PUTBT1", 0x033D },
+ { "PUTBT2", 0x033E },
+ { "PUTBT3", 0x033F },
+ { "B0-ICHID", 0x0340 },
+ { "B0-ICDNO", 0x0341 },
+ { "B0-ICCOM", 0x0342 },
+ { "B0-ICSTA", 0x0343 },
+ { "B0-ICBAL", 0x0344 },
+ { "B0-ICBAH", 0x0345 },
+ { "B0-ICPTL", 0x0346 },
+ { "B0-ICPTH", 0x0347 },
+ { "B0-ICBLL", 0x0348 },
+ { "B0-ICBLH", 0x0349 },
+ { "B0-ICAX1", 0x034A },
+ { "B0-ICAX2", 0x034B },
+ { "B0-ICAX3", 0x034C },
+ { "B0-ICAX4", 0x034D },
+ { "B0-ICAX5", 0x034E },
+ { "B0-ICAX6", 0x034F },
+ { "B1-ICHID", 0x0350 },
+ { "B1-ICDNO", 0x0351 },
+ { "B1-ICCOM", 0x0352 },
+ { "B1-ICSTA", 0x0353 },
+ { "B1-ICBAL", 0x0354 },
+ { "B1-ICBAH", 0x0355 },
+ { "B1-ICPTL", 0x0356 },
+ { "B1-ICPTH", 0x0357 },
+ { "B1-ICBLL", 0x0358 },
+ { "B1-ICBLH", 0x0359 },
+ { "B1-ICAX1", 0x035A },
+ { "B1-ICAX2", 0x035B },
+ { "B1-ICAX3", 0x035C },
+ { "B1-ICAX4", 0x035D },
+ { "B1-ICAX5", 0x035E },
+ { "B1-ICAX6", 0x035F },
+ { "B2-ICHID", 0x0360 },
+ { "B2-ICDNO", 0x0361 },
+ { "B2-ICCOM", 0x0362 },
+ { "B2-ICSTA", 0x0363 },
+ { "B2-ICBAL", 0x0364 },
+ { "B2-ICBAH", 0x0365 },
+ { "B2-ICPTL", 0x0366 },
+ { "B2-ICPTH", 0x0367 },
+ { "B2-ICBLL", 0x0368 },
+ { "B2-ICBLH", 0x0369 },
+ { "B2-ICAX1", 0x036A },
+ { "B2-ICAX2", 0x036B },
+ { "B2-ICAX3", 0x036C },
+ { "B2-ICAX4", 0x036D },
+ { "B2-ICAX5", 0x036E },
+ { "B2-ICAX6", 0x036F },
+ { "B3-ICHID", 0x0370 },
+ { "B3-ICDNO", 0x0371 },
+ { "B3-ICCOM", 0x0372 },
+ { "B3-ICSTA", 0x0373 },
+ { "B3-ICBAL", 0x0374 },
+ { "B3-ICBAH", 0x0375 },
+ { "B3-ICPTL", 0x0376 },
+ { "B3-ICPTH", 0x0377 },
+ { "B3-ICBLL", 0x0378 },
+ { "B3-ICBLH", 0x0379 },
+ { "B3-ICAX1", 0x037A },
+ { "B3-ICAX2", 0x037B },
+ { "B3-ICAX3", 0x037C },
+ { "B3-ICAX4", 0x037D },
+ { "B3-ICAX5", 0x037E },
+ { "B3-ICAX6", 0x037F },
+ { "B4-ICHID", 0x0380 },
+ { "B4-ICDNO", 0x0381 },
+ { "B4-ICCOM", 0x0382 },
+ { "B4-ICSTA", 0x0383 },
+ { "B4-ICBAL", 0x0384 },
+ { "B4-ICBAH", 0x0385 },
+ { "B4-ICPTL", 0x0386 },
+ { "B4-ICPTH", 0x0387 },
+ { "B4-ICBLL", 0x0388 },
+ { "B4-ICBLH", 0x0389 },
+ { "B4-ICAX1", 0x038A },
+ { "B4-ICAX2", 0x038B },
+ { "B4-ICAX3", 0x038C },
+ { "B4-ICAX4", 0x038D },
+ { "B4-ICAX5", 0x038E },
+ { "B4-ICAX6", 0x038F },
+ { "B5-ICHID", 0x0390 },
+ { "B5-ICDNO", 0x0391 },
+ { "B5-ICCOM", 0x0392 },
+ { "B5-ICSTA", 0x0393 },
+ { "B5-ICBAL", 0x0394 },
+ { "B5-ICBAH", 0x0395 },
+ { "B5-ICPTL", 0x0396 },
+ { "B5-ICPTH", 0x0397 },
+ { "B5-ICBLL", 0x0398 },
+ { "B5-ICBLH", 0x0399 },
+ { "B5-ICAX1", 0x039A },
+ { "B5-ICAX2", 0x039B },
+ { "B5-ICAX3", 0x039C },
+ { "B5-ICAX4", 0x039D },
+ { "B5-ICAX5", 0x039E },
+ { "B5-ICAX6", 0x039F },
+ { "B6-ICHID", 0x03A0 },
+ { "B6-ICDNO", 0x03A1 },
+ { "B6-ICCOM", 0x03A2 },
+ { "B6-ICSTA", 0x03A3 },
+ { "B6-ICBAL", 0x03A4 },
+ { "B6-ICBAH", 0x03A5 },
+ { "B6-ICPTL", 0x03A6 },
+ { "B6-ICPTH", 0x03A7 },
+ { "B6-ICBLL", 0x03A8 },
+ { "B6-ICBLH", 0x03A9 },
+ { "B6-ICAX1", 0x03AA },
+ { "B6-ICAX2", 0x03AB },
+ { "B6-ICAX3", 0x03AC },
+ { "B6-ICAX4", 0x03AD },
+ { "B6-ICAX5", 0x03AE },
+ { "B6-ICAX6", 0x03AF },
+ { "B7-ICHID", 0x03B0 },
+ { "B7-ICDNO", 0x03B1 },
+ { "B7-ICCOM", 0x03B2 },
+ { "B7-ICSTA", 0x03B3 },
+ { "B7-ICBAL", 0x03B4 },
+ { "B7-ICBAH", 0x03B5 },
+ { "B7-ICPTL", 0x03B6 },
+ { "B7-ICPTH", 0x03B7 },
+ { "B7-ICBLL", 0x03B8 },
+ { "B7-ICBLH", 0x03B9 },
+ { "B7-ICAX1", 0x03BA },
+ { "B7-ICAX2", 0x03BB },
+ { "B7-ICAX3", 0x03BC },
+ { "B7-ICAX4", 0x03BD },
+ { "B7-ICAX5", 0x03BE },
+ { "B7-ICAX6", 0x03BF },
+ { "PRNBUF", 0x03C0 }, /*PRNBUF 1-39 */
+ { "SUPERF", 0x03E8 },
+ { "CKEY", 0x03E9 },
+ { "CASSBT", 0x03EA },
+ { "CARTCK", 0x03EB },
+ { "DERRF", 0x03EC },
+ { "ACMVAR", 0x03ED }, /*ACMVAR 1-10*/
+ { "BASICF", 0x03F8 },
+ { "MINTLK", 0x03F9 },
+ { "GINTLK", 0x03FA },
+ { "CHLINK", 0x03FB },
+ { "CHLINK+1", 0x03FC },
+ { "CASBUF", 0x03FD },
+
+ { "M0PF", 0xD000 },
+ { "HPOSP0", 0xD000 },
+ { "M1PF", 0xD001 },
+ { "HPOSP1", 0xD001 },
+ { "M2PF", 0xD002 },
+ { "HPOSP2", 0xD002 },
+ { "M3PF", 0xD003 },
+ { "HPOSP3", 0xD003 },
+ { "P0PF", 0xD004 },
+ { "HPOSM0", 0xD004 },
+ { "P1PF", 0xD005 },
+ { "HPOSM1", 0xD005 },
+ { "P2PF", 0xD006 },
+ { "HPOSM2", 0xD006 },
+ { "P3PF", 0xD007 },
+ { "HPOSM3", 0xD007 },
+ { "M0PL", 0xD008 },
+ { "SIZEP0", 0xD008 },
+ { "M1PL", 0xD009 },
+ { "SIZEP1", 0xD009 },
+ { "M2PL", 0xD00A },
+ { "HPOSP2", 0xD00A },
+ { "M3PL", 0xD00B },
+ { "HPOSP3", 0xD00B },
+ { "P0PL", 0xD00C },
+ { "SIZEM", 0xD00C },
+ { "P1PL", 0xD00D },
+ { "GRAFP0", 0xD00D },
+ { "P2PL", 0xD00E },
+ { "GRAFP1", 0xD00E },
+ { "P3PL", 0xD00F },
+ { "GRAFP2", 0xD00F },
+ { "TRIG0", 0xD010 },
+ { "GRAFP3", 0xD010 },
+ { "TRIG1", 0xD011 },
+ { "GRAFM", 0xD011 },
+ { "TRIG2", 0xD012 },
+ { "COLPM0", 0xD012 },
+ { "TRIG3", 0xD013 },
+ { "COLPM1", 0xD013 },
+ { "PAL", 0xD014 },
+ { "COLPM2", 0xD014 },
+ { "COLPM3", 0xD015 },
+ { "COLPF0", 0xD016 },
+ { "COLPF1", 0xD017 },
+ { "COLPF2", 0xD018 },
+ { "COLPF3", 0xD019 },
+ { "COLBK", 0xD01A },
+ { "PRIOR", 0xD01B },
+ { "VDELAY", 0xD01C },
+ { "GRACTL", 0xD01D },
+ { "HITCLR", 0xD01E },
+ { "CONSOL", 0xD01F },
+
+ { "POT0", 0xD200 },
+ { "AUDF1", 0xD200 },
+ { "POT1", 0xD201 },
+ { "AUDC1", 0xD201 },
+ { "POT2", 0xD202 },
+ { "AUDF2", 0xD202 },
+ { "POT3", 0xD203 },
+ { "AUDC2", 0xD203 },
+ { "POT4", 0xD204 },
+ { "AUDF3", 0xD204 },
+ { "POT5", 0xD205 },
+ { "AUDC3", 0xD205 },
+ { "POT6", 0xD206 },
+ { "AUDF4", 0xD206 },
+ { "POT7", 0xD207 },
+ { "AUDC4", 0xD207 },
+ { "ALLPOT", 0xD208 },
+ { "AUDCTL", 0xD208 },
+ { "KBCODE", 0xD209 },
+ { "STIMER", 0xD209 },
+ { "RANDOM", 0xD20A },
+ { "SKREST", 0xD20A },
+ { "POTGO", 0xD20B },
+ { "SERIN", 0xD20D },
+ { "SEROUT", 0xD20D },
+ { "IRQST", 0xD20E },
+ { "IRQEN", 0xD20E },
+ { "SKSTAT", 0xD20F },
+ { "SKCTL", 0xD20F },
+
+ { "PORTA", 0xD300 },
+ { "PORTB", 0xD301 },
+ { "PACTL", 0xD302 },
+ { "PBCTL", 0xD303 },
+
+ { "DMACTL", 0xD400 },
+ { "CHACTL", 0xD401 },
+ { "DLISTL", 0xD402 },
+ { "DLISTH", 0xD403 },
+ { "HSCROL", 0xD404 },
+ { "VSCROL", 0xD405 },
+ { "PMBASE", 0xD407 },
+ { "CHBASE", 0xD409 },
+ { "WSYNC", 0xD40A },
+ { "VCOUNT", 0xD40B },
+ { "PENH", 0xD40C },
+ { "PENL", 0xD40D },
+ { "NMIEN", 0xD40E },
+ { "NMIST", 0xD40F },
+ { "NMIRES", 0xD40F },
+
+ { "AFP", 0xD800 },
+ { "FASC", 0xD8E6 },
+ { "IFP", 0xD9AA },
+ { "FPI", 0xD9D2 },
+ { "ZPRO", 0xDA44 },
+ { "ZF1", 0xDA46 },
+ { "FSUB", 0xDA60 },
+ { "FADD", 0xDA66 },
+ { "FMUL", 0xDADB },
+ { "FDIV", 0xDB28 },
+ { "PLYEVL", 0xDD40 },
+ { "FLD0R", 0xDD89 },
+ { "FLD0R", 0xDD8D },
+ { "FLD1R", 0xDD98 },
+ { "FLD1P", 0xDD9C },
+ { "FST0R", 0xDDA7 },
+ { "FST0P", 0xDDAB },
+ { "FMOVE", 0xDDB6 },
+ { "EXP", 0xDDC0 },
+ { "EXP10", 0xDDCC },
+ { "LOG", 0xDECD },
+ { "LOG10", 0xDED1 },
+
+ { "DSKINV", 0xE453 },
+ { "CIOV", 0xE456 },
+ { "SIOV", 0xE459 },
+ { "SETVBV", 0xE45C },
+ { "SYSVBV", 0xE45F },
+ { "XITVBV", 0xE462 },
+ { "SIOINV", 0xE465 },
+ { "SENDEV", 0xE468 },
+ { "INTINV", 0xE46B },
+ { "CIOINV", 0xE46E },
+ { "SELFSV", 0xE471 },
+ { "WARMSV", 0xE474 },
+ { "COLDSV", 0xE477 },
+ { "RBLOKV", 0xE47A },
+ { "CSOPIV", 0xE47D },
+ { "PUPDIV", 0xE480 },
+ { "SELFTSV", 0xE483 },
+ { "PENTV", 0xE486 },
+ { "PHUNLV", 0xE489 },
+ { "PHINIV", 0xE48C },
+ { "GPDVV", 0xE48F }
+};
+
+int symtable_size=sizeof(symtable)/sizeof(symtable_rec);
+
+
+void OutputBlockDiss( BYTE* pbtBlock, WORD wOffset, WORD wEnd )
+{
+ WORD wPC_curr = 0;
+ WORD wPC_end = wEnd - wOffset;
+ WORD wInsLen = 0;
+ WORD wInsCode = 0;
+ BOOL bInsIncomplete = FALSE;
+
+ while ( wPC_curr <= wPC_end )
+ {
+ wInsCode = pbtBlock[ wPC_curr ];
+ wInsLen = instable[ wInsCode ].length;
+
+ printf("%04X ", wPC_curr + wOffset );
+
+ if ( wPC_curr + wInsLen > wPC_end )
+ {
+ wInsLen = wPC_end - wPC_curr;
+ bInsIncomplete = TRUE;
+ }
+
+ for ( int i = 0; i <= wInsLen; i++ )
+ {
+ printf("%02X ", pbtBlock[ wPC_curr + i ] );
+ }
+
+ for ( int i = 0; i < ( 3 - wInsLen ); i++ )
+ {
+ printf(" ");
+ }
+
+ char obuf[256];
+ char *p;
+
+ char* szSymbol = NULL;
+
+ strcpy( obuf, instable[ wInsCode ].instruct );
+
+ for (p = obuf; *p; p++)
+ {
+ if (*p == '*')
+ {
+ *p = '\0';
+ p++;
+ break;
+ }
+ }
+
+ if ( !instable[ pbtBlock[ wPC_curr ] ].length )
+ {
+ printf( "%s\n", instable[pbtBlock[wPC_curr]].instruct );
+ }
+ else
+ {
+ if ( bInsIncomplete )
+ {
+ printf( "!!!\n" );
+ break;
+ }
+
+ printf( "%s",obuf );
+
+ if ( instable[wInsCode].branch )
+ {
+ int uPdata = (int) (signed char)pbtBlock[ wPC_curr + 1 ];
+ printf( "%04X", wPC_curr + 2 + uPdata + wOffset );
+ }
+ else
+ {
+ if ( instable[wInsCode].length == 1 )
+ {
+ WORD wAddr = (BYTE)pbtBlock[ wPC_curr + 1 ];
+
+ if ( !instable[ wInsCode ].immed )
+ szSymbol = SymbolFind( wAddr, instable[ wInsCode ].write ? TRUE : FALSE );
+
+ printf( "$%02X", wAddr );
+
+ }
+ else if ( instable[wInsCode].length == 2 )
+ {
+ WORD wAddr = (WORD) pbtBlock[ wPC_curr + 1 ] |
+ (WORD)( pbtBlock[ wPC_curr + 2 ] << 8 );
+
+ if ( !instable[ wInsCode ].immed )
+ szSymbol = SymbolFind( wAddr, instable[ wInsCode ].write ? TRUE : FALSE );
+
+ printf( "$%04X", wAddr );
+
+ }
+ }
+
+ if ( szSymbol )
+ printf("%s\t;%s\n", p, szSymbol );
+ else
+ printf("%s\n",p);
+ }
+
+ wPC_curr += ( wInsLen + 1 );
+ }
+
+}
+
+char* SymbolFind( WORD addr, BOOL bWrite )
+{
+ int lo = 0;
+ int mi = 0;
+ int hi = symtable_size - 1;
+
+ while ( lo < hi )
+ {
+ mi = ( lo + hi ) / 2;
+
+ if ( symtable[ mi ].addr == addr )
+ {
+ break;
+ }
+ else
+ {
+ if ( symtable[ mi ].addr > addr )
+ hi=mi;
+ else
+ lo=mi+1;
+ }
+ }
+
+ if ( symtable[mi].addr == addr )
+ {
+ if ( mi>0 && symtable[mi-1].addr == addr )
+ {
+ mi--;
+ }
+
+ if ( bWrite )
+ {
+ if ( mi < symtable_size - 1 )
+ if ( symtable[ mi + 1 ].addr == addr )
+ mi++;
+ }
+
+ return symtable[ mi ].name;
+ }
+
+ else
+ return NULL;
+}
+
+
+
diff --git a/jindroush/lib/autil.cpp b/jindroush/lib/autil.cpp
new file mode 100644
index 0000000..3afc782
--- /dev/null
+++ b/jindroush/lib/autil.cpp
@@ -0,0 +1,139 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "autil.h"
+
+void Peecize( char* szPC, char* szAtari );
+
+//converts 8+3 Atari fname to it's PC equivalent
+void ADos2MsDos( char* szMsDos, char* szADos )
+{
+ char szName[ 9 ];
+ strncpy( szName, szADos, 8 );
+ szName[ 8 ] = '\0';
+
+ char szExt[ 4 ];
+ strncpy( szExt, szADos + 8, 3 );
+ szExt[ 3 ] = '\0';
+
+ Peecize( szName, szName );
+ Peecize( szExt, szExt );
+
+ if ( !*szName )
+ strcpy( szName, "out" );
+
+ strcpy( szMsDos, szName );
+
+ if ( *szExt )
+ {
+ strcat( szMsDos, "." );
+ strcat( szMsDos, szExt );
+ }
+}
+
+//kind of 'good-for-dos' filter
+void Peecize( char* szPC, char* szAtari )
+{
+ int iLen = strlen( szAtari );
+
+ while( iLen-- )
+ {
+ //filter off the inverse chars
+ char c = *( szAtari++ ) & 0x7F;
+
+ //filter spaces
+ if ( c == ' ' )
+ continue;
+
+ //filter unprintables
+ if ( !isprint( c ) )
+ c = '_';
+
+ //filter other 'ugly' characters :)
+ switch( c )
+ {
+ case '*':
+ case ':':
+ case '\"':
+ case ',':
+ case '.':
+ case '|':
+ case '?':
+ case '/':
+ case '\\':
+ c = '_';
+ break;
+ }
+
+ *( szPC++ ) = c;
+ }
+
+ *szPC = '\0';
+}
+
+
+//converts any Atari name to it's PC equivalent
+void GuessBestFnameFromAtari( char* szDest, char* szSrc, char* szExt )
+{
+ char szTemp[ 255 ];
+ Peecize( szTemp, szSrc );
+ GuessBestFnameFromPC( szDest, szTemp, szExt );
+}
+
+//changes file extension
+void GuessBestFnameFromPC( char* szDest, char* szSrc, char* szExt, char* szAdd )
+{
+ char szTemp[ 255 ];
+
+ char szGoodSrc[ 255 ];
+
+ _fixpath( szSrc, szGoodSrc );
+
+ char* szSl = strrchr( szGoodSrc, '/' );
+
+ if ( szSl )
+ strcpy( szTemp, szSl + 1 );
+ else
+ strcpy( szTemp, szGoodSrc );
+
+ char* szDot = strrchr( szTemp, '.' );
+
+ if ( szDot )
+ *szDot = '\0';
+
+ if ( !strlen( szTemp ) )
+ strcpy( szTemp, "out" );
+
+ strcpy( szDest, szTemp );
+
+ if ( szAdd )
+ strcat( szDest, szAdd );
+
+ strcat( szDest, "." );
+ strcat( szDest, szExt );
+}
+
+//is memory block empty?
+BOOL IsBlockEmpty( BYTE* p, int iLen )
+{
+ while( iLen-- )
+ {
+ if ( *( p++ ) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cdisk.cpp b/jindroush/lib/cdisk.cpp
new file mode 100644
index 0000000..74ee067
--- /dev/null
+++ b/jindroush/lib/cdisk.cpp
@@ -0,0 +1,276 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdisk.h"
+#include "cdsk_atr.h"
+#include "cdsk_xfd.h"
+#include "cdsk_dcm.h"
+#include "cdsk_scp.h"
+
+
+CDisk::CDisk()
+{
+ m_bOpened = FALSE;
+ m_pbtMemory = NULL;
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk constructed: %08X\n", this );
+ #endif
+}
+
+CDisk::~CDisk()
+{
+ if ( m_pbtMemory )
+ {
+ delete [] m_pbtMemory;
+ m_pbtMemory = NULL;
+ }
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDisk::Duplicate( CDisk* pDisk )
+{
+ if ( !Format( & ( pDisk->m_geometry ) ) )
+ return FALSE;
+
+ memcpy( m_pbtMemory, pDisk->m_pbtMemory, pDisk->m_iAllocated );
+ return TRUE;
+}
+
+BOOL CDisk::Format( DISK_GEOMETRY* pgeo )
+{
+ int iSectors = pgeo->iSides * pgeo->iTracks * pgeo->iSectorsPerTrack;
+
+ if ( m_pbtMemory )
+ delete [] m_pbtMemory;
+
+ m_iAllocated = iSectors * pgeo->iBytesPerSector;
+ m_pbtMemory = new BYTE [ m_iAllocated ];
+
+ if ( !m_pbtMemory )
+ {
+ sprintf( m_szLastError, "DISK: Can't format - Not enough memory!" );
+ return FALSE;
+ }
+
+ memset( m_pbtMemory, 0, m_iAllocated );
+
+ m_geometry.iSides = pgeo->iSides;
+ m_geometry.iTracks = pgeo->iTracks;
+ m_geometry.iSectorsPerTrack = pgeo->iSectorsPerTrack;
+ m_geometry.iBytesPerSector = pgeo->iBytesPerSector;
+ m_geometry.iSectors = iSectors;
+
+ return TRUE;
+}
+
+BOOL CDisk::ReadSector( void* pBuf, int iStartSec )
+{
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( pBuf, m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Reading non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL CDisk::ReadSectors( void* pBuf, int iStartSec, int iSecs )
+{
+ while( iSecs )
+ {
+ if ( !ReadSector( pBuf, iStartSec ) )
+ return FALSE;
+
+ iStartSec++;
+ iSecs--;
+ pBuf = (BYTE*)pBuf + m_geometry.iBytesPerSector;
+ }
+
+ return TRUE;
+}
+
+BOOL CDisk::WriteSector( int iStartSec, void* pBuf )
+{
+ //printf( " ws: %d ", iStartSec );
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, pBuf, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Writing non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void GuessClassicSizes( int iSectors, int iSectorSize, DISK_GEOMETRY* pGeometry )
+{
+ pGeometry->iSides = 1;
+ pGeometry->iBytesPerSector = iSectorSize;
+
+ pGeometry->iTracks = 1;
+ pGeometry->iSectorsPerTrack = iSectors;
+
+ switch( iSectors )
+ {
+ case 720:
+ switch( iSectorSize )
+ {
+ case 0x80:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+
+ case 0x100:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 18;
+ break;
+ }
+ break;
+
+ case 1040:
+ pGeometry->iTracks = 40;
+ pGeometry->iSectorsPerTrack = 26;
+ break;
+
+ }
+
+}
+
+//returns ptr to disk type name
+char* GetDiskTypeName( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ return "XFD";
+
+ case DISK_ATR:
+ return "ATR";
+
+ case DISK_XFDb:
+ return "XFDb";
+
+ case DISK_ATRb:
+ return "ATRb";
+
+ case DISK_DCM:
+ return "DCM";
+
+ case DISK_SCP:
+ return "SCP";
+
+ default:
+ return "None";
+ }
+}
+
+//returns ptr to disk type extension
+char* GetDiskTypeExt( DISK_TYPE disktype )
+{
+ switch( disktype )
+ {
+ case DISK_XFD:
+ case DISK_XFDb:
+ return "xfd";
+
+ case DISK_ATR:
+ case DISK_ATRb:
+ return "atr";
+
+ case DISK_DCM:
+ return "dcm";
+
+ case DISK_SCP:
+ return "scp";
+
+ default:
+ return "xxx";
+ }
+}
+
+DISKINIT_RETCODE InitializeDisk( CDisk** ppDisk, DISK_TYPE disktype, char* szFname, BOOL bVerbose, BOOL bRepair, BOOL bRepairAuto )
+{
+ switch( disktype )
+ {
+ case DISK_ATR:
+ *ppDisk = new CAtr();
+ break;
+
+ case DISK_SCP:
+ *ppDisk = new CScp();
+ break;
+
+ case DISK_DCM:
+ *ppDisk = new CDcm();
+ break;
+
+ case DISK_XFD:
+ *ppDisk = new CXfd();
+ break;
+
+ default:
+ if ( bVerbose )
+ fprintf( stderr, "Invalid disk type specified!\n" );
+ return DI_RET_CANT_CONTINUE;
+ }
+
+ if ( !*ppDisk )
+ {
+ if ( bVerbose )
+ fprintf( stderr, "Can't initialize disk driver!\n" );
+ return DI_RET_CONTINUE;
+ }
+
+ if ( !(*ppDisk)->Load( szFname, bRepair, bRepairAuto ) )
+ {
+ int iError = (*ppDisk)->GetErrorCode();
+
+ DISKINIT_RETCODE ret = DI_RET_CONTINUE;
+
+ switch( iError )
+ {
+ case CATR_FORMAT_VIOLATED:
+ case CXFD_FORMAT_VIOLATED:
+ case CDISK_ERROR_CANT_OPEN:
+ case CDCM_FORMAT_VIOLATED:
+ case CSCP_FORMAT_VIOLATED:
+ ret = DI_RET_CANT_CONTINUE;
+ break;
+ }
+
+ if ( bVerbose || ( ret == DI_RET_CANT_CONTINUE ) )
+ {
+ printf( "Input file '%s' ", szFname );
+ printf( "(%s)\n", GetDiskTypeName( disktype ) );
+ printf( "Load failed because:\n%s\n", (*ppDisk)->GetLastError() );
+ }
+ if ( ret != DI_RET_OK )
+ {
+ delete *ppDisk;
+ return ret;
+ }
+ }
+
+ return DI_RET_OK;
+}
+
+
diff --git a/jindroush/lib/cdsk.cpp b/jindroush/lib/cdsk.cpp
new file mode 100644
index 0000000..cc905f6
--- /dev/null
+++ b/jindroush/lib/cdsk.cpp
@@ -0,0 +1,115 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk.h"
+
+CDisk::CDisk()
+{
+ m_bHasData = FALSE;
+ m_pbtMemory = NULL;
+
+ m_iMaxSectorWritten = 0;
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk constructed: %p\n", this );
+ #endif
+}
+
+CDisk::~CDisk()
+{
+ if ( m_pbtMemory )
+ {
+ delete [] m_pbtMemory;
+ m_pbtMemory = NULL;
+ }
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDisk destructed: %p\n", this );
+ #endif
+}
+
+BOOL CDisk::Duplicate( CDisk* pDisk, DISK_GEOMETRY* pGeoForced )
+{
+ DISK_GEOMETRY* pGeo = pGeoForced;
+ if ( !pGeo )
+ pGeo = &( pDisk->m_geometry );
+
+ if ( !Format( pGeo ) )
+ return FALSE;
+
+ memcpy( m_pbtMemory, pDisk->m_pbtMemory, pDisk->m_iAllocated );
+ m_iMaxSectorWritten = pDisk->m_iMaxSectorWritten;
+ return TRUE;
+}
+
+BOOL CDisk::Format( DISK_GEOMETRY* pgeo )
+{
+ m_iMaxSectorWritten = 0;
+
+ int iSectors = pgeo->iSides * pgeo->iTracks * pgeo->iSectorsPerTrack;
+
+ if ( m_pbtMemory )
+ delete [] m_pbtMemory;
+
+ m_iAllocated = iSectors * pgeo->iBytesPerSector;
+ m_pbtMemory = new BYTE [ m_iAllocated ];
+
+ if ( !m_pbtMemory )
+ {
+ sprintf( m_szLastError, "DISK: Can't format - Not enough memory!" );
+ return FALSE;
+ }
+
+ memset( m_pbtMemory, 0, m_iAllocated );
+
+ m_geometry.iSides = pgeo->iSides;
+ m_geometry.iTracks = pgeo->iTracks;
+ m_geometry.iSectorsPerTrack = pgeo->iSectorsPerTrack;
+ m_geometry.iBytesPerSector = pgeo->iBytesPerSector;
+ m_geometry.iSectors = iSectors;
+
+ return TRUE;
+}
+
+BOOL CDisk::ReadSector( void* pBuf, int iStartSec )
+{
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( pBuf, m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Reading non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL CDisk::WriteSector( int iStartSec, void* pBuf )
+{
+ //printf( " ws: %d ", iStartSec );
+ if ( iStartSec && ( iStartSec <= m_geometry.iSectors ) )
+ memcpy( m_pbtMemory + ( iStartSec - 1 ) * m_geometry.iBytesPerSector, pBuf, m_geometry.iBytesPerSector );
+ else
+ {
+ sprintf( m_szLastError, "DISK: Writing non-existent sector: %04X", iStartSec );
+ return FALSE;
+ }
+
+ if ( iStartSec > m_iMaxSectorWritten )
+ m_iMaxSectorWritten = iStartSec;
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cdsk_atr.cpp b/jindroush/lib/cdsk_atr.cpp
new file mode 100644
index 0000000..a472561
--- /dev/null
+++ b/jindroush/lib/cdsk_atr.cpp
@@ -0,0 +1,439 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_atr.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define ATR_MAGIC 0x0296
+
+typedef struct
+{
+ WORD wMagic;
+ WORD wPars;
+ WORD wSecSize;
+ BYTE btParHigh;
+ DWORD dwCRC;
+ DWORD dwUnused;
+ BYTE btFlags;
+
+} ATRhead;
+
+#define ATR_HEAD_LEN 0x10
+
+CAtr::CAtr() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr constructed: %08X\n", this );
+ #endif
+}
+
+CAtr::~CAtr()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CAtr destructed: %08X\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3,
+ LOAD_PAD
+} LOAD_VARIANT;
+
+BOOL CAtr::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ m_iErrorCode = 0;
+
+ int iFirstSectorsSize = 0x80;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ ATRhead head;
+
+ head.wMagic = cf.readLEw();
+ head.wPars = cf.readLEw();
+ head.wSecSize = cf.readLEw();
+ head.btParHigh = cf.readb();
+ head.dwCRC = cf.readLEdw();
+ head.dwUnused = cf.readLEdw();
+ head.btFlags = cf.readb();
+
+ if ( head.wMagic != ATR_MAGIC )
+ {
+ sprintf( m_szLastError, "ATR: File '%s' is not an ATR file!", szFname );
+ return FALSE;
+ }
+
+ LONG lFileLen = cf.GetLength();
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( head.wSecSize )
+ {
+ case 0x80:
+ case 0x100:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "ATR: Invalid sector size: %04X", head.wSecSize );
+ return FALSE;
+ }
+ }
+
+ DWORD dwPars = head.wPars | ( head.btParHigh << 16 );
+
+ int iSectors = ( dwPars * 0x10 ) / head.wSecSize;
+
+ //BOOL bReadOnly = (head.btFlags & 1) ? TRUE : FALSE;
+
+ if ( head.wSecSize == 0x100 )
+ {
+ //if ( dwPars % head.wSecSize )
+ if ( ( dwPars * 0x10 ) % head.wSecSize )
+ {
+ iSectors = ( ( dwPars * 0x10 - 0x180 ) / head.wSecSize ) + 3;
+ }
+ else
+ {
+ sprintf( m_szLastError, "ATR: Format violated. First three sectors are not $80 long!" );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ if ( !bRepair )
+ {
+ return FALSE;
+ }
+ else
+ {
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ATR_HEAD_LEN + ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ if ( iMethod == 4 )
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+
+ cf.Seek( ATR_HEAD_LEN, SEEK_SET );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ case LOAD_BAD_DD_2:
+ case LOAD_BAD_DD_3:
+ iFirstSectorsSize = 0x100;
+ break;
+
+ default:
+ break;
+
+ }
+
+ } //end of repair
+
+ }
+ }
+
+ LONG lTotalComputedLen = (LONG) ( ( iSectors - 3 ) * head.wSecSize + ATR_HEAD_LEN + 3 * iFirstSectorsSize );
+
+ if ( lTotalComputedLen != lFileLen )
+ {
+ sprintf( m_szLastError, "ATR: Invalid length! %08lX <> %08lX (%08X)", lTotalComputedLen, lFileLen, iSectors );
+ m_iErrorCode = CATR_FORMAT_VIOLATED;
+
+ if ( !bRepair || ( load_method != LOAD_OK ) )
+ return FALSE;
+ else
+ {
+ if ( !bRepairAuto )
+ {
+ printf( "ATR with invalid length encountered.\n" );
+ printf( "Should be: $%08lX. Is: $%08lX.\n", lTotalComputedLen, lFileLen );
+ printf( "Choose:\n" );
+ printf( "1) Repair (shorten/pad)\n" );
+ printf( "2) Don't repair\n" );
+
+ int iMethod;
+
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 2 ) );
+
+ if ( iMethod == 2 )
+ return FALSE;
+
+ load_method = LOAD_PAD;
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_PAD;
+ }
+
+ }
+
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSectors, head.wSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_PAD:
+ memset( abtBuff, 0, 0x100 );
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : head.wSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ WriteSector( i + 1, abtBuff );
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CAtr::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "ATR: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ ATRhead head;
+ memset( &head, 0, sizeof( ATRhead ) );
+
+ head.wMagic = ATR_MAGIC;
+ head.wSecSize = m_geometry.iBytesPerSector;
+
+ BOOL bReadOnly = TRUE;
+ head.btFlags |= ( bReadOnly ) ? 0x01 : 0x00;
+
+ DWORD dwLength = 0;
+
+ dwLength = 0x180 + ( m_geometry.iSectors - 3 ) * m_geometry.iBytesPerSector;
+
+ dwLength >>= 4;
+
+ head.wPars = dwLength & 0xFFFF;
+ head.btParHigh = dwLength >> 0x10;
+
+ cf.writeLEw( head.wMagic );
+ cf.writeLEw( head.wPars );
+ cf.writeLEw( head.wSecSize );
+ cf.writeb( head.btParHigh );
+ cf.writeLEdw( head.dwCRC );
+ cf.writeLEdw( head.dwUnused );
+ cf.writeb( head.btFlags );
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ ReadSector( abtBuff, i );
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iToWrite != iWritten ) )
+ {
+ sprintf( m_szLastError, "ATR: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/cdsk_dcm.cpp b/jindroush/lib/cdsk_dcm.cpp
new file mode 100644
index 0000000..06ec1a3
--- /dev/null
+++ b/jindroush/lib/cdsk_dcm.cpp
@@ -0,0 +1,762 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_dcm.h"
+#include "cfile.h"
+#include "cprefile.h"
+#include "autil.h"
+
+//#define _DCM_DUMP_
+
+#define DCM_CHANGE_BEGIN 0x41 //Change only start of sector
+#define DCM_DOS_SECTOR 0x42 //128 byte compressed sector
+#define DCM_COMPRESSED 0x43 //Uncompressed/compressed pairs
+#define DCM_CHANGE_END 0x44 //Change only end of sector
+#define DCM_PASS_END 0x45 //End of pass
+#define DCM_SAME_AS_BEFORE 0x46 //Same as previous non-zero
+#define DCM_UNCOMPRESSED 0x47 //Uncompressed sector
+
+#define DCM_HEADER_SINGLE 0xFA
+#define DCM_HEADER_MULTI 0xF9
+
+#define DCM_DENSITY_SD 0 //Single density, 90K
+#define DCM_DENSITY_DD 1 //Double density, 180K
+#define DCM_DENSITY_ED 2 //Enhanced density, 130K
+
+CDcm::CDcm() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm constructed: %08X\n", this );
+ #endif
+}
+
+CDcm::~CDcm()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDcm destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDcm::Load( char* szFname, BOOL, BOOL )
+{
+ BYTE btArcType = 0; //Block type for first block
+ BYTE btBlkType; //Current block type
+
+ m_bAlreadyFormatted = FALSE;
+ m_bLastPass = FALSE;
+ m_wCurrentSector = 0;
+
+ CFile cfo;
+ CPreFile cf;
+
+ if ( !cfo.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't open '%s'", szFname );
+ m_iErrorCode = CDISK_ERROR_CANT_OPEN;
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ cf.Open( &cfo, 20 );
+
+ m_lFileLength = cf.GetLength();
+
+ for(;;) //outpass
+ {
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ if ( ( !m_bLastPass ) && ( btArcType == DCM_HEADER_MULTI ) )
+ {
+ sprintf( m_szLastError,"DCM: Multi-part archive error.\n" \
+ "To process these files, you must first combine the files into a single file." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ btArcType = cf.readb();
+
+ switch( btArcType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ if ( !DecodeRecFA( cf ) )
+ return FALSE;
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown header block.\n", btArcType );
+ return FALSE;
+ }
+
+ for(;;) //inpass
+ {
+ btBlkType = cf.readb();
+
+ if ( btBlkType == DCM_PASS_END )
+ break;
+
+ if ( cf.Tell() >= m_lFileLength )
+ {
+ sprintf( m_szLastError, "DCM: EOF before end block." );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ BOOL bRes = TRUE;
+
+ *m_szLastError = '\0';
+ switch( btBlkType & 0x7F )
+ {
+ case DCM_CHANGE_BEGIN:
+ bRes = DecodeRec41( cf );
+ break;
+
+ case DCM_DOS_SECTOR:
+ bRes = DecodeRec42( cf );
+ break;
+
+ case DCM_COMPRESSED:
+ bRes = DecodeRec43( cf );
+ break;
+
+ case DCM_CHANGE_END:
+ bRes = DecodeRec44( cf );
+ break;
+
+ case DCM_SAME_AS_BEFORE:
+ //not needed
+ //bRes = DecodeRec46( cf );
+ break;
+
+ case DCM_UNCOMPRESSED:
+ bRes = DecodeRec47( cf );
+ break;
+
+ default:
+ {
+ switch( btBlkType )
+ {
+ case DCM_HEADER_MULTI:
+ case DCM_HEADER_SINGLE:
+ sprintf( m_szLastError, "DCM: Trying to start section but last section never had "
+ "an end section block.");
+ break;
+
+ default:
+ sprintf( m_szLastError, "DCM: %02X is an unknown block type. File may be "
+ "corrupt.",btBlkType);
+ break;
+ }
+
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+ }
+
+ if ( !bRes )
+ {
+ sprintf( m_szLastError, "DCM: Block %02X decode error!", btBlkType );
+ m_iErrorCode = CDCM_FORMAT_VIOLATED;
+ return FALSE;
+ }
+
+ if ( !WriteSector( m_wCurrentSector, m_abtCurrBuff ) )
+ return FALSE;
+
+ if ( btBlkType & 0x80 )
+ m_wCurrentSector++;
+ else
+ m_wCurrentSector = cf.readLEw();
+
+ } //infinite for (inpass)
+
+ //End block
+ if ( m_bLastPass )
+ break;
+
+ } //infinite for (outpass)
+
+ cf.Close();
+ cfo.Close();
+ return TRUE;
+
+}
+
+BOOL CDcm::DecodeRec41( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec41: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = cf.readb();
+ BYTE* pbt = m_abtCurrBuff + iOffset;
+
+ do
+ {
+ *( pbt-- ) = cf.readb();
+ } while( iOffset-- );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec42( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec42: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ sprintf( m_szLastError, "DCM: Record type 0x42 untested. Uncomment?" );
+ return FALSE;
+
+ //TODO: uncomment later!
+ //cf.Read( m_abtCurrBuff + 123, 5 );
+ //memset( m_abtCurrBuff, m_abtCurrBuff[ 123 ], 123 );
+ //return TRUE;
+}
+
+BOOL CDcm::DecodeRec43( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec43: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE* pbtP = m_abtCurrBuff;
+ BYTE* pbtE;
+
+ BYTE* pbtEnd = m_abtCurrBuff + m_iSectorSize;
+
+ do
+ {
+ //uncompressed string
+ if ( pbtP != m_abtCurrBuff )
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ else
+ pbtE = m_abtCurrBuff + cf.readb();
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: uncst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE != pbtP )
+ {
+ cf.Read( pbtP, pbtE - pbtP );
+ pbtP = pbtE;
+ }
+
+ if ( pbtP >= pbtEnd )
+ break;
+
+ //rle compressed string
+ pbtE = m_abtCurrBuff + ReadOffset( cf );
+ BYTE c = cf.readb();
+
+ #ifdef _DCM_DUMP_
+ printf( "dec43: cst: %p %p %ld\n", pbtP, pbtE, pbtE - pbtP );
+ #endif
+
+ if ( pbtE < pbtP )
+ return FALSE;
+
+ memset( pbtP, c, pbtE - pbtP );
+ pbtP = pbtE;
+
+ } while( pbtP < pbtEnd );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec44( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec44: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ int iOffset = ReadOffset( cf );
+
+ cf.Read( m_abtCurrBuff + iOffset, m_iSectorSize - iOffset );
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec46( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec46: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRec47( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "dec47: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ //TODO: Is this TRUE or NOT???
+ //cf.Read( m_abtCurrBuff, ( m_wCurrentSector < 4 ? 128 : m_iSectorSize ) );
+
+ cf.Read( m_abtCurrBuff, m_iSectorSize );
+ return TRUE;
+}
+
+BOOL CDcm::DecodeRecFA( CGenFile& cf )
+{
+ #ifdef _DCM_DUMP_
+ printf( "decFA: %08lX\n", cf.Tell() - 1 );
+ #endif
+
+ BYTE btPom = cf.readb();
+
+ BYTE btDensity = ( btPom >> 5 ) & 0x03;
+ //BYTE btPass = btPom & 0x1F;
+ m_bLastPass = ( btPom & 0x80 ) ? TRUE : FALSE;
+
+ int iSpT;
+ int iTracks;
+
+ switch( btDensity )
+ {
+ case DCM_DENSITY_SD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 128;
+ break;
+
+ case DCM_DENSITY_DD:
+ iTracks = 40;
+ iSpT = 18;
+ m_iSectorSize = 256;
+ break;
+
+ case DCM_DENSITY_ED:
+ iTracks = 40;
+ iSpT = 26;
+ m_iSectorSize = 128;
+ break;
+
+ default:
+ sprintf( m_szLastError,"DCM: Density type unknown (%02X)\n", btDensity );
+ return FALSE;
+ }
+
+ if ( !m_bAlreadyFormatted )
+ {
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = iTracks;
+ dg.iSectorsPerTrack = iSpT;
+ dg.iBytesPerSector = m_iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ m_bAlreadyFormatted = TRUE;
+ }
+
+ m_wCurrentSector = cf.readLEw();
+
+ return TRUE;
+}
+
+WORD CDcm::ReadOffset( CGenFile& cf )
+{
+ BYTE bt = cf.readb();
+
+ return( bt ? bt : 256 );
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CDcm::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "DCM: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ int iDensity = -1;
+ m_iSectorSize = m_geometry.iBytesPerSector;
+
+ if ( m_iSectorSize == 0x80 )
+ {
+ if ( m_geometry.iTracks == 40 )
+ {
+ if ( m_geometry.iSectorsPerTrack == 18 )
+ iDensity = DCM_DENSITY_SD;
+
+ if ( m_geometry.iSectorsPerTrack == 26 )
+ iDensity = DCM_DENSITY_ED;
+ }
+ }
+
+ if ( m_iSectorSize == 0x100 )
+ {
+ if ( ( m_geometry.iSectorsPerTrack == 18 ) &&
+ ( m_geometry.iTracks == 40 ) )
+ iDensity = DCM_DENSITY_DD;
+ }
+
+ if ( iDensity == - 1 )
+ {
+ sprintf( m_szLastError, "DCM: Can't work with such density!" );
+ return FALSE;
+ }
+
+ int iPass = 1;
+
+ m_pbtPass = new BYTE [ 0x6500 ];
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't create '%s'", szOutFile );
+ delete [] m_pbtPass;
+ return FALSE;
+ }
+
+ int iFirstSector = 0;
+ int iPrevSector = 0;
+ int iCurrentSector = 1;
+
+ memset( m_abtPrevBuff, 0, m_iSectorSize );
+
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //here should be other compression
+
+ while( iCurrentSector <= m_geometry.iSectors )
+ {
+ iFirstSector = 0;
+
+ while( ( m_pbtCurr - m_pbtPass ) < 0x5EFD )
+ {
+ if ( iCurrentSector > m_geometry.iSectors )
+ break;
+
+ ReadSector( m_abtCurrBuff, iCurrentSector );
+
+ BOOL bSkip = IsBlockEmpty( m_abtCurrBuff, m_iSectorSize );
+
+ //first non empty sector is marked as first, what a surprise! :)
+ if ( !bSkip && !iFirstSector )
+ {
+ iFirstSector = iCurrentSector;
+ iPrevSector = iCurrentSector;
+ }
+
+ //if just skipped, increment sector
+ if ( bSkip )
+ {
+ iCurrentSector++;
+ }
+ else
+ {
+ //if there is a gap, write sector number
+ if ( ( iCurrentSector - iPrevSector ) > 1 )
+ {
+ *( m_pbtCurr++ ) = iCurrentSector;
+ *( m_pbtCurr++ ) = iCurrentSector >> 8;
+ }
+ else
+ {
+ //else mark previous record
+ *m_pbtLastRec |= 0x80;
+ }
+
+ //first sector could be encoded with only some data
+ if ( iCurrentSector == iFirstSector )
+ EncodeRec( TRUE );
+ else
+ {
+ //if are same, encode as record 46
+ if ( !memcmp( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize ) )
+ EncodeRec46();
+ else
+ EncodeRec( FALSE );
+ }
+
+ //store this sector as previous
+ memcpy( m_abtPrevBuff, m_abtCurrBuff, m_iSectorSize );
+
+ //and move pointers
+ iPrevSector = iCurrentSector;
+ iCurrentSector++;
+ }
+
+ }
+
+ //mark previous sector
+ *m_pbtLastRec |= 0x80;
+
+ //encode end
+ EncodeRec45();
+
+ BYTE* pEnd = m_pbtCurr;
+
+ //change beginning block
+ if ( iCurrentSector > m_geometry.iSectors )
+ EncodeRecFA( TRUE, iPass, iDensity, iFirstSector );
+ else
+ EncodeRecFA( FALSE, iPass, iDensity, iFirstSector );
+
+ //and write whole pass
+
+ if ( ( pEnd - m_pbtPass ) > 0x6000 )
+ {
+ sprintf( m_szLastError, "DCM: Internal error! Pass too long!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Write( m_pbtPass, pEnd - m_pbtPass ) )
+ {
+ sprintf( m_szLastError, "DCM: Can't write!" );
+ delete [] m_pbtPass;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ iPass++;
+ }
+
+ cf.Close();
+
+ delete [] m_pbtPass;
+
+ return TRUE;
+}
+
+void CDcm::EncodeRecFA( BOOL bLast, int iPass, int iDensity, int iFirstSec )
+{
+ m_pbtCurr = m_pbtPass;
+
+ #ifdef _DCM_DUMP_
+ printf( "ERFA: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE btType = bLast ? 0x80 : 0;
+
+ btType |= ( iDensity & 3 ) << 5;
+
+ btType |= ( iPass & 0x1F );
+
+ *( m_pbtCurr++ ) = DCM_HEADER_SINGLE;
+ *( m_pbtCurr++ ) = btType;
+ *( m_pbtCurr++ ) = iFirstSec;
+ *( m_pbtCurr++ ) = iFirstSec >> 8;
+
+}
+
+void CDcm::EncodeRec45()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER45: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_PASS_END;
+}
+
+void CDcm::EncodeRec46()
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER46: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+ *( m_pbtCurr++ ) = DCM_SAME_AS_BEFORE;
+}
+
+void CDcm::EncodeRec( BOOL bIsFirstSector )
+{
+ #ifdef _DCM_DUMP_
+ printf( "ER: %08lX\n", m_pbtCurr - m_pbtPass );
+ #endif
+
+ m_pbtLastRec = m_pbtCurr;
+
+ BYTE abtBuff41[ 0x300 ];
+ BYTE abtBuff43[ 0x300 ];
+ BYTE abtBuff44[ 0x300 ];
+ BYTE* abtBuff47 = m_abtCurrBuff;
+
+ int iEnd41 = 0x300;
+ int iEnd43 = 0x300;
+ int iEnd44 = 0x300;
+
+ int iBestMethod = DCM_UNCOMPRESSED;
+ int iBestEnd = m_iSectorSize;
+ BYTE* pbtBest = abtBuff47;
+
+ EncodeRec43( abtBuff43, &iEnd43, m_abtCurrBuff, m_iSectorSize );
+
+ if ( !bIsFirstSector )
+ {
+ EncodeRec41( abtBuff41, &iEnd41, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ EncodeRec44( abtBuff44, &iEnd44, m_abtCurrBuff, m_abtPrevBuff, m_iSectorSize );
+ }
+
+ if ( iEnd41 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_BEGIN;
+ iBestEnd = iEnd41;
+ pbtBest = abtBuff41;
+ }
+
+ if ( iEnd43 < iBestEnd )
+ {
+ iBestMethod = DCM_COMPRESSED;
+ iBestEnd = iEnd43;
+ pbtBest = abtBuff43;
+ }
+
+ if ( iEnd44 < iBestEnd )
+ {
+ iBestMethod = DCM_CHANGE_END;
+ iBestEnd = iEnd44;
+ pbtBest = abtBuff44;
+ }
+
+ *( m_pbtCurr++ ) = iBestMethod;
+ memcpy( m_pbtCurr, pbtBest, iBestEnd );
+ m_pbtCurr += iBestEnd;
+}
+
+void CDcm::EncodeRec41( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc + iSrcLen - 1;
+ pbtSrcOld += iSrcLen - 1;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS-- ) != * ( pbtSrcOld-- ) )
+ break;
+ }
+
+ pbtS++;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+
+ int iBytes = pbtS - pbtSrc + 1;
+
+ while( iBytes-- )
+ {
+ *( pbtD++ ) = *( pbtS-- );
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec43( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, int iSrcLen )
+{
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+ BYTE* pbtCur = pbtSrc;
+
+ BYTE* pbtD = pbtDest;
+
+ while( pbtCur < pbtEnd )
+ {
+ BOOL bFound = FALSE;
+
+ for( BYTE* pbtNow = pbtCur; pbtNow < ( pbtEnd - 2 ); pbtNow++ )
+ {
+
+ if ( ( *pbtNow == *(pbtNow+1) ) && ( *pbtNow == *(pbtNow+2) ) )
+ {
+ int iUnc = pbtNow - pbtCur;
+
+ *( pbtD ++ ) = pbtNow - pbtSrc;
+ if ( iUnc )
+ {
+ memcpy( pbtD, pbtCur, iUnc );
+ pbtD += iUnc;
+ }
+
+ BYTE bt = *pbtNow;
+ BYTE*p;
+ for( p = pbtNow + 1; p < pbtEnd; p++ )
+ {
+ if ( *p != bt )
+ break;
+ }
+
+ if ( p > pbtEnd )
+ p = pbtEnd;
+
+ *( pbtD++ ) = p - pbtSrc;
+ *( pbtD++ ) = bt;
+
+ pbtCur = p;
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if ( ( pbtCur >= pbtEnd - 2 ) || !bFound )
+ {
+ if ( pbtCur < pbtEnd )
+ {
+ *( pbtD++ ) = iSrcLen;
+ memcpy( pbtD, pbtCur, pbtEnd - pbtCur );
+ pbtD += pbtEnd - pbtCur;
+ }
+
+ break;
+ }
+
+ }
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+void CDcm::EncodeRec44( BYTE* pbtDest, int* piDestLen, BYTE* pbtSrc, BYTE* pbtSrcOld, int iSrcLen )
+{
+ BYTE* pbtS = pbtSrc;
+ BYTE* pbtEnd = pbtSrc + iSrcLen;
+
+ BYTE* pbtD = pbtDest;
+
+ for( int i = 0; i < iSrcLen; i++ )
+ {
+ if ( *( pbtS++ ) != * ( pbtSrcOld++ ) )
+ break;
+ }
+
+ pbtS--;
+
+ *( pbtD++ ) = pbtS - pbtSrc;
+ memcpy( pbtD, pbtS, pbtEnd - pbtS );
+ pbtD += pbtEnd - pbtS;
+
+ *piDestLen = pbtD - pbtDest;
+}
+
+#endif // __CDISK_WRITE__
+
diff --git a/jindroush/lib/cdsk_scp.cpp b/jindroush/lib/cdsk_scp.cpp
new file mode 100644
index 0000000..eb2e0f2
--- /dev/null
+++ b/jindroush/lib/cdsk_scp.cpp
@@ -0,0 +1,279 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_scp.h"
+#include "autil.h"
+#include "cfile.h"
+
+#define SCP_MAGIC 0xFDFD
+
+CScp::CScp() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp constructed: %08X\n", this );
+ #endif
+}
+
+CScp::~CScp()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CScp destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CScp::Load( char* szFname, BOOL, BOOL )
+{
+ WORD wMagic;
+ BYTE btSectorSize;
+ BYTE btTracks;
+ BYTE btSectorsPerTrack;
+
+ CFile cf;
+
+ if( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ wMagic = cf.readLEw();
+
+ if ( wMagic != SCP_MAGIC )
+ {
+ sprintf( m_szLastError, "SCP: File '%s' is not an SCP file!", szFname );
+ return FALSE;
+ }
+
+ btSectorSize = cf.readb();
+ btTracks = cf.readb();
+ btSectorsPerTrack = cf.readb();
+
+ int iSectorSize;
+
+ switch( btSectorSize )
+ {
+ case 0x80:
+ iSectorSize = 0x80;
+ break;
+
+ case 0x00:
+ iSectorSize = 0x100;
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "SCP: Invalid sector size: %02X", btSectorSize );
+ return FALSE;
+ }
+ }
+
+ DISK_GEOMETRY dg;
+ dg.iSides = 1;
+ dg.iTracks = btTracks;
+ dg.iSectorsPerTrack = btSectorsPerTrack;
+ dg.iBytesPerSector = iSectorSize;
+
+ if ( !Format( &dg ) )
+ return FALSE;
+
+ BYTE *pbtTable = new BYTE [ btSectorsPerTrack * btTracks ];
+
+ if ( ! pbtTable )
+ {
+ sprintf( m_szLastError, "SCP: Not enough memory for sector table!" );
+ return FALSE;
+ }
+
+ if ( !cf.Read( pbtTable, btSectorsPerTrack * btTracks ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't read sector table!" );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ BYTE* pbtPtr = pbtTable;
+
+ for( int iTrack = 0; iTrack < btTracks; iTrack++ )
+ {
+ for( int iSector = 0; iSector < btSectorsPerTrack; iSector++ )
+ {
+ if ( *pbtPtr )
+ {
+ int iNowRead;
+
+ if ( !iTrack && ( iSector < 3 ) )
+ iNowRead = 0x80;
+ else
+ iNowRead = iSectorSize;
+
+ int iReallyRead;
+
+ if ( !cf.Read( abtBuff, iNowRead, &iReallyRead ) || ( iNowRead != iReallyRead ) )
+ {
+ delete [] pbtTable;
+ sprintf( m_szLastError, "SCP: Image broken!" );
+ return FALSE;
+ }
+
+ if ( !WriteSector( *pbtPtr + iTrack* btSectorsPerTrack, abtBuff ) )
+ {
+ delete [] pbtTable;
+ return FALSE;
+ }
+
+ }
+ pbtPtr++;
+ }
+
+ }
+
+ delete [] pbtTable;
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CScp::Save( char* szOutFile, BOOL bOverWrite )
+{
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "SCP: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE btSize;
+ BYTE btTracks;
+ BYTE btSpT;
+
+ switch ( m_geometry.iBytesPerSector )
+ {
+ case 0x80:
+ btSize = 0x80;
+ break;
+
+ case 0x100:
+ default:
+ btSize = 0x00;
+ break;
+ }
+
+ BOOL bGood = FALSE;
+
+ btTracks = m_geometry.iTracks;
+ btSpT = m_geometry.iSectorsPerTrack;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 18 ) )
+ bGood = TRUE;
+
+ if ( ( m_geometry.iTracks == 40 ) && ( m_geometry.iSectorsPerTrack == 26 ) )
+ bGood = TRUE;
+
+ if ( !bGood )
+ {
+ sprintf( m_szLastError, "SCP: Can't export, because of invalid disk size!" );
+ return FALSE;
+ }
+
+ int iMapSize = m_geometry.iTracks * m_geometry.iSectorsPerTrack;
+
+ BYTE* pMap = new BYTE [ iMapSize ];
+
+ if ( !pMap )
+ {
+ sprintf( m_szLastError, "SCP: Can't allocate memory for map!" );
+ return FALSE;
+ }
+
+ memset( pMap, 0, iMapSize );
+
+
+ CFile cf;
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't create '%s'", szOutFile );
+ delete [] pMap;
+ return FALSE;
+ }
+
+ WORD wMagic = SCP_MAGIC;
+
+ cf.writeLEw( wMagic );
+ cf.writeb( btSize );
+ cf.writeb( btTracks );
+ cf.writeb( btSpT );
+
+ cf.Seek( iMapSize, SEEK_CUR );
+
+ BYTE abtBuff[ 0x100 ];
+
+ int iSectors = m_geometry.iSectors;
+
+ for( int i = 0; i < iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i + 1 ) )
+ {
+ delete [] pMap;
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ int iBytesNow = ( i < 3 ) ? 0x80 : m_geometry.iBytesPerSector;
+
+ if ( !IsBlockEmpty( abtBuff, iBytesNow ) )
+ {
+ int iWritten;
+ if ( !cf.Write( abtBuff, iBytesNow, &iWritten ) || ( iBytesNow != iWritten ) )
+ {
+ sprintf( m_szLastError, "SCP: Error writing to '%s'", szOutFile );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ pMap[ i ] = ( i % btSpT ) + 1;
+ }
+ }
+
+ cf.Seek( 5, SEEK_SET );
+
+ if ( !cf.Write( pMap, iMapSize ) )
+ {
+ sprintf( m_szLastError, "SCP: Can't write!" );
+ delete [] pMap;
+ cf.Close( );
+ unlink( szOutFile );
+ return FALSE;
+
+ }
+
+ delete [] pMap;
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/cdsk_xfd.cpp b/jindroush/lib/cdsk_xfd.cpp
new file mode 100644
index 0000000..aecaeb2
--- /dev/null
+++ b/jindroush/lib/cdsk_xfd.cpp
@@ -0,0 +1,334 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cdsk_xfd.h"
+#include "autil.h"
+#include "cfile.h"
+
+CXfd::CXfd() : CDisk()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd constructed: %08X\n", this );
+ #endif
+}
+
+CXfd::~CXfd()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CXfd destructed: %08X\n", this );
+ #endif
+}
+
+typedef enum
+{
+ LOAD_OK,
+ LOAD_BAD_DD_1,
+ LOAD_BAD_DD_2,
+ LOAD_BAD_DD_3
+} LOAD_VARIANT;
+
+BOOL CXfd::Load( char* szFname, BOOL bRepair, BOOL bRepairAuto )
+{
+ LOAD_VARIANT load_method = LOAD_OK;
+
+ int iFirstSectorsSize = 0x80;
+
+ CFile cf;
+
+ if ( !cf.Open( szFname ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't open '%s'", szFname );
+ return FALSE;
+ }
+
+ strcpy( m_szFname, szFname );
+
+ LONG lFileLen = cf.GetLength();
+
+ int iSecs;
+ int iSecSize;
+
+ if ( lFileLen % 0x80 )
+ {
+ sprintf( m_szLastError, "XFD: Strange length!" );
+ cf.Close();
+ return FALSE;
+ }
+
+ if ( ( lFileLen / 0x80 ) > 1040 )
+ {
+ iSecSize = 0x100;
+
+ iSecs = ( ( lFileLen - 0x180 ) / 0x100 ) + 3;
+ }
+ else
+ {
+ iSecSize = 0x80;
+ iSecs = lFileLen / 0x80;
+ }
+
+ if ( ( ( ( iSecs - 3 ) * iSecSize ) + 0x180 ) != lFileLen )
+ {
+ sprintf( m_szLastError, "XFD: Format violated: (%08lX != %08X)", lFileLen, iSecs * iSecSize );
+ m_iErrorCode = CXFD_FORMAT_VIOLATED;
+
+ if ( !bRepair )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ else
+ {
+ iSecs = lFileLen / iSecSize;
+ BYTE abtBuff[ 0x100 ];
+
+ memset( abtBuff, 0, 0x100 );
+
+ int iM1zeroes = 3;
+ int iM2zeroes = 3;
+ int iM3zeroes = 3;
+
+ cf.Seek( ( 0x02 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM1zeroes--;
+
+ cf.Seek( ( 0x04 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( ( 0x05 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM2zeroes--;
+
+ cf.Seek( ( 0x06 - 1 ) * 0x80, SEEK_SET );
+ cf.Read( abtBuff, 0x80 );
+
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ {
+ iM1zeroes--;
+ iM2zeroes--;
+ }
+
+ cf.Seek( -0x180, SEEK_END );
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ cf.Read( abtBuff, 0x80 );
+ if ( IsBlockEmpty( abtBuff, 0x80 ) )
+ iM3zeroes--;
+
+ if ( !iM1zeroes )
+ {
+ load_method = LOAD_BAD_DD_1;
+ }
+ else if ( !iM2zeroes )
+ {
+ load_method = LOAD_BAD_DD_2;
+ }
+ else if ( !iM3zeroes )
+ {
+ load_method = LOAD_BAD_DD_3;
+ }
+
+ if ( !bRepairAuto )
+ {
+ printf( "Invalid DD ATR file encountered.\n" );
+ printf( "Choose repair method:\n" );
+ printf( "1) Sector, gap, sector, gap, sector, gap, data\n" );
+ printf( "2) Three sectors, three empty sectors, data\n" );
+ printf( "3) Data, three empty sectors\n" );
+ printf( "4) Don't repair\n" );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ printf( "(Method 1 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_2:
+ printf( "(Method 2 looks best)\n" );
+ break;
+
+ case LOAD_BAD_DD_3:
+ printf( "(Method 3 looks best)\n" );
+ break;
+
+ default:
+ break;
+ }
+
+ int iMethod;
+
+ printf( "\n" );
+ do
+ {
+ iMethod = getch() - '0';
+ } while( ( iMethod < 1 ) || ( iMethod > 4 ) );
+
+ if ( iMethod == 4 )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+ else
+ {
+ if ( load_method == LOAD_OK )
+ load_method = LOAD_BAD_DD_1;
+ }
+
+ cf.Seek( 0, SEEK_SET );
+
+ switch( load_method )
+ {
+ case LOAD_BAD_DD_1:
+ case LOAD_BAD_DD_2:
+ iFirstSectorsSize = 0x100;
+ break;
+
+ default:
+ break;
+
+ }
+
+
+ }
+ }
+
+ DISK_GEOMETRY dg;
+
+ GuessClassicSizes( iSecs, iSecSize, &dg );
+
+ if ( !Format( &dg ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+ memset( abtBuff, 0, 0x100 );
+
+ for( int i = 0; i < iSecs; i++ )
+ {
+ switch( load_method )
+ {
+ default:
+ case LOAD_OK:
+ cf.Read( abtBuff, ( i < 3 ) ? 0x80 : iSecSize );
+ break;
+
+ case LOAD_BAD_DD_1:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+ cf.Seek( 0x80, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+ break;
+
+ case LOAD_BAD_DD_2:
+ if ( i < 3 )
+ {
+ cf.Read( abtBuff, 0x80 );
+
+ if ( i == 2 )
+ cf.Seek( 0x180, SEEK_CUR );
+ }
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+
+ case LOAD_BAD_DD_3:
+ if ( i < 3 )
+ cf.Read( abtBuff, 0x80 );
+ else
+ cf.Read( abtBuff, 0x100 );
+
+ break;
+ }
+
+ if ( !WriteSector( i + 1, abtBuff ) )
+ {
+ cf.Close();
+ return FALSE;
+ }
+ }
+
+ cf.Close();
+ return TRUE;
+
+}
+
+#ifdef __CDISK_WRITE__
+
+BOOL CXfd::Save( char* szOutFile, BOOL bOverWrite )
+{
+ CFile cf;
+
+ if ( !bOverWrite && !access( szOutFile, F_OK ) )
+ {
+ sprintf( m_szLastError, "XFD: File already exists! '%s'", szOutFile );
+ return FALSE;
+ }
+
+ if ( !cf.Create( szOutFile ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't create '%s'", szOutFile );
+ return FALSE;
+ }
+
+ BYTE abtBuff[ 0x100 ];
+
+ for( WORD i = 1; i <= m_geometry.iSectors; i++ )
+ {
+ if ( !ReadSector( abtBuff, i ) )
+ return FALSE;
+
+ int iToWrite = ( i <= 3 ) ? 0x80: m_geometry.iBytesPerSector;
+
+ int iWritten;
+
+ if ( !cf.Write( abtBuff, iToWrite, &iWritten ) || ( iWritten != iToWrite ) )
+ {
+ sprintf( m_szLastError, "XFD: Can't write!" );
+ cf.Close();
+ unlink( szOutFile );
+ return FALSE;
+ }
+
+ }
+
+ cf.Close();
+
+ return TRUE;
+}
+
+#endif //__CDISK_WRITE__
diff --git a/jindroush/lib/cfile.cpp b/jindroush/lib/cfile.cpp
new file mode 100644
index 0000000..97a78d2
--- /dev/null
+++ b/jindroush/lib/cfile.cpp
@@ -0,0 +1,139 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfile.h"
+
+CFile::CFile()
+{
+ m_bOpened = FALSE;
+ m_hFile = 0;
+ m_bIsDirty = FALSE;
+}
+
+CFile::~CFile()
+{
+ Close();
+}
+
+//opens file for reading, binary
+BOOL CFile::Open( char* szName )
+{
+ if ( m_bOpened )
+ return FALSE;
+
+ m_hFile = open( szName, O_BINARY | O_RDONLY );
+
+ if ( m_hFile == -1 )
+ {
+ m_hFile = 0;
+
+ //printf( "CFile::Open %s Err:%d\n", szName, errno );
+
+ return FALSE;
+ }
+
+ m_bOpened = TRUE;
+
+ m_lLength = lseek( m_hFile, 0, SEEK_END );
+ lseek( m_hFile, 0, SEEK_SET );
+
+ return TRUE;
+
+}
+
+//creates new file, opened for rdwr, binary, deletes existing
+BOOL CFile::Create( char* szName )
+{
+ if ( m_bOpened )
+ return FALSE;
+
+ m_bIsDirty = FALSE;
+ m_hFile = open( szName, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666 );
+
+ if ( m_hFile == -1 )
+ {
+ m_hFile = 0;
+ return FALSE;
+ }
+
+ m_bOpened = TRUE;
+
+ m_lLength = lseek( m_hFile, 0, SEEK_END );
+ lseek( m_hFile, 0, SEEK_SET );
+
+ return TRUE;
+
+}
+
+//reads iBytesToRead bytes to buffer
+BOOL CFile::Read( void* pBuff, int iBytesToRead, int* piBytesRead )
+{
+ if ( !m_bOpened )
+ return FALSE;
+
+ m_bIsDirty = FALSE;
+ int iBytesRead = read( m_hFile, pBuff, iBytesToRead );
+
+ if ( piBytesRead )
+ *piBytesRead = iBytesRead;
+
+ if ( -1 == iBytesRead )
+ return FALSE;
+
+ m_lCurrPtr = tell( m_hFile );
+
+ return TRUE;
+}
+
+//writes iBytesToWrite from buffer
+//TODO:check for file being opened for writing
+BOOL CFile::Write( void* pBuff, int iBytesToWrite, int* piBytesWritten )
+{
+ if ( !m_bOpened )
+ return FALSE;
+
+ int iBytesWritten = write( m_hFile, pBuff, iBytesToWrite );
+
+ if ( piBytesWritten )
+ *piBytesWritten = iBytesWritten;
+
+ if ( -1 == iBytesWritten )
+ return FALSE;
+
+ m_lCurrPtr = tell( m_hFile );
+ m_bIsDirty = TRUE;
+
+ return TRUE;
+}
+
+//seek
+BOOL CFile::Seek( long lPos, int iType )
+{
+ m_lCurrPtr = lseek( m_hFile, lPos, iType );
+
+ return TRUE;
+}
+
+//closes the file
+void CFile::Close()
+{
+ if ( m_hFile )
+ close( m_hFile );
+
+ m_bIsDirty = FALSE;
+ m_hFile = 0;
+ m_bOpened = FALSE;
+}
+
diff --git a/jindroush/lib/cfs.cpp b/jindroush/lib/cfs.cpp
new file mode 100644
index 0000000..17de630
--- /dev/null
+++ b/jindroush/lib/cfs.cpp
@@ -0,0 +1,69 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs.h"
+
+CDirEntry::CDirEntry()
+{
+ *m_szFname = '\0';
+ *m_szAscData = '\0';
+ m_dwFlags = 0;
+ m_pSubdir = NULL;
+ m_pNext = NULL;
+ m_pPrev = NULL;
+
+ #ifdef _MEMORY_DUMP_
+ printf( "CDirEntry constructed: %08X\n", this );
+ #endif
+}
+
+CDirEntry::~CDirEntry()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDirEntry destructed: %08X\n", this );
+ #endif
+}
+
+CFs::CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CFs constructed: %08X\n", this );
+ #endif
+}
+
+CFs::~CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CFs destructed: %08X\n", this );
+ #endif
+}
+
+void CFs::DeleteList( CDirEntry* pList )
+{
+ CDirEntry* pCurr = pList;
+ CDirEntry* pNext;
+
+ while( pCurr )
+ {
+ if ( pCurr->m_pSubdir )
+ DeleteList( pCurr->m_pSubdir );
+
+ pNext = pCurr->m_pNext;
+ delete pCurr;
+
+ pCurr = pNext;
+ }
+}
+
diff --git a/jindroush/lib/cfs_b2b.cpp b/jindroush/lib/cfs_b2b.cpp
new file mode 100644
index 0000000..8b62ded
--- /dev/null
+++ b/jindroush/lib/cfs_b2b.cpp
@@ -0,0 +1,156 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_b2b.h"
+#include "autil.h"
+
+CBas2Boot::CBas2Boot() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CBas2Boot constructed: %08X\n", this );
+ #endif
+}
+
+CBas2Boot::~CBas2Boot()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CBas2Boot destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CBas2Boot::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ m_pRoot = CreateEntry();
+
+ return m_pRoot ? TRUE : FALSE;
+}
+
+void CBas2Boot::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CBas2BootDirEntry* CBas2Boot::CreateEntry()
+{
+ CBas2BootDirEntry* pE = new CBas2BootDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSector( abtSec, 1 ) )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ pE->m_dwFileLen = abtSec[ 8 ] + ( abtSec[ 9 ] << 8 );
+
+ if ( !m_pDisk->ReadSector( abtSec, 2 ) )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ int iSectors = ( ( pE->m_dwFileLen - 0x0E + 0x7F ) / 0x80 );
+ int iStoredSectors = abtSec[ 0x70 ] + ( abtSec[ 0x71 ] << 8 );
+
+ if ( ( iSectors - 1 ) != iStoredSectors )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Not a Bas2Boot image or invalid! (%d<>%d)", iSectors - 1, iStoredSectors );
+ delete pE;
+ return NULL;
+ }
+
+
+ if ( ( iSectors + 2 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Not a Bas2Boot image or invalid! (%d<>%d)", iSectors + 2, m_pDisk->GetSectorCount() );
+ delete pE;
+ return NULL;
+ }
+
+ sprintf( pE->m_szAscData, "%06lX", pE->m_dwFileLen );
+
+ GuessBestFnameFromPC( pE->m_szFname, m_pDisk->GetImageName(), "bas" );
+
+ return pE;
+}
+
+BOOL CBas2Boot::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ DWORD dwFileLen = ((CBas2BootDirEntry*)pDirE) ->m_dwFileLen;
+
+ BYTE abtBuff[ 0x80 ];
+
+ int iSector = 3;
+
+ m_pDisk->ReadSector( abtBuff, 2 );
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff + 0x72, 0x0E );
+
+ dwFileLen -= 0xE;
+
+ while( dwFileLen )
+ {
+ WORD wToCopy = ( dwFileLen < 0x80 ) ? dwFileLen : 0x80;
+
+ if ( !m_pDisk->ReadSector( abtBuff, iSector ) )
+ {
+ sprintf( m_szLastError, "BAS2BOOT: Can't read sector because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, wToCopy );
+
+ dwFileLen -= wToCopy;
+ iSector++;
+
+ }
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_boot.cpp b/jindroush/lib/cfs_boot.cpp
new file mode 100644
index 0000000..b1279ac
--- /dev/null
+++ b/jindroush/lib/cfs_boot.cpp
@@ -0,0 +1,128 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_boot.h"
+#include "autil.h"
+#include "adsk_xfd.h"
+
+CBoot::CBoot() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CBoot constructed: %08X\n", this );
+ #endif
+}
+
+CBoot::~CBoot()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CBoot destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CBoot::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ m_pRoot = CreateEntry();
+
+ return m_pRoot ? TRUE : FALSE;
+}
+
+void CBoot::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CBootDirEntry* CBoot::CreateEntry()
+{
+ CBootDirEntry* pE = new CBootDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iSectorCount = m_pDisk->GetBootSectorCount();
+
+ if ( pE->m_iSectorCount > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "BOOT: Overlaps end of file!" );
+ delete pE;
+ return NULL;
+ }
+
+ sprintf( pE->m_szAscData, "%08X", pE->m_iSectorCount );
+
+ GuessBestFnameFromPC( pE->m_szFname, m_pDisk->GetImageName(), "xfd", "_boot" );
+
+ return pE;
+}
+
+BOOL CBoot::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ if ( !szOutFile )
+ return TRUE;
+
+ CXfd newdisk;
+
+ DISK_GEOMETRY dg;
+
+ int iSecCount = ((CBootDirEntry*)pDirE)->m_iSectorCount;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iStartSec = 1;
+ int iCurrSec = 1;
+
+ BYTE abtBuff[ MAX_ATARI_SECTOR_LEN ];
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "BOOT: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_dos2.cpp b/jindroush/lib/cfs_dos2.cpp
new file mode 100644
index 0000000..81a8037
--- /dev/null
+++ b/jindroush/lib/cfs_dos2.cpp
@@ -0,0 +1,224 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_dos2.h"
+#include "autil.h"
+
+#define ROOT_DIR 361
+
+CDos2::CDos2() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos2 constructed: %08X\n", this );
+ #endif
+}
+
+CDos2::~CDos2()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos2 destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDos2::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ DOS2_DIRENT dire;
+
+ WORD wEntry = 0;
+
+ CDos2DirEntry* pPrev = NULL;
+
+ do
+ {
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSector( abtSec, ROOT_DIR + ( wEntry / 8 ) ) )
+ {
+ sprintf( m_szLastError, "DOS2: Can't read directory entry %04X because\n%s", wEntry, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ //this is not endian-safe
+ //memcpy( &dire, abtSec + ( wEntry % 8) * sizeof( DOS2_DIRENT ), sizeof( DOS2_DIRENT ) );
+ BYTE* pTmp = abtSec + ( wEntry % 8) * sizeof( DOS2_DIRENT );
+ dire.btFlags = MGET_B( pTmp );
+ dire.wSecCount = MGET_LEW( pTmp );
+ dire.wSecStart = MGET_LEW( pTmp );
+ memcpy( dire.acAtariName, pTmp, 11 );
+
+ if ( !dire.btFlags )
+ break;
+
+ CDos2DirEntry* pE = CreateEntry( &dire, wEntry );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ wEntry++;
+
+ } while( dire.btFlags && ( wEntry < 64 ) );
+
+ return TRUE;
+}
+
+void CDos2::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDos2DirEntry* CDos2::CreateEntry( DOS2_DIRENT* pDire, WORD wEntry )
+{
+ CDos2DirEntry* pE = new CDos2DirEntry();
+
+ if ( !pE )
+ {
+ sprintf( m_szLastError, "DOS2: Can't allocate memory for directory!" );
+ return NULL;
+ }
+
+ if ( pDire->btFlags == 0x80 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ sprintf( pE->m_szAscData, "%02X %04X %04X", pDire->btFlags, pDire->wSecStart, pDire->wSecCount );
+
+ pE->m_wFileNumber = wEntry;
+ pE->m_btFlags = pDire->btFlags;
+ pE->m_wSecStart = pDire->wSecStart;
+ pE->m_wSecCount = pDire->wSecCount;
+
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CDos2::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOS2: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ BYTE abtBuff[ 0x0100 ];
+
+ WORD wSector = ((CDos2DirEntry*)pDirE ) -> m_wSecStart;
+ WORD wCount = ((CDos2DirEntry*)pDirE ) -> m_wSecCount;
+ WORD wSectorSize = m_pDisk->GetSectorSize();
+ WORD wFileNumber = ((CDos2DirEntry*)pDirE ) -> m_wFileNumber;
+
+ abtBuff[ wSectorSize - 1 ] = 0;
+
+ while( wCount )
+ {
+ if ( wSector < 1 )
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (invalid sector %04X)", szOutFile, wSector );
+ return FALSE;
+ }
+
+ if ( ( abtBuff[ wSectorSize - 1 ] & 0x80 ) && ( wSectorSize == 0x80 ) )
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (unexpected EOF)", szOutFile );
+ return FALSE;
+ }
+
+ if ( !m_pDisk->ReadSector( abtBuff, wSector ) )
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s'\n%s\n", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ /*
+ if ( -1 != hOutfile )
+ {
+ printf( "%04X/%04X %02X | %02X %02X %02X\n",
+ wSector,
+ wCount,
+ wFileNumber,
+ abtBuff[ wSectorSize - 3 ],
+ abtBuff[ wSectorSize - 2 ],
+ abtBuff[ wSectorSize - 1 ] );
+ }
+ */
+
+ wSector = abtBuff[ wSectorSize - 2 ] + ( 0x03 & abtBuff[ wSectorSize - 3 ] ) * 0x100;
+
+ if ( ( abtBuff[ wSectorSize-3 ] >> 2 ) != wFileNumber )
+ {
+ WORD wFN = abtBuff[ wSectorSize - 3 ] >> 2;
+
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (167: file number mismatch [%04X != %04X])", szOutFile, wFileNumber, wFN );
+ return FALSE;
+ }
+
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, abtBuff[ wSectorSize - 1 ] );
+
+ wCount--;
+ }
+
+ if ( ((CDos2DirEntry*)pDirE ) -> m_wSecCount )
+ {
+ if ( ! ( abtBuff[ wSectorSize - 1 ] & 128 ) && ( wSectorSize == 128 ) && wSector)
+ {
+ sprintf( m_szLastError, "DOS2: Corrupted file '%s' (expected EOF, code %02X, next sector %04X)", szOutFile, abtBuff[ wSectorSize - 1 ], wSector );
+ return FALSE;
+ }
+ }
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_dos3.cpp b/jindroush/lib/cfs_dos3.cpp
new file mode 100644
index 0000000..2eca4b2
--- /dev/null
+++ b/jindroush/lib/cfs_dos3.cpp
@@ -0,0 +1,209 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_dos3.h"
+#include "autil.h"
+
+#define ROOT_DIR 0x10
+#define FAT 0x18
+
+CDos3::CDos3() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos3 constructed: %08X\n", this );
+ #endif
+}
+
+CDos3::~CDos3()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDos3 destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDos3::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "DOS3: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ CDos3DirEntry* pPrev = NULL;
+
+ DOS3_DIRENT dire;
+
+ WORD wEntry = 1;
+
+ if ( !pDisk->ReadSector( m_abtFat, FAT ) )
+ {
+ sprintf( m_szLastError, "DOS3: Can't read FAT sector because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ do
+ {
+ BYTE abtSec[ 0x100 ];
+
+ if ( !pDisk->ReadSector( abtSec, ROOT_DIR + ( wEntry / 8 ) ) )
+ {
+ sprintf( m_szLastError, "DOS3: Can't read directory entry %04X because\n%s", wEntry, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ memcpy( &dire, abtSec + ( wEntry % 8) * sizeof( DOS3_DIRENT ), sizeof( DOS3_DIRENT ) );
+
+ if ( !dire.btFlags )
+ break;
+
+ CDos3DirEntry* pE = CreateEntry( &dire );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ wEntry++;
+
+ } while( dire.btFlags );
+
+ return TRUE;
+}
+
+void CDos3::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDos3DirEntry* CDos3::CreateEntry( DOS3_DIRENT* pDire )
+{
+ CDos3DirEntry* pE = new CDos3DirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ if ( pDire->btFlags == 0x80 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ //sprintf( pE->m_szAscData, "%02X %02X %02X %04X", pDire->btSecStart, pDire->btSecCount, pDire->btFlags, pDire->wFileLen );
+ sprintf( pE->m_szAscData, "%02X %04X", pDire->btFlags, pDire->wFileLen );
+
+ pE->m_btSecStart = pDire->btSecStart;
+ pE->m_btSecCount = pDire->btSecCount;
+ pE->m_btFlags = pDire->btFlags;
+ pE->m_wFileLen = pDire->wFileLen;
+
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CDos3::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOS3: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ BYTE abtBuff[ 0x80 * 8 ];
+
+ BYTE btSecCount = ((CDos3DirEntry*)pDirE) ->m_btSecCount;
+ BYTE btSector = ((CDos3DirEntry*)pDirE) ->m_btSecStart;
+ WORD wFileLen = ((CDos3DirEntry*)pDirE) ->m_wFileLen;
+
+ while( btSecCount )
+ {
+ WORD wToCopy = ( wFileLen < 0x400 ) ? wFileLen : 0x400;
+
+ if ( !m_pDisk->ReadSectors( abtBuff, ( btSector * 8 ) + FAT + 1, 8 ) )
+ {
+ {
+ sprintf( m_szLastError, "DOS3: Corrupted file '%s'\n%s\n", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, wToCopy );
+
+ btSecCount--;
+ wFileLen -= wToCopy;
+
+ btSector = m_abtFat[ btSector ];
+
+ if ( wToCopy == 0x400 )
+ {
+ if ( btSector >= 0xFD )
+ {
+ sprintf( m_szLastError, "DOS3: Corrupted file '%s' (unexpected EOF)", szOutFile );
+ return FALSE;
+ }
+
+ }
+ else
+ {
+ if ( btSector != 0xFD )
+ {
+ sprintf( m_szLastError, "DOS3: Corrupted file '%s' (missed EOF) %02X", szOutFile, btSector );
+ return FALSE;
+ }
+
+ }
+
+
+ }
+
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_dosm.cpp b/jindroush/lib/cfs_dosm.cpp
new file mode 100644
index 0000000..96c04fb
--- /dev/null
+++ b/jindroush/lib/cfs_dosm.cpp
@@ -0,0 +1,240 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_dosm.h"
+#include "autil.h"
+
+#define ROOT_DIR 361
+
+CDosM::CDosM() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosM constructed: %08X\n", this );
+ #endif
+}
+
+CDosM::~CDosM()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosM destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDosM::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ return ReadDir( ROOT_DIR, (CDosMDirEntry**)&m_pRoot );
+}
+
+BOOL CDosM::ReadDir( int iSector, CDosMDirEntry** ppRoot )
+{
+ DOSM_DIRENT dire;
+
+ WORD wEntry = 0;
+
+ CDosMDirEntry* pPrev = NULL;
+
+ do
+ {
+ BYTE abtSec[ 0x100 ];
+
+ //printf( "reading sec %d\n", iSector + ( wEntry / 8 ) );
+
+ if ( !m_pDisk->ReadSector( abtSec, iSector + ( wEntry / 8 ) ) )
+ {
+ sprintf( m_szLastError, "DOSM: Can't read directory entry %04X because\n%s", wEntry, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ //this is not endian-safe
+ //memcpy( &dire, abtSec + ( wEntry % 8) * sizeof( DOSM_DIRENT ), sizeof( DOSM_DIRENT ) );
+ BYTE* pTmp = abtSec + ( wEntry % 8) * sizeof( DOSM_DIRENT );
+ dire.btFlags = MGET_B( pTmp );
+ dire.wSecCount = MGET_LEW( pTmp );
+ dire.wSecStart = MGET_LEW( pTmp );
+ memcpy( dire.acAtariName, pTmp, 11 );
+
+ //printf( "%p %p %04X %02X\n", pTmp, abtSec, wEntry, dire.btFlags );
+
+ if ( !dire.btFlags )
+ break;
+
+ CDosMDirEntry* pE = CreateEntry( &dire );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( *ppRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ *ppRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ wEntry++;
+
+ } while( dire.btFlags && ( wEntry < 64 ) );
+
+ return TRUE;
+}
+
+void CDosM::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDosMDirEntry* CDosM::CreateEntry( DOSM_DIRENT* pDire )
+{
+ CDosMDirEntry* pE = new CDosMDirEntry();
+
+ if ( !pE )
+ {
+ sprintf( m_szLastError, "DOSM: Can't allocate memory for directory!" );
+ return NULL;
+ }
+
+ if ( pDire->btFlags == 0x80 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ sprintf( pE->m_szAscData, "%02X %04X %04X", pDire->btFlags, pDire->wSecStart, pDire->wSecCount );
+ //printf( "%02X %04X %04X %s\n", pDire->btFlags, pDire->wSecStart, pDire->wSecCount, pE->m_szFname );
+
+ pE->m_btFlags = pDire->btFlags;
+ pE->m_wSecStart = pDire->wSecStart;
+ pE->m_wSecCount = pDire->wSecCount;
+
+ if ( pDire->btFlags == 0x10 )
+ {
+ pE->m_dwFlags |= DIRE_SUBDIR;
+
+ BOOL bRes = ReadDir( pE->m_wSecStart, (CDosMDirEntry**)&pE->m_pSubdir );
+
+ if ( !bRes )
+ return NULL;
+ }
+ else
+ {
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ {
+ m_iFilesValid++;
+ }
+ else
+ {
+ m_iFilesInvalid++;
+ }
+ }
+
+ return pE;
+}
+
+BOOL CDosM::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOSM: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ BYTE abtBuff[ 0x0100 ];
+
+ WORD wSector = ((CDosMDirEntry*)pDirE ) -> m_wSecStart;
+ WORD wCount = ((CDosMDirEntry*)pDirE ) -> m_wSecCount;
+ WORD wSectorSize = m_pDisk->GetSectorSize();
+
+ abtBuff[ wSectorSize - 1 ] = 0;
+
+ while( wCount )
+ {
+ if ( wSector < 1 )
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s' (invalid sector %04X)", szOutFile, wSector );
+ return FALSE;
+ }
+
+ if ( ( abtBuff[ wSectorSize - 1 ] & 0x80 ) && ( wSectorSize == 0x80 ) )
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s' (unexpected EOF)", szOutFile );
+ return FALSE;
+ }
+
+ if ( !m_pDisk->ReadSector( abtBuff, wSector ) )
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s'\n%s\n", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+// if ( -1 != hOutfile )
+// {
+// printf( "%04X/%04X | %02X %02X %02X\n",
+// wSector,
+// wCount,
+// abtBuff[ wSectorSize - 3 ],
+// abtBuff[ wSectorSize - 2 ],
+// abtBuff[ wSectorSize - 1 ] );
+// }
+
+ //originally, there was 0x07 as a mask, but megaimages were not working with it
+ if ( m_pDisk->GetSectorCount() > 943 )
+ wSector = abtBuff[ wSectorSize - 2 ] + ( (WORD)abtBuff[ wSectorSize - 3 ] & 0xff ) * 0x100;
+ else
+ wSector = abtBuff[ wSectorSize - 2 ] + ( 0x03 & (WORD)abtBuff[ wSectorSize - 3 ] ) * 0x100;
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, abtBuff[ wSectorSize - 1 ] );
+
+ wCount--;
+ }
+
+ if ( ((CDosMDirEntry*)pDirE ) -> m_wSecCount )
+ {
+ if ( ! ( abtBuff[ wSectorSize - 1 ] & 128 ) && ( wSectorSize == 128 ) && wSector)
+ {
+ sprintf( m_szLastError, "DOSM: Corrupted file '%s' (expected EOF, code %02X, next sector %04X)", szOutFile, abtBuff[ wSectorSize - 1 ], wSector );
+ return FALSE;
+ }
+ }
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_doss.cpp b/jindroush/lib/cfs_doss.cpp
new file mode 100644
index 0000000..42092ec
--- /dev/null
+++ b/jindroush/lib/cfs_doss.cpp
@@ -0,0 +1,383 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_doss.h"
+#include "autil.h"
+
+#define SP3TOLONG(dire) ( ( dire.btSizeHi << 16 ) + dire.wSizeLo )
+
+CDosS::CDosS() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosS constructed: %08X\n", this );
+ #endif
+}
+
+CDosS::~CDosS()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CDosS destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CDosS::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetBootSectorCount() != 3 )
+ {
+ sprintf( m_szLastError, "DOSS: Strange boot sector!" );
+ return FALSE;
+ }
+
+ int iSize = m_pDisk->GetBootSectorSize();
+
+ BYTE* pBoot = new BYTE [ iSize ];
+
+ if ( !pBoot )
+ {
+ sprintf( m_szLastError, "DOSS: Not enough memory to allocate boot sector!" );
+ return FALSE;
+ }
+
+ if ( !m_pDisk->GetBootSector( pBoot ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete [] pBoot;
+ return FALSE;
+ }
+
+ BYTE btSpDosIdent = pBoot[ 7 ];
+
+ if ( btSpDosIdent != 0x80 )
+ {
+ sprintf( m_szLastError, "DOSS: Mismatched boot." );
+ delete [] pBoot;
+ return FALSE;
+ }
+
+ m_wMainDirStart = pBoot[ 9 ] + ( pBoot[ 10 ] << 8 );
+ //WORD wSectors = pBoot[ 11 ] + ( pBoot[ 12 ] << 8 );
+ //WORD wFreeSectors = pBoot[ 13 ] + ( pBoot[ 14 ] << 8 );
+ //BYTE btBitmapSectors = pBoot[ 15 ];
+ //WORD wFirstBitmapSector = pBoot[ 16 ] + ( pBoot[ 17 ] << 8 );
+ //WORD wFreeDataSector = pBoot[ 18 ] + ( pBoot[ 19 ] << 8 );
+ //WORD wFreeDirSector = pBoot[ 20 ] + ( pBoot[ 21 ] << 8 );
+ //22-29 volume name
+
+ switch( pBoot[ 31 ] )
+ {
+ case 0:
+ m_wSectorSize = 0x100;
+ break;
+
+ case 0x80:
+ m_wSectorSize = 0x80;
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "DOSS: Unknown sector size %02X!", pBoot[ 31 ] );
+ delete [] pBoot;
+ return FALSE;
+ }
+
+ }
+
+ //BYTE btVersion = pBoot[ 32 ];
+ //BYTE btSeqNumber = pBoot[ 38 ];
+ //BYTE btRndNumber = pBoot[ 39 ];
+ //WORD wDosBootStart = pBoot[ 40 ] + ( pBoot[ 41 ] << 8 );
+
+ delete [] pBoot;
+
+ return ReadDir( m_wMainDirStart, (CDosSDirEntry**)&m_pRoot );
+}
+
+int CDosS::GetSectorLinkEntry( int iLink, int iSec )
+{
+ WORD awSector[ 0x80 ];
+
+ int iCurrLink = iLink;
+
+ int iDivisor = 0;
+ switch( m_wSectorSize )
+ {
+ case 0x80:
+ iDivisor = 0x3E;
+ break;
+
+ case 0x100:
+ iDivisor = 0x7E;
+ break;
+
+ default:
+ return 0;
+
+ }
+
+ int iSecNeeded = ( iSec / iDivisor ) + 1;
+
+ do
+ {
+ if ( !m_pDisk->ReadSector( awSector, iCurrLink ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read link sector because\n%s", m_pDisk->GetLastError() );
+ return 0;
+ }
+
+ iSecNeeded--;
+ //not endian-safe
+ //iCurrLink = awSector[ 0 ];
+ iCurrLink = MREAD_LEW( (BYTE*)awSector );
+ if ( iSec >= iDivisor )
+ iSec -= iDivisor;
+
+ } while( iSecNeeded );
+
+ //not endian-safe
+ //return awSector[ iSec + 2 ];
+ return MREAD_LEW( (BYTE*)(awSector + iSec + 2 ));
+}
+
+BOOL CDosS::ReadDir( int iSectorLink, CDosSDirEntry** ppRoot )
+{
+ DOSS_DIRENT dire;
+
+ BYTE abtSector[ 0x100 ];
+
+ int iSector = GetSectorLinkEntry( iSectorLink, 0 );
+
+ if ( !m_pDisk->ReadSector( abtSector, iSector ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read dir because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ //not endian safe
+ //memcpy( &dire, abtSector, sizeof( DOSS_DIRENT ) );
+ BYTE* pTmp = abtSector;
+ dire.btFlags = MGET_B( pTmp );
+ dire.wSector = MGET_LEW( pTmp );
+ dire.wSizeLo = MGET_LEW( pTmp );
+ dire.btSizeHi = MGET_B( pTmp );
+ memcpy( dire.acAtariName, pTmp, 11 ); pTmp+= 11;
+ memcpy( &dire.btDay, pTmp, 6 ); //dirty hack, copying last 6 byte values
+
+ int iDirLen = SP3TOLONG( dire );
+ BYTE* pDir = MapFile( iSectorLink, iDirLen );
+ if ( !pDir )
+ return FALSE;
+
+ int iEntries = iDirLen / sizeof( DOSS_DIRENT );
+
+ //if ( iDirLen != iEntries * (int)sizeof( DOSS_DIRENT ) )
+ //{
+ // UnMapFile( pDir );
+ // sprintf( m_szLastError, "DOSS: Dir size mismatch! (%04X<>%04X)\n",
+ // iDirLen,
+ // iEntries * (int)sizeof( DOSS_DIRENT )
+ // );
+ // return FALSE;
+ //}
+
+ CDosSDirEntry* pPrev = NULL;
+
+ for( int i = 1; i < iEntries; i++ )
+ {
+
+ DOSS_DIRENT dire2;
+ BYTE* pTmp = pDir + i * sizeof( DOSS_DIRENT );
+ dire2.btFlags = MGET_B( pTmp );
+ dire2.wSector = MGET_LEW( pTmp );
+ dire2.wSizeLo = MGET_LEW( pTmp );
+ dire2.btSizeHi = MGET_B( pTmp );
+ memcpy( dire2.acAtariName, pTmp, 11 ); pTmp+= 11;
+ memcpy( &dire2.btDay, pTmp, 6 ); //dirty hack, copying last 6 byte values
+
+ CDosSDirEntry* pE = CreateEntry( &dire2 );
+
+ if ( pE && ! ( pE->m_dwFlags & DIRE_DELETED ) )
+ {
+ if ( *ppRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ *ppRoot = pE;
+ pPrev = pE;
+ }
+
+ }
+
+ }
+
+ UnMapFile( pDir );
+
+ return TRUE;
+}
+
+void CDosS::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CDosSDirEntry* CDosS::CreateEntry( DOSS_DIRENT* pDire )
+{
+ CDosSDirEntry* pE = new CDosSDirEntry();
+
+ if ( !pE )
+ {
+ sprintf( m_szLastError, "DOSS: Can't allocate memory for directory!" );
+ return NULL;
+ }
+
+ ADos2MsDos( pE->m_szFname, pDire->acAtariName );
+
+ sprintf( pE->m_szAscData, "%02X %04X %02X%04X %02d-%02d-19%02d %2d:%02d.%02d",
+ pDire->btFlags,
+ pDire->wSector,
+ pDire->btSizeHi,
+ pDire->wSizeLo,
+ pDire->btMonth,
+ pDire->btDay,
+ pDire->btYear,
+ pDire->btHour,
+ pDire->btMinute,
+ pDire->btSecond
+ );
+
+ pE->m_iLength = ( pDire->btSizeHi << 16 ) + pDire->wSizeLo;
+ pE->m_iLinkSector = pDire->wSector;
+
+ if ( pDire->btFlags == 0x10 )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ if ( ! ( pDire->btFlags && 0x08 ) )
+ {
+ pE->m_dwFlags |= DIRE_DELETED;
+ }
+
+ if ( pDire->btFlags & 0x20 )
+ {
+ pE->m_dwFlags |= DIRE_SUBDIR;
+
+ BOOL bRes = ReadDir( pE->m_iLinkSector, (CDosSDirEntry**)&pE->m_pSubdir );
+
+ if ( !bRes )
+ {
+ delete pE;
+ return NULL;
+ }
+ }
+ else
+ {
+ if ( pE->m_dwFlags & DIRE_DELETED )
+ {
+ }
+ else if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+ }
+
+ return pE;
+}
+
+BOOL CDosS::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "DOSS: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ int iLinkSector = ((CDosSDirEntry*)pDirE ) -> m_iLinkSector;
+ int iLength = ((CDosSDirEntry*)pDirE ) -> m_iLength;
+
+ BYTE* pDir = MapFile( iLinkSector, iLength );
+
+ if ( !pDir )
+ {
+ return FALSE;
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, pDir, iLength );
+
+ UnMapFile( pDir );
+
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
+BYTE* CDosS::MapFile( int iLinkSector, int iLength )
+{
+ BYTE* pBuff = new BYTE [ iLength ];
+
+ if ( !pBuff )
+ return NULL;
+
+ int iLogSector = 0;
+
+ BYTE abtBuff[ 0x100 ];
+ BYTE * p = pBuff;
+
+ while( iLength )
+ {
+ int iToCopy = ( iLength > m_wSectorSize ) ? m_wSectorSize : iLength;
+
+ int iSector = GetSectorLinkEntry( iLinkSector, iLogSector );
+
+ if ( !m_pDisk->ReadSector( abtBuff, iSector ) )
+ {
+ sprintf( m_szLastError, "DOSS: Can't read file sector because\n%s", m_pDisk->GetLastError() );
+ delete [] pBuff;
+ return 0;
+ }
+
+ memcpy( p, abtBuff, iToCopy );
+ iLength -= iToCopy;
+ p += iToCopy;
+ iLogSector++;
+ }
+
+ return pBuff;
+}
+
+void CDosS::UnMapFile( BYTE * pBuff )
+{
+ if ( pBuff )
+ delete [] pBuff;
+}
diff --git a/jindroush/lib/cfs_howf.cpp b/jindroush/lib/cfs_howf.cpp
new file mode 100644
index 0000000..2fa71ae
--- /dev/null
+++ b/jindroush/lib/cfs_howf.cpp
@@ -0,0 +1,209 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_howf.h"
+#include "autil.h"
+#include "adsk_atr.h"
+
+#define HOWF_MAX_NAME 32
+#define HOWF_REASONABLE_NAME ( HOWF_MAX_NAME - 7 )
+
+CHowf::CHowf() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CHowf constructed: %08X\n", this );
+ #endif
+}
+
+CHowf::~CHowf()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CHowf destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CHowf::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "HOWF: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ switch( m_pDisk->GetBootSectorCount() )
+ {
+ case 0x0A:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "HOWF: Can't identify disk as a HowFen menu!" );
+ return FALSE;
+ }
+ }
+
+ CHowfDirEntry* pPrev = NULL;
+
+ BYTE abtSec[ 0xA * 0x80 ];
+
+ if ( !m_pDisk->ReadSectors( abtSec, 0x1, 0xA ) )
+ {
+ sprintf( m_szLastError, "HOWF: Can't read directory because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ BYTE* pbtName = abtSec + 0x89;
+ BYTE* abtStartSecLo = abtSec + 0x32A;
+ BYTE* abtStartSecHi = abtSec + 0x33E;
+
+ BYTE btRecords = abtSec[ 0x329 ];
+
+ for( int i = 0; i < btRecords; i++ )
+ {
+ WORD wStartSec = *abtStartSecLo + ( *abtStartSecHi << 8 );
+
+ if ( !wStartSec )
+ break;
+
+ CHowfDirEntry* pE = CreateEntry( wStartSec, pbtName );
+
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ abtStartSecLo++;
+ abtStartSecHi++;
+ pbtName += HOWF_MAX_NAME;
+ }
+
+ return TRUE;
+}
+
+void CHowf::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CHowfDirEntry* CHowf::CreateEntry( WORD wStartSec, BYTE* btName )
+{
+ CHowfDirEntry* pE = new CHowfDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iStartSec = wStartSec;
+
+ sprintf( pE->m_szAscData, "%04X", wStartSec );
+
+ char szTemp[ HOWF_REASONABLE_NAME + 1 ];
+ memcpy( szTemp, (char*)btName + 3, HOWF_REASONABLE_NAME );
+ szTemp[ HOWF_REASONABLE_NAME ] = '\0';
+
+ for( int i = 0; i < HOWF_REASONABLE_NAME; i++ )
+ {
+ char c = szTemp[ i ];
+ if ( ( c >= 0x00 ) && ( c <= 0x40 ) )
+ c += 0x20;
+
+ szTemp[ i ] = c;
+ }
+
+ GuessBestFnameFromAtari( pE->m_szFname, szTemp, "atr" );
+
+ if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CHowf::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int iSecCount;
+ int iStartSec = ((CHowfDirEntry*)pDirE) ->m_iStartSec;
+
+ BYTE abtBuff[ 0x80 ];
+
+ m_pDisk->ReadSector( abtBuff, iStartSec );
+
+ iSecCount = abtBuff[1];
+
+ if ( ( iStartSec + iSecCount - 1 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' goes past last sector!", szOutFile );
+ return FALSE;
+ }
+
+ if ( !szOutFile )
+ return TRUE;
+
+ CAtr newdisk;
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iCurrSec = 1;
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "HOWF: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_jonw.cpp b/jindroush/lib/cfs_jonw.cpp
new file mode 100644
index 0000000..6517bee
--- /dev/null
+++ b/jindroush/lib/cfs_jonw.cpp
@@ -0,0 +1,204 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_jonw.h"
+#include "autil.h"
+#include "adsk_atr.h"
+
+#define JONW_MAX_NAME 20
+
+CJonw::CJonw() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CJonw constructed: %08X\n", this );
+ #endif
+}
+
+CJonw::~CJonw()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CJonw destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CJonw::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "JONW: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ switch( m_pDisk->GetBootSectorCount() )
+ {
+ case 0x28:
+ case 0x29:
+ case 0x2F:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "JONW: Can't identify disk as a JonW menu!" );
+ return FALSE;
+ }
+ }
+
+ CJonwDirEntry* pPrev = NULL;
+
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSectors( abtSec, 0x30, 2 ) )
+ {
+ sprintf( m_szLastError, "JONW: Can't read directory because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ BYTE* abtSecCounts = abtSec;
+ BYTE* abtStartSecLo = abtSec + 10;
+ BYTE* abtStartSecHi = abtSec + 20;
+ BYTE* pbtName = abtSec + 30;
+
+ for( int i = 0; i < 10; i++ )
+ {
+ if ( ! *abtSecCounts )
+ break;
+
+ CJonwDirEntry* pE = CreateEntry( *abtSecCounts, *abtStartSecLo + ( *abtStartSecHi << 8 ), pbtName );
+
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ abtSecCounts++;
+ abtStartSecLo++;
+ abtStartSecHi++;
+ pbtName += JONW_MAX_NAME;
+ }
+
+ return TRUE;
+}
+
+void CJonw::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CJonwDirEntry* CJonw::CreateEntry( BYTE btSecCount, WORD wStartSec, BYTE* btName )
+{
+ CJonwDirEntry* pE = new CJonwDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iStartSec = wStartSec;
+ pE->m_iSecCount = btSecCount;
+
+ sprintf( pE->m_szAscData, "%04X %02X", wStartSec, btSecCount );
+
+ char szTemp[ 21 ];
+ strncpy( szTemp, (char*)btName, 20 );
+ szTemp[ 20 ] = '\0';
+
+ GuessBestFnameFromAtari( pE->m_szFname, szTemp, "atr" );
+
+ if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CJonw::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int iSecCount = ((CJonwDirEntry*)pDirE) ->m_iSecCount;
+ int iStartSec = ((CJonwDirEntry*)pDirE) ->m_iStartSec;
+
+ BYTE abtBuff[ 0x80 ];
+
+ if ( ( iStartSec + iSecCount - 1 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' goes past last sector!", szOutFile );
+ return FALSE;
+ }
+
+ m_pDisk->ReadSector( abtBuff, iStartSec );
+
+ if ( abtBuff[ 1 ] != iSecCount )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' Mismatched length (%d<>%d)!", szOutFile, abtBuff[ 1 ], iSecCount );
+ return FALSE;
+ }
+
+ if ( !szOutFile )
+ return TRUE;
+
+ CAtr newdisk;
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iCurrSec = 1;
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "JONW: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_kboo.cpp b/jindroush/lib/cfs_kboo.cpp
new file mode 100644
index 0000000..526e9a6
--- /dev/null
+++ b/jindroush/lib/cfs_kboo.cpp
@@ -0,0 +1,148 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_kboo.h"
+#include "autil.h"
+
+CKBoot::CKBoot() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CKBoot constructed: %08X\n", this );
+ #endif
+}
+
+CKBoot::~CKBoot()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CKBoot destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CKBoot::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ m_pRoot = CreateEntry();
+
+ return m_pRoot ? TRUE : FALSE;
+}
+
+void CKBoot::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CKBootDirEntry* CKBoot::CreateEntry()
+{
+ CKBootDirEntry* pE = new CKBootDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ BYTE abtSec[ 0x100 ];
+
+ if ( !m_pDisk->ReadSector( abtSec, 1 ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't read boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ pE->m_dwFileLen = abtSec[ 9 ] + ( abtSec[ 10 ] << 8 ) + ( abtSec[ 11 ] << 16 );
+
+ if ( !m_pDisk->ReadSector( abtSec, 4 ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't read first post boot sector because\n%s", m_pDisk->GetLastError() );
+ delete pE;
+ return NULL;
+ }
+
+ if ( ( abtSec[ 0 ] != 0xFF ) || ( abtSec[ 1 ] != 0xFF ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Not a KBoot image!" );
+ delete pE;
+ return NULL;
+ }
+
+ int iSectors = 3 + ( ( pE->m_dwFileLen + 0x7F ) / 0x80 );
+
+ if ( iSectors > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "KBOOT: Not a KBoot image or invalid! (%d<>%d)", iSectors, m_pDisk->GetSectorCount() );
+ delete pE;
+ return NULL;
+ }
+
+ sprintf( pE->m_szAscData, "%06lX", pE->m_dwFileLen );
+
+ GuessBestFnameFromPC( pE->m_szFname, m_pDisk->GetImageName(), "axe" );
+
+ return pE;
+}
+
+BOOL CKBoot::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int hOutfile = -1;
+
+ if ( szOutFile )
+ {
+ hOutfile = open( szOutFile, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, 0666 );
+
+ if ( -1 == hOutfile )
+ {
+ sprintf( m_szLastError, "KBOOT: Unable to create file '%s'!", szOutFile );
+ return FALSE;
+ }
+ }
+
+ DWORD dwFileLen = ((CKBootDirEntry*)pDirE) ->m_dwFileLen;
+
+ BYTE abtBuff[ 0x80 ];
+
+ int iSector = 4;
+
+ while( dwFileLen )
+ {
+ WORD wToCopy = ( dwFileLen < 0x80 ) ? dwFileLen : 0x80;
+
+ if ( !m_pDisk->ReadSector( abtBuff, iSector ) )
+ {
+ sprintf( m_szLastError, "KBOOT: Can't read sector because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( -1 != hOutfile )
+ write( hOutfile, abtBuff, wToCopy );
+
+ dwFileLen -= wToCopy;
+ iSector++;
+
+ }
+ if ( -1 != hOutfile )
+ close( hOutfile );
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cfs_robc.cpp b/jindroush/lib/cfs_robc.cpp
new file mode 100644
index 0000000..089b4bc
--- /dev/null
+++ b/jindroush/lib/cfs_robc.cpp
@@ -0,0 +1,231 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cfs_robc.h"
+#include "autil.h"
+#include "adsk_atr.h"
+
+#define ROBC_MAX_NAME 20
+
+CRobc::CRobc() : CFs()
+{
+ #ifdef _MEMORY_DUMP_
+ printf( "CRobc constructed: %08X\n", this );
+ #endif
+}
+
+CRobc::~CRobc()
+{
+ Dismount();
+ #ifdef _MEMORY_DUMP_
+ printf( "CRobc destructed: %08X\n", this );
+ #endif
+}
+
+BOOL CRobc::Mount( ADisk* pDisk )
+{
+ m_iFilesValid = 0;
+ m_iFilesInvalid = 0;
+ m_pDisk = pDisk;
+ m_pRoot = NULL;
+
+ if ( m_pDisk->GetSectorSize() != 0x80 )
+ {
+ sprintf( m_szLastError, "ROBC: Can't process DD disk!" );
+ return FALSE;
+ }
+
+ switch( m_pDisk->GetBootSectorCount() )
+ {
+ case 0x04:
+ break;
+
+ default:
+ {
+ sprintf( m_szLastError, "ROBC: Can't identify disk as a RobC menu!" );
+ return FALSE;
+ }
+ }
+
+ CRobcDirEntry* pPrev = NULL;
+
+ BYTE abtSec[ 0x180 ];
+
+ if ( !m_pDisk->ReadSectors( abtSec, 0x02, 3 ) )
+ {
+ sprintf( m_szLastError, "ROBC: Can't read directory because\n%s", m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ BYTE* abtStartSecLo = abtSec + 0x77;
+ BYTE* abtStartSecHi = abtSec + 0x6E;
+ BYTE* pbtName = abtSec + 0xB9;
+
+ for( int i = 0; i < 10; i++ )
+ {
+ WORD wSec = *abtStartSecLo + ( *abtStartSecHi << 8 );
+
+ //printf( "%d) %04X\n", i, wSec );
+
+ if ( ! wSec )
+ continue;
+
+ BYTE abtLocSec[ 0x80 ];
+ BYTE btSecCount;
+
+ if( !m_pDisk->ReadSector( abtLocSec, wSec ) )
+ {
+ sprintf( m_szLastError, "ROBC: Can't read dir entry %d!", i );
+ return FALSE;
+ }
+
+ btSecCount = abtLocSec[ 1 ];
+
+ if ( ! btSecCount )
+ break;
+
+ CRobcDirEntry* pE = CreateEntry( btSecCount, wSec, pbtName + 2 );
+
+ if ( m_pRoot )
+ {
+ pPrev->m_pNext = pE;
+ pE->m_pPrev = pPrev;
+ pPrev = pE;
+ }
+ else
+ {
+ m_pRoot = pE;
+ pPrev = pE;
+ }
+
+ abtStartSecLo++;
+ abtStartSecHi++;
+ pbtName += ROBC_MAX_NAME;
+ }
+
+ return TRUE;
+}
+
+void CRobc::Dismount()
+{
+ DeleteList( m_pRoot );
+}
+
+CRobcDirEntry* CRobc::CreateEntry( BYTE btSecCount, WORD wStartSec, BYTE* btName )
+{
+ CRobcDirEntry* pE = new CRobcDirEntry();
+
+ if ( !pE )
+ return NULL;
+
+ pE->m_iStartSec = wStartSec;
+ pE->m_iSecCount = btSecCount;
+
+ sprintf( pE->m_szAscData, "%04X %02X", wStartSec, btSecCount );
+
+ char szTemp[ ROBC_MAX_NAME + 1 - 2 ];
+ memcpy( szTemp, btName, ROBC_MAX_NAME - 2 );
+ szTemp[ ROBC_MAX_NAME - 2 ] = '\0';
+
+ //printf( "%s\n", szTemp );
+
+ char* szT = szTemp;
+
+ while( *szT )
+ {
+ *szT &= 0x7F;
+ *szT -= 0x20;
+ szT++;
+ }
+
+ GuessBestFnameFromAtari( pE->m_szFname, szTemp, "atr" );
+
+ //printf( "%s\n", pE->m_szFname );
+
+ if ( ExportFile( NULL, pE ) )
+ m_iFilesValid++;
+ else
+ m_iFilesInvalid++;
+
+ return pE;
+}
+
+BOOL CRobc::ExportFile( char* szOutFile, CDirEntry* pDirE )
+{
+ int iSecCount = ((CRobcDirEntry*)pDirE) ->m_iSecCount;
+ int iStartSec = ((CRobcDirEntry*)pDirE) ->m_iStartSec;
+
+ BYTE abtBuff[ 0x80 ];
+
+ if ( ( iStartSec + iSecCount - 1 ) > m_pDisk->GetSectorCount() )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' goes past last sector!", szOutFile );
+ return FALSE;
+ }
+
+ m_pDisk->ReadSector( abtBuff, iStartSec );
+
+ if ( abtBuff[ 1 ] != iSecCount )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' Mismatched length (%d<>%d)!", szOutFile, abtBuff[ 1 ], iSecCount );
+ return FALSE;
+ }
+
+ if ( !szOutFile )
+ return TRUE;
+
+ CAtr newdisk;
+
+ DISK_GEOMETRY dg;
+
+ dg.iSides = 1;
+ dg.iTracks = 1;
+ dg.iSectorsPerTrack = iSecCount;
+ dg.iBytesPerSector = 0x80;
+
+ if ( !newdisk.Format( &dg ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ int iCurrSec = 1;
+
+ while( iSecCount )
+ {
+ if( !m_pDisk->ReadSector( abtBuff, iStartSec++ ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, m_pDisk->GetLastError() );
+ return FALSE;
+ }
+
+ if ( !newdisk.WriteSector( iCurrSec++, abtBuff ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ iSecCount--;
+ }
+
+ if ( !newdisk.Save( szOutFile, FALSE ) )
+ {
+ sprintf( m_szLastError, "ROBC: File '%s' can't create because\n%s", szOutFile, newdisk.GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/jindroush/lib/cgenfile.cpp b/jindroush/lib/cgenfile.cpp
new file mode 100644
index 0000000..66d678d
--- /dev/null
+++ b/jindroush/lib/cgenfile.cpp
@@ -0,0 +1,95 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cgenfile.h"
+
+//writes little-endian dword
+void CGenFile::writeLEdw( DWORD dwT )
+{
+ writeb( dwT & 0xFF );
+ writeb( ( dwT >> 8 ) & 0xFF );
+ writeb( ( dwT >>16 ) & 0xFF );
+ writeb( ( dwT >>24 ) & 0xFF );
+}
+
+//writes little-endian word
+void CGenFile::writeLEw( WORD wT )
+{
+ writeb( wT & 0xFF );
+ writeb( ( wT >> 8 ) & 0xFF );
+}
+
+void CGenFile::writeBEw( WORD wT )
+{
+ writeb( ( wT >> 8 ) & 0xFF );
+ writeb( wT & 0xFF );
+}
+
+//reads little-endian word
+WORD CGenFile::readLEw()
+{
+ WORD wT;
+ wT = readb();
+ wT |= readb() << 8;
+ return wT;
+}
+
+WORD CGenFile::readBEw()
+{
+ WORD wT;
+ wT = readb() << 8;
+ wT |= readb();
+ return wT;
+}
+
+
+//reads little-endian dword
+DWORD CGenFile::readLEdw()
+{
+ DWORD dwT;
+ dwT = readb();
+ dwT |= readb() << 8;
+ dwT |= readb() << 16;
+ dwT |= readb() << 24;
+
+ return dwT;
+}
+
+//writes byte
+void CGenFile::writeb( BYTE btT )
+{
+ Write( &btT, 1, NULL );
+}
+
+//reads byte
+BYTE CGenFile::readb()
+{
+ BYTE btPom;
+ Read( &btPom, 1, NULL );
+ return btPom;
+}
+
+//skips part of file
+BOOL CGenFile::skip( long lSkip )
+{
+ return Seek( lSkip, SEEK_CUR );
+}
+
+//gets current value of pointer
+long CGenFile::Tell()
+{
+ return m_lCurrPtr;
+}
+
diff --git a/jindroush/lib/cobj.cpp b/jindroush/lib/cobj.cpp
new file mode 100644
index 0000000..9c2a6c6
--- /dev/null
+++ b/jindroush/lib/cobj.cpp
@@ -0,0 +1,23 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cobj.h"
+
+CObj::CObj()
+{
+ *m_szLastError = '\0';
+ m_iErrorCode = 0;
+}
+
diff --git a/jindroush/lib/cprefile.cpp b/jindroush/lib/cprefile.cpp
new file mode 100644
index 0000000..b96cdfe
--- /dev/null
+++ b/jindroush/lib/cprefile.cpp
@@ -0,0 +1,153 @@
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "cprefile.h"
+
+CPreFile::CPreFile()
+{
+ m_lCacheStartOffset = -1;
+ m_lCacheEndOffset = -1;
+ m_bOpened = FALSE;
+ m_pbtCache = NULL;
+}
+
+CPreFile::~CPreFile()
+{
+ Close();
+}
+
+BOOL CPreFile::Open( CGenFile* pcf, int iCacheSizeKB )
+{
+ m_lCacheLen = 1024 * iCacheSizeKB;
+
+ if ( m_bOpened )
+ return FALSE;
+
+ m_pcf = pcf;
+
+ m_pcf->Seek( 0, SEEK_END );
+
+ m_lLength = m_pcf->Tell();
+
+ if ( m_lLength < m_lCacheLen )
+ {
+ m_lCacheLen = m_lLength;
+ }
+
+ if ( ! ( m_pbtCache = new BYTE [ m_lCacheLen ] ) )
+ return FALSE;
+
+ m_pcf->Seek( 0, SEEK_SET );
+
+ m_lCurrPtr = 0;
+
+ m_bOpened = TRUE;
+
+ PreRead();
+
+ return TRUE;
+
+}
+
+BOOL CPreFile::PreRead()
+{
+ m_pcf->Seek( m_lCurrPtr, SEEK_SET );
+ m_lCacheStartOffset = m_lCurrPtr;
+ m_lCacheEndOffset = m_lCacheStartOffset + m_lCacheLen - 1;
+
+ m_pcf->Read( m_pbtCache, m_lCacheLen );
+
+ return TRUE;
+}
+
+BOOL CPreFile::Read( void* pBuff, int iLen, int* piLen )
+{
+ if ( !m_bOpened )
+ return FALSE;
+
+ if ( m_lCurrPtr > m_lLength )
+ return FALSE;
+
+ if ( iLen >= m_lCacheLen )
+ {
+ m_pcf->Seek( m_lCurrPtr, SEEK_SET );
+ if ( !m_pcf->Read( pBuff, iLen, piLen ) )
+ return FALSE;
+
+ m_lCurrPtr = m_pcf->Tell();
+ m_lCacheEndOffset = -1;
+ return TRUE;
+ }
+
+ if ( ( m_lCurrPtr < m_lCacheStartOffset ) || ( m_lCurrPtr > m_lCacheEndOffset ) )
+ PreRead();
+
+ long lReadEnd = m_lCurrPtr + iLen - 1;
+
+ if ( lReadEnd >= m_lCacheEndOffset )
+ {
+ m_pcf->Seek( m_lCurrPtr, SEEK_SET );
+ if ( !m_pcf->Read( pBuff, iLen, piLen ) )
+ return FALSE;
+
+ m_lCurrPtr = m_pcf->Tell();
+ m_lCacheEndOffset = -1;
+
+ return TRUE;
+ }
+
+ memcpy( pBuff, m_pbtCache + m_lCurrPtr - m_lCacheStartOffset, iLen );
+ m_lCurrPtr += iLen;
+
+ return TRUE;
+}
+
+BOOL CPreFile::Write( void* pBuff, int iLen, int* piLen )
+{
+ return FALSE;
+}
+
+BOOL CPreFile::Seek( long lPos, int iType )
+{
+
+ switch( iType )
+ {
+ case SEEK_SET:
+ m_lCurrPtr = lPos;
+ break;
+
+ case SEEK_CUR:
+ m_lCurrPtr += lPos;
+ break;
+
+ case SEEK_END:
+ m_lCurrPtr = m_lLength - lPos;
+ break;
+
+ }
+ return TRUE;
+}
+
+void CPreFile::Close()
+{
+ m_bOpened = FALSE;
+
+ if ( m_pbtCache )
+ delete [] m_pbtCache;
+
+ m_pbtCache = NULL;
+ m_lCurrPtr = 0;
+}
+
diff --git a/jindroush/man/Makefile b/jindroush/man/Makefile
new file mode 100644
index 0000000..bfe47c0
--- /dev/null
+++ b/jindroush/man/Makefile
@@ -0,0 +1,12 @@
+DESTDIR=
+PREFIX=/usr/local
+MANDIR=$(PREFIX)/man
+MAN1DIR=$(MANDIR)/man1
+GZIP_MAN=y
+RST2MAN=rst2man
+MANS=acvt.1 adir.1 aext.1 bas2boot.1 chkbas.1 chkexe.1 chkrom.1
+
+all: $(MANS)
+
+%.1: %.rst manhdr.rst manftr.rst
+ $(RST2MAN) $< > $@
diff --git a/jindroush/man/acvt.1 b/jindroush/man/acvt.1
new file mode 100644
index 0000000..4336fe7
--- /dev/null
+++ b/jindroush/man/acvt.1
@@ -0,0 +1,116 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "ACVT" 1 "2024-05-16" "1.07" "Jindroush's Atari 8-bit tools"
+.SH NAME
+acvt \- convert between Atari 8-bit disk image formats
+.SH SYNOPSIS
+.sp
+acvt [\fB\-xfd\fP | \fB\-atr\fP | \fB\-scp\fP | \fB\-dcm\fP | \fB\-di\fP] [\fB\-batchmode\fP] [\fB\-autorepair\fP] [\fB\-norepair\fP] [\fB\-errstop\fP] [\fB\-over\fP] [\fB\-test\fP] [\fB\-classic\fP] \fIinput\-file\fP [\fIoutput\-file\fP]
+.SH DESCRIPTION
+.sp
+\fBacvt\fP converts Atari 8\-bit images between various formats. It can
+also repair some kinds of problems with broken/corrupted images.
+.sp
+Supported formats are:
+.INDENT 0.0
+.INDENT 3.5
+.INDENT 0.0
+.TP
+.B ATR
+Originally defined by SIOPC; the modern standard format.
+.TP
+.B XFD
+Originally defined by the XFormer emulator; raw images.
+.TP
+.B DCM
+DiskComm (Disk Communicator) images.
+.TP
+.B SCP
+SpartaDOS SCOPY images.
+.TP
+.B DI
+XL/ST link / XLDJ disk images.
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+If no \fIoutput\-file\fP is given, the filename is created automatically by
+replacing the filename extension (e.g. \fIfoo.xfd\fP becomes \fIfoo.atr\fP).
+.sp
+If the output file already exists, it will not be overwritten unless
+the \fB\-over\fP option is given.
+.sp
+If the input file is invalid, \fBacvt\fP may prompt for a repair method.
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \fB\-xfd\fP, \fB\-atr\fP, \fB\-scp\fP, \fB\-dcm\fP, \fB\-di\fP
+Output disk image format. Default is \fB\-atr\fP\&.
+.TP
+.B \fB\-batchmode\fP
+Multi\-file processing mode. Only input files are specified on command\-line.
+Regular expressions are allowed. Output filenames are created automatically.
+.TP
+.B \fB\-autorepair\fP
+Automatically determines the best repair method (rather than prompting).
+.TP
+.B \fB\-norepair\fP
+Doesn\(aqt ask for repair options and considers input file invalid if it needs repair.
+.TP
+.B \fB\-errstop\fP
+In batch mode, exits on the first error encountered.
+.TP
+.B \fB\-over\fP
+Overwrites existing files.
+.TP
+.B \fB\-test\fP
+Load input images and display their state, but do not write output.
+.TP
+.B \fB\-classic\fP
+Force output to be one of the classic Atari disk sizes (90K, 128K, 180K).
+.UNINDENT
+.SH COPYRIGHT
+.sp
+This utility is released under the GNU General Public License.
+.SH AUTHORS
+.sp
+This utility was written by Jindrich Kubec, AKA Jindroush.
+.sp
+This page was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
+.SH SEE ALSO
+.sp
+\fBacvt\fP(1),
+\fBaext\fP(1),
+\fBbas2boot\fP(1),
+\fBchkbas\fP(1),
+\fBchkexe\fP(1),
+\fBchkrom\fP(1).
+.\" Generated by docutils manpage writer.
+.
diff --git a/jindroush/man/acvt.rst b/jindroush/man/acvt.rst
new file mode 100644
index 0000000..925ffbc
--- /dev/null
+++ b/jindroush/man/acvt.rst
@@ -0,0 +1,77 @@
+.. |version| replace:: 1.07
+
+====
+acvt
+====
+
+----------------------------------------------
+convert between Atari 8-bit disk image formats
+----------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+acvt [**-xfd** | **-atr** | **-scp** | **-dcm** | **-di**] [**-batchmode**] [**-autorepair**] [**-norepair**] [**-errstop**] [**-over**] [**-test**] [**-classic**] *input-file* [*output-file*]
+
+DESCRIPTION
+===========
+
+**acvt** converts Atari 8-bit images between various formats. It can
+also repair some kinds of problems with broken/corrupted images.
+
+Supported formats are:
+
+ ATR
+ Originally defined by SIOPC; the modern standard format.
+
+ XFD
+ Originally defined by the XFormer emulator; raw images.
+
+ DCM
+ DiskComm (Disk Communicator) images.
+
+ SCP
+ SpartaDOS SCOPY images.
+
+ DI
+ XL/ST link / XLDJ disk images.
+
+If no *output-file* is given, the filename is created automatically by
+replacing the filename extension (e.g. *foo.xfd* becomes *foo.atr*).
+
+If the output file already exists, it will not be overwritten unless
+the **-over** option is given.
+
+If the input file is invalid, **acvt** may prompt for a repair method.
+
+OPTIONS
+=======
+
+**-xfd**, **-atr**, **-scp**, **-dcm**, **-di**
+ Output disk image format. Default is **-atr**.
+
+**-batchmode**
+ Multi-file processing mode. Only input files are specified on command-line.
+ Regular expressions are allowed. Output filenames are created automatically.
+
+**-autorepair**
+ Automatically determines the best repair method (rather than prompting).
+
+**-norepair**
+ Doesn't ask for repair options and considers input file invalid if it needs repair.
+
+**-errstop**
+ In batch mode, exits on the first error encountered.
+
+**-over**
+ Overwrites existing files.
+
+**-test**
+ Load input images and display their state, but do not write output.
+
+**-classic**
+ Force output to be one of the classic Atari disk sizes (90K, 128K, 180K).
+
+.. include:: manftr.rst
diff --git a/jindroush/man/adir.1 b/jindroush/man/adir.1
new file mode 100644
index 0000000..8250225
--- /dev/null
+++ b/jindroush/man/adir.1
@@ -0,0 +1,141 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "ADIR" 1 "2024-05-16" "0.67" "Jindroush's Atari 8-bit tools"
+.SH NAME
+adir \- list and extract files from Atari 8-bit disk images
+.SH SYNOPSIS
+.sp
+adir [ [\fB\-help*] | [\fP\-dos2** | [\fB\-dos3\fP] | [\fB\-mydos\fP] | [\fB\-spdos\fP] | [\fB\-kboot\fP] | [\fB\-bas2boot\fP ] | [\fB\-jonw\fP] | [\fB\-robc\fP] | [\fB\-howf\fP] | [\fB\-boot] ] [\fP\-e**] [\fB\-dir\fP \fIpath\fP] [\fB\-dontrepair\fP] \fBdisk\-image\fP [\fBmask\fP]
+.SH DESCRIPTION
+.sp
+\fBadir\fP lists and extracts the files contained in an Atari 8\-bit
+disk image. Many Atari DOS and DOS\-like filesystems are supported,
+and disk images can be in various formats.
+.sp
+The image types supported are:
+.INDENT 0.0
+.INDENT 3.5
+.INDENT 0.0
+.TP
+.B ATR
+Originally defined by SIOPC; the modern standard format.
+.TP
+.B XFD
+Originally defined by the XFormer emulator; raw images.
+.TP
+.B DCM
+DiskComm (Disk Communicator) images.
+.TP
+.B SCP
+SpartaDOS SCOPY images.
+.TP
+.B DI
+XL/ST link / XLDJ disk images.
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+The image type is autodetected; there are no options to override the
+detection.
+.sp
+The filesystems supported are:
+.INDENT 0.0
+.INDENT 3.5
+.INDENT 0.0
+.IP \(bu 2
+Atari DOS 2.0/2.5 and compatibles
+.IP \(bu 2
+Atari DOS 3.0
+.IP \(bu 2
+MyDOS
+.IP \(bu 2
+Sparta DOS and compatibles (BeWe, RealDOS)
+.IP \(bu 2
+K\-Boot images
+.IP \(bu 2
+HowFen DOS
+.IP \(bu 2
+JonW multiboot
+.IP \(bu 2
+RobC multiboot
+.IP \(bu 2
+Bas2Boot images
+.IP \(bu 2
+boot images (extracts boot sector only)
+.UNINDENT
+.UNINDENT
+.UNINDENT
+.sp
+By default, \fBadir\fP attempts to autodetect the filesystem type, but it can
+be set explicitly by one of the options, below.
+.sp
+\fBmask\fP is a wildcard mask of filenames to extract. Note that
+it\(aqs case\-sensitive, meaning it generally will have to be given in
+uppercase since most Atari filesystems don\(aqt support lowercase.
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \fB\-dos2\fP, \fB\-dos3\fP, \fB\-mydos\fP, \fB\-spdos\fP, \fB\-kboot\fP, \fB\-bas2boot\fP, \fB\-jonw\fP, \fB\-robc\fP, \fB\-howf\fP, \fB\-boot\fP
+Set the filesystem type (see list, above).
+.TP
+.B \fB\-e\fP
+Extracts files from the image. If a wildcard \fBmask\fP is given,
+files matching the wildcard will be listed (and extracted, with
+\fB\-e\fP). Without a \fBmask\fP, all files on the image will be
+listed/extracted.
+.TP
+.B \fB\-dir\fP \fIpath\fP
+Write extracted files to this directory, which will be created if it
+doesn\(aqt already exist. Default is "." (the current directory).
+.TP
+.B \fB\-dontrepair\fP
+Don\(aqt attempt to automatically repair invalid files.
+.UNINDENT
+.SH EXIT STATUS
+.sp
+Zero for success, non\-zero for failure.
+.SH COPYRIGHT
+.sp
+This utility is released under the GNU General Public License.
+.SH AUTHORS
+.sp
+This utility was written by Jindrich Kubec, AKA Jindroush.
+.sp
+This page was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
+.SH SEE ALSO
+.sp
+\fBacvt\fP(1),
+\fBaext\fP(1),
+\fBbas2boot\fP(1),
+\fBchkbas\fP(1),
+\fBchkexe\fP(1),
+\fBchkrom\fP(1).
+.\" Generated by docutils manpage writer.
+.
diff --git a/jindroush/man/adir.rst b/jindroush/man/adir.rst
new file mode 100644
index 0000000..eff5911
--- /dev/null
+++ b/jindroush/man/adir.rst
@@ -0,0 +1,89 @@
+.. |version| replace:: 0.67
+
+====
+adir
+====
+
+---------------------------------------------------
+list and extract files from Atari 8-bit disk images
+---------------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+adir [ [**-help*] | [**-dos2** | [**-dos3**] | [**-mydos**] | [**-spdos**] | [**-kboot**] | [**-bas2boot** ] | [**-jonw**] | [**-robc**] | [**-howf**] | [**-boot] ] [**-e**] [**-dir** *path*] [**-dontrepair**] **disk-image** [**mask**]
+
+DESCRIPTION
+===========
+
+**adir** lists and extracts the files contained in an Atari 8-bit
+disk image. Many Atari DOS and DOS-like filesystems are supported,
+and disk images can be in various formats.
+
+The image types supported are:
+
+ ATR
+ Originally defined by SIOPC; the modern standard format.
+
+ XFD
+ Originally defined by the XFormer emulator; raw images.
+
+ DCM
+ DiskComm (Disk Communicator) images.
+
+ SCP
+ SpartaDOS SCOPY images.
+
+ DI
+ XL/ST link / XLDJ disk images.
+
+The image type is autodetected; there are no options to override the
+detection.
+
+The filesystems supported are:
+
+ - Atari DOS 2.0/2.5 and compatibles
+ - Atari DOS 3.0
+ - MyDOS
+ - Sparta DOS and compatibles (BeWe, RealDOS)
+ - K-Boot images
+ - HowFen DOS
+ - JonW multiboot
+ - RobC multiboot
+ - Bas2Boot images
+ - boot images (extracts boot sector only)
+
+By default, **adir** attempts to autodetect the filesystem type, but it can
+be set explicitly by one of the options, below.
+
+**mask** is a wildcard mask of filenames to extract. Note that
+it's case-sensitive, meaning it generally will have to be given in
+uppercase since most Atari filesystems don't support lowercase.
+
+OPTIONS
+=======
+
+**-dos2**, **-dos3**, **-mydos**, **-spdos**, **-kboot**, **-bas2boot**, **-jonw**, **-robc**, **-howf**, **-boot**
+ Set the filesystem type (see list, above).
+
+**-e**
+ Extracts files from the image. If a wildcard **mask** is given,
+ files matching the wildcard will be listed (and extracted, with
+ **-e**). Without a **mask**, all files on the image will be
+ listed/extracted.
+
+**-dir** *path*
+ Write extracted files to this directory, which will be created if it
+ doesn't already exist. Default is "." (the current directory).
+
+**-dontrepair**
+ Don't attempt to automatically repair invalid files.
+
+EXIT STATUS
+===========
+
+Zero for success, non-zero for failure.
+
+.. include:: manftr.rst
diff --git a/jindroush/man/aext.1 b/jindroush/man/aext.1
new file mode 100644
index 0000000..534c2da
--- /dev/null
+++ b/jindroush/man/aext.1
@@ -0,0 +1,55 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "AEXT" 1 "2024-05-16" "1.02" "Jindroush's Atari 8-bit tools"
+.SH NAME
+aext \- extract binary blocks from Atari 8-bit disk images
+.SH SYNOPSIS
+.sp
+aext [\fB\-s\fP \fIstart\fP] [\fB\-e\fP \fIend\fP] [\fB\-l\fP \fIlength\fP] [\fB\-oa\fP] [\fB\-base\fP] \fBinput\-file\fP [\fBoutput\-file\fP]
+.SH DESCRIPTION
+.SH OPTIONS
+.SH COPYRIGHT
+.sp
+This utility is released under the GNU General Public License.
+.SH AUTHORS
+.sp
+This utility was written by Jindrich Kubec, AKA Jindroush.
+.sp
+This page was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
+.SH SEE ALSO
+.sp
+\fBacvt\fP(1),
+\fBaext\fP(1),
+\fBbas2boot\fP(1),
+\fBchkbas\fP(1),
+\fBchkexe\fP(1),
+\fBchkrom\fP(1).
+.\" Generated by docutils manpage writer.
+.
diff --git a/jindroush/man/aext.rst b/jindroush/man/aext.rst
new file mode 100644
index 0000000..ed8fb98
--- /dev/null
+++ b/jindroush/man/aext.rst
@@ -0,0 +1,24 @@
+.. |version| replace:: 1.02
+
+====
+aext
+====
+
+--------------------------------------------------
+extract binary blocks from Atari 8-bit disk images
+--------------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+aext [**-s** *start*] [**-e** *end*] [**-l** *length*] [**-oa**] [**-base**] **input-file** [**output-file**]
+
+DESCRIPTION
+===========
+
+OPTIONS
+=======
+
+.. include:: manftr.rst
diff --git a/jindroush/man/bas2boot.1 b/jindroush/man/bas2boot.1
new file mode 100644
index 0000000..7e838db
--- /dev/null
+++ b/jindroush/man/bas2boot.1
@@ -0,0 +1,84 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "BAS2BOOT" 1 "2024-05-16" "1.0.2" "Jindroush's Atari 8-bit tools"
+.SH NAME
+bas2boot \- make a bootable Atari 8-bit disk image of a BASIC program
+.SH SYNOPSIS
+.sp
+bas2boot [\fB\-atr\fP | \fB\-xfd\fP | \fB\-scp\fP | \fB\-dcm\fP | \fB\-di\fP] [\fB\-long\fP] [\fB\-message\fP \fItext\fP] \fBbasic\-file\fP [\fBoutput\-disk\-image\fP]
+.SH DESCRIPTION
+.sp
+\fBbas2boot\fP creates an Atari 8\-bit disk image that consists of a boot
+loader followed by a tokenized Atari BASIC program. When the disk is
+booted on the Atari, the BASIC program is loaded into memory and run.
+.sp
+There is no DOS on the disk; the BASIC program won\(aqt be able to use
+the D: devices.
+.sp
+The bootloader will enable BASIC if possible (600XL, 800XL, all
+XEs). Otherwise (400/800/1200XL), the Atari BASIC cartridge must be
+inserted. The bootloader doesn\(aqt work with other BASICs like BASIC XL,
+TurboBASIC, etc.
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \fB\-atr\fP \fB\-xfd\fP \fB\-scp\fP \fB\-dcm\fP \fB\-di\fP
+Set the output image type. Default: \fB\-atr\fP\&. Note that the image
+type is \fInot\fP affected by the filename extension (the default
+is still \fB\-atr\fP even with a file called \fIoutput.xfd\fP).
+.TP
+.B \fB\-long\fP
+Use \(aqclassic\(aq disk size (single density, 90KB). Default is to create a
+short ATR file consisting only of the sectors used.
+.TP
+.B \fB\-message\fP \fItext\fP
+Sets message displayed while the program is loading.
+.UNINDENT
+.SH EXIT STATUS
+.sp
+Zero for success, non\-zero for failure.
+.SH COPYRIGHT
+.sp
+This utility is released under the GNU General Public License.
+.SH AUTHORS
+.sp
+This utility was written by Jindrich Kubec, AKA Jindroush.
+.sp
+This page was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
+.SH SEE ALSO
+.sp
+\fBacvt\fP(1),
+\fBaext\fP(1),
+\fBbas2boot\fP(1),
+\fBchkbas\fP(1),
+\fBchkexe\fP(1),
+\fBchkrom\fP(1).
+.\" Generated by docutils manpage writer.
+.
diff --git a/jindroush/man/bas2boot.rst b/jindroush/man/bas2boot.rst
new file mode 100644
index 0000000..c5273e6
--- /dev/null
+++ b/jindroush/man/bas2boot.rst
@@ -0,0 +1,53 @@
+.. |version| replace:: 1.0.2
+
+========
+bas2boot
+========
+
+---------------------------------------------------------
+make a bootable Atari 8-bit disk image of a BASIC program
+---------------------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+bas2boot [**-atr** | **-xfd** | **-scp** | **-dcm** | **-di**] [**-long**] [**-message** *text*] **basic-file** [**output-disk-image**]
+
+DESCRIPTION
+===========
+
+**bas2boot** creates an Atari 8-bit disk image that consists of a boot
+loader followed by a tokenized Atari BASIC program. When the disk is
+booted on the Atari, the BASIC program is loaded into memory and run.
+
+There is no DOS on the disk; the BASIC program won't be able to use
+the D: devices.
+
+The bootloader will enable BASIC if possible (600XL, 800XL, all
+XEs). Otherwise (400/800/1200XL), the Atari BASIC cartridge must be
+inserted. The bootloader doesn't work with other BASICs like BASIC XL,
+TurboBASIC, etc.
+
+OPTIONS
+=======
+
+**-atr** **-xfd** **-scp** **-dcm** **-di**
+ Set the output image type. Default: **-atr**. Note that the image
+ type is *not* affected by the filename extension (the default
+ is still **-atr** even with a file called *output.xfd*).
+
+**-long**
+ Use 'classic' disk size (single density, 90KB). Default is to create a
+ short ATR file consisting only of the sectors used.
+
+**-message** *text*
+ Sets message displayed while the program is loading.
+
+EXIT STATUS
+===========
+
+Zero for success, non-zero for failure.
+
+.. include:: manftr.rst
diff --git a/jindroush/man/chkbas.1 b/jindroush/man/chkbas.1
new file mode 100644
index 0000000..1069d6c
--- /dev/null
+++ b/jindroush/man/chkbas.1
@@ -0,0 +1,155 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "CHKBAS" 1 "2024-05-16" "1.10" "Jindroush's Atari 8-bit tools"
+.SH NAME
+chkbas \- check and detokenize Atari BASIC SAVEd files
+.SH SYNOPSIS
+.sp
+chkbas [\fB\-atari\fP] [\fB\-short\fP] [\fB\-verbose\fP] [\fB\-noinverse\fP] [\fB\-tbs\fP | \fB\-bxl\fP | \fB\-bxe\fP] \fBbasic\-file\fP [\fBoutput\-file\fP]
+.sp
+listbas [\fB\-atari\fP] [\fB\-verbose\fP] [\fB\-noinverse\fP] [\fB\-tbs\fP | \fB\-bxl\fP | \fB\-bxe\fP] \fBbasic\-file\fP [\fBoutput\-file\fP]
+.SH DESCRIPTION
+.sp
+\fBchkbas\fP detokenizes Atari 8\-bit BASIC SAVEd files. It lists the BASIC
+code in human\-readable form, and gives some other useful information
+about the program.
+.sp
+\fBbasic\-file\fP is an Atari BASIC, TurboBASIC, BASIC XL, or BASIC
+XE program. Output will go to \fBoutput\-file\fP, if given; otherwise,
+standard output. If \fBbasic\-file\fP is anything other than standard
+Atari BASIC, the BASIC dialect must be specified (see \fBOPTIONS\fP,
+below).
+.sp
+\fBlistbas\fP is simply an alias for \fBchkbas \-short\fP\&.
+.sp
+Sample run, with no options:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ chkbas HELLO.BAS
+chkbas v1.10 (c) 1999\-2001 Jindrich Kubec <kubecj@asw.cz>
+
+chkbas v1.10 (c) 1999\-2001 Jindrich Kubec <kubecj@asw.cz>
+Atari Basic/Turbo Basic/Basic XL/Basic XE decompiler.
+ Latest version can be found at http://www.asw.cz/~kubecj
+ Published under GPL. See GPL.TXT.
+ Thanks to Russ Gilbert for his SALVAGE programs.
+
+Input file: HELLO.BAS
+
+Constants & pointers:
+Start of Name Table (VNT) : 000E
+End of Name Table (VNTE) : 0011
+Lenght of Name Table (VNTL) : 0004
+Start of Variable Table (VVT) : 0012
+End of Variable Table (VVTE) : 0021
+Length of Variable Table (VVTL) : 0010
+Number of Variables (NV) : 0002
+Start of Code (STMTAB): 0022
+Length of Code : 004E
+Current command (STMCUR): 0070
+Length of current command : 0013
+First byte after program (STARP) : 0083
+Length of file : 0083
+File len difference : 00000000
+
+Variable table:
+0001 STRING (81) 00: SPoff: 0000 Len: 5 Dim: 10 A$
+0002 SCALAR (00) 01: 11 I
+
+Main code starts here:
+10 DIM A$(10)
+20 A$="HELLO"
+30 FOR I=1 TO 10
+40 ? A$;" WORLD!"
+50 NEXT I
+
+Immediate code starts here:
+32768 SAVE "H:HELLO.BAS"
+
+Done!
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SH OPTIONS
+.SS Input Options
+.INDENT 0.0
+.TP
+.B \fB\-tbs\fP
+Treat input as a Turbo BASIC program.
+.TP
+.B \fB\-bxl\fP
+Treat input as a BASIC XL program.
+.TP
+.B \fB\-bxe\fP
+Treat input as a BASIC XE program, which may or may not be EXTENDed
+with code in the extra XE banks.
+.UNINDENT
+.SS Output Options
+.INDENT 0.0
+.TP
+.B \fB\-atari\fP
+Output only the program listing, with lines terminated by Atari
+EOL characters (\fB$9B\fP).
+.TP
+.B \fB\-short\fP
+Output only the program listing, with lines terminated by the
+system default newline character(s), e.g. \fBn\fP on UNIX\-like OSes,
+\fBrn\fP on MS\-DOS or Windows. This is the default for \fBlistbas\fP\&.
+.TP
+.B \fB\-verbose\fP
+Program listing will be interspersed with per\-line and per\-statement
+low\-level information. This option is probably most useful for debugging
+\fBchkbas\fP itself.
+.UNINDENT
+.SH EXIT STATUS
+.sp
+Zero for success, non\-zero for failure.
+.SH COPYRIGHT
+.sp
+This utility is released under the GNU General Public License.
+.SH AUTHORS
+.sp
+This utility was written by Jindrich Kubec, AKA Jindroush.
+.sp
+This page was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
+.SH SEE ALSO
+.sp
+\fBacvt\fP(1),
+\fBaext\fP(1),
+\fBbas2boot\fP(1),
+\fBchkbas\fP(1),
+\fBchkexe\fP(1),
+\fBchkrom\fP(1).
+.\" Generated by docutils manpage writer.
+.
diff --git a/jindroush/man/chkbas.rst b/jindroush/man/chkbas.rst
new file mode 100644
index 0000000..2f9e6b7
--- /dev/null
+++ b/jindroush/man/chkbas.rst
@@ -0,0 +1,118 @@
+.. |version| replace:: 1.10
+
+======
+chkbas
+======
+
+--------------------------------------------
+check and detokenize Atari BASIC SAVEd files
+--------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+chkbas [**-atari**] [**-short**] [**-verbose**] [**-noinverse**] [**-tbs** | **-bxl** | **-bxe**] **basic-file** [**output-file**]
+
+listbas [**-atari**] [**-verbose**] [**-noinverse**] [**-tbs** | **-bxl** | **-bxe**] **basic-file** [**output-file**]
+
+DESCRIPTION
+===========
+
+**chkbas** detokenizes Atari 8-bit BASIC SAVEd files. It lists the BASIC
+code in human-readable form, and gives some other useful information
+about the program.
+
+**basic-file** is an Atari BASIC, TurboBASIC, BASIC XL, or BASIC
+XE program. Output will go to **output-file**, if given; otherwise,
+standard output. If **basic-file** is anything other than standard
+Atari BASIC, the BASIC dialect must be specified (see **OPTIONS**,
+below).
+
+**listbas** is simply an alias for **chkbas -short**.
+
+Sample run, with no options::
+
+ $ chkbas HELLO.BAS
+ chkbas v1.10 (c) 1999-2001 Jindrich Kubec <kubecj@asw.cz>
+
+ chkbas v1.10 (c) 1999-2001 Jindrich Kubec <kubecj@asw.cz>
+ Atari Basic/Turbo Basic/Basic XL/Basic XE decompiler.
+ Latest version can be found at http://www.asw.cz/~kubecj
+ Published under GPL. See GPL.TXT.
+ Thanks to Russ Gilbert for his SALVAGE programs.
+
+ Input file: HELLO.BAS
+
+ Constants & pointers:
+ Start of Name Table (VNT) : 000E
+ End of Name Table (VNTE) : 0011
+ Lenght of Name Table (VNTL) : 0004
+ Start of Variable Table (VVT) : 0012
+ End of Variable Table (VVTE) : 0021
+ Length of Variable Table (VVTL) : 0010
+ Number of Variables (NV) : 0002
+ Start of Code (STMTAB): 0022
+ Length of Code : 004E
+ Current command (STMCUR): 0070
+ Length of current command : 0013
+ First byte after program (STARP) : 0083
+ Length of file : 0083
+ File len difference : 00000000
+
+ Variable table:
+ 0001 STRING (81) 00: SPoff: 0000 Len: 5 Dim: 10 A$
+ 0002 SCALAR (00) 01: 11 I
+
+ Main code starts here:
+ 10 DIM A$(10)
+ 20 A$="HELLO"
+ 30 FOR I=1 TO 10
+ 40 ? A$;" WORLD!"
+ 50 NEXT I
+
+ Immediate code starts here:
+ 32768 SAVE "H:HELLO.BAS"
+
+ Done!
+
+OPTIONS
+=======
+
+Input Options
+-------------
+
+**-tbs**
+ Treat input as a Turbo BASIC program.
+
+**-bxl**
+ Treat input as a BASIC XL program.
+
+**-bxe**
+ Treat input as a BASIC XE program, which may or may not be EXTENDed
+ with code in the extra XE banks.
+
+Output Options
+--------------
+
+**-atari**
+ Output only the program listing, with lines terminated by Atari
+ EOL characters (**$9B**).
+
+**-short**
+ Output only the program listing, with lines terminated by the
+ system default newline character(s), e.g. **\n** on UNIX-like OSes,
+ **\r\n** on MS-DOS or Windows. This is the default for **listbas**.
+
+**-verbose**
+ Program listing will be interspersed with per-line and per-statement
+ low-level information. This option is probably most useful for debugging
+ **chkbas** itself.
+
+EXIT STATUS
+===========
+
+Zero for success, non-zero for failure.
+
+.. include:: manftr.rst
diff --git a/jindroush/man/chkexe.1 b/jindroush/man/chkexe.1
new file mode 100644
index 0000000..c266a03
--- /dev/null
+++ b/jindroush/man/chkexe.1
@@ -0,0 +1,86 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "CHKEXE" 1 "2024-05-16" "2.62" "Jindroush's Atari 8-bit tools"
+.SH NAME
+chkexe \- check and/or disassemble Atari 8-bit executables
+.SH SYNOPSIS
+.sp
+chkexe [\fB\-gaps\fP \fIgap\-size\fP] [\fB\-silent\fP] [\fB\-split\fP] [\fB\-d\fP] \fBxex\-file\fP [\fBoutput\-file\fP]
+.SH DESCRIPTION
+.sp
+\fBchkexe\fP reads an Atari 8\-bit executable (aka XEX file) and prints a
+list of segments, each with their start and end address. Run and init
+addresses are decoded.
+.sp
+If no \fBoutput\-file\fP is given, \fBchkexe\fP simply prints the results of
+its analysis. With an \fBoutput\-file\fP, a possibly modified copy of the
+XEX file is created: Adjacent blocks (e.g. a block ending at $1FFF,
+followed by a block beginning at $2000) will be combined. The \fB\-gaps\fP
+option can be used to control the threshold for combining blocks.
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \fB\-gaps\fP \fIgap\-size\fP
+Blocks less than \fIgap\-size\fP bytes apart will be combined. Default: \fI0\fP\&.
+.TP
+.B \fB\-silent\fP
+Don\(aqt print informational messages.
+.TP
+.B \fB\-split\fP
+Split multi\-segment executables into one file per segment. The output
+files will be called \fIblkNNNN.blk\fP, where \fINNNN\fP is the block number in
+hexadecimal. These files are standard Atari executables, with \fI$FFFF\fP
+headers.
+.TP
+.B \fB\-d\fP
+Disassemble each block. The disassembler is very simple: single pass,
+no attempt to recognize data blocks.
+.UNINDENT
+.SH EXIT STATUS
+.sp
+Zero for success, non\-zero for failure.
+.SH COPYRIGHT
+.sp
+This utility is released under the GNU General Public License.
+.SH AUTHORS
+.sp
+This utility was written by Jindrich Kubec, AKA Jindroush.
+.sp
+This page was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
+.SH SEE ALSO
+.sp
+\fBacvt\fP(1),
+\fBaext\fP(1),
+\fBbas2boot\fP(1),
+\fBchkbas\fP(1),
+\fBchkexe\fP(1),
+\fBchkrom\fP(1).
+.\" Generated by docutils manpage writer.
+.
diff --git a/jindroush/man/chkexe.rst b/jindroush/man/chkexe.rst
new file mode 100644
index 0000000..91c65ab
--- /dev/null
+++ b/jindroush/man/chkexe.rst
@@ -0,0 +1,55 @@
+.. |version| replace:: 2.62
+
+======
+chkexe
+======
+
+------------------------------------------------
+check and/or disassemble Atari 8-bit executables
+------------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+chkexe [**-gaps** *gap-size*] [**-silent**] [**-split**] [**-d**] **xex-file** [**output-file**]
+
+DESCRIPTION
+===========
+
+**chkexe** reads an Atari 8-bit executable (aka XEX file) and prints a
+list of segments, each with their start and end address. Run and init
+addresses are decoded.
+
+If no **output-file** is given, **chkexe** simply prints the results of
+its analysis. With an **output-file**, a possibly modified copy of the
+XEX file is created: Adjacent blocks (e.g. a block ending at $1FFF,
+followed by a block beginning at $2000) will be combined. The **-gaps**
+option can be used to control the threshold for combining blocks.
+
+OPTIONS
+=======
+
+**-gaps** *gap-size*
+ Blocks less than *gap-size* bytes apart will be combined. Default: *0*.
+
+**-silent**
+ Don't print informational messages.
+
+**-split**
+ Split multi-segment executables into one file per segment. The output
+ files will be called *blkNNNN.blk*, where *NNNN* is the block number in
+ hexadecimal. These files are standard Atari executables, with *$FFFF*
+ headers.
+
+**-d**
+ Disassemble each block. The disassembler is very simple: single pass,
+ no attempt to recognize data blocks.
+
+EXIT STATUS
+===========
+
+Zero for success, non-zero for failure.
+
+.. include:: manftr.rst
diff --git a/jindroush/man/chkrom.1 b/jindroush/man/chkrom.1
new file mode 100644
index 0000000..772f7b8
--- /dev/null
+++ b/jindroush/man/chkrom.1
@@ -0,0 +1,90 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "CHKROM" 1 "2024-05-16" "1.00" "Jindroush's Atari 8-bit tools"
+.SH NAME
+chkrom \- check or disassemble 8K or 16K Atari 8-bit cartridge images
+.SH SYNOPSIS
+.sp
+chkrom [\fB\-disassemble\fP] \fBrom\-image\fP
+.SH DESCRIPTION
+.sp
+\fBchkrom\fP reads a \fIraw\fP Atari 8\-bit ROM image (not a \fB\&.car\fP file)
+and prints the run address, init address, and the decoded flags in the
+cartridge options byte.
+.sp
+Sample run:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ chkrom basic.rom
+chkrom v1.00 (c) 1998\-1999 Jindrich Kubec <kubecj@asw.cz>
+ROM file: basic.rom
+Init Addr :BFF0
+Run Addr :A000
+Flags :0500 ( INIT&RUN BOOT )
+Ok!
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+\fBchkrom\fP only supports images exactly 8KB (8192 bytes) or 16KB
+(16384 bytes). Bankswitched cartridge aren\(aqt supported. If you get
+"Unknown ROM size", make sure you\(aqre using a raw image. If it\(aqs a
+\fB\&.car\fP image, use \fBcart2rom\fP(1) to make a raw image of it.
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \fB\-disassemble\fP
+Prints a disassembly of the entire cartridge.
+.UNINDENT
+.SH EXIT STATUS
+.sp
+Zero for success, non\-zero for failure.
+.SH COPYRIGHT
+.sp
+This utility is released under the GNU General Public License.
+.SH AUTHORS
+.sp
+This utility was written by Jindrich Kubec, AKA Jindroush.
+.sp
+This page was written by B. Watson <\fI\%urchlay@slackware.uk\fP>.
+.SH SEE ALSO
+.sp
+\fBacvt\fP(1),
+\fBaext\fP(1),
+\fBbas2boot\fP(1),
+\fBchkbas\fP(1),
+\fBchkexe\fP(1),
+\fBchkrom\fP(1).
+.\" Generated by docutils manpage writer.
+.
diff --git a/jindroush/man/chkrom.rst b/jindroush/man/chkrom.rst
new file mode 100644
index 0000000..5db1b15
--- /dev/null
+++ b/jindroush/man/chkrom.rst
@@ -0,0 +1,51 @@
+.. |version| replace:: 1.00
+
+======
+chkrom
+======
+
+-----------------------------------------------------------
+check or disassemble 8K or 16K Atari 8-bit cartridge images
+-----------------------------------------------------------
+
+.. include:: manhdr.rst
+
+SYNOPSIS
+========
+
+chkrom [**-disassemble**] **rom-image**
+
+DESCRIPTION
+===========
+
+**chkrom** reads a *raw* Atari 8-bit ROM image (not a **.car** file)
+and prints the run address, init address, and the decoded flags in the
+cartridge options byte.
+
+Sample run::
+
+ $ chkrom basic.rom
+ chkrom v1.00 (c) 1998-1999 Jindrich Kubec <kubecj@asw.cz>
+ ROM file: basic.rom
+ Init Addr :BFF0
+ Run Addr :A000
+ Flags :0500 ( INIT&RUN BOOT )
+ Ok!
+
+**chkrom** only supports images exactly 8KB (8192 bytes) or 16KB
+(16384 bytes). Bankswitched cartridge aren't supported. If you get
+"Unknown ROM size", make sure you're using a raw image. If it's a
+**.car** image, use **cart2rom**\(1) to make a raw image of it.
+
+OPTIONS
+=======
+
+**-disassemble**
+ Prints a disassembly of the entire cartridge.
+
+EXIT STATUS
+===========
+
+Zero for success, non-zero for failure.
+
+.. include:: manftr.rst
diff --git a/jindroush/man/manftr.rst b/jindroush/man/manftr.rst
new file mode 100644
index 0000000..192a1b4
--- /dev/null
+++ b/jindroush/man/manftr.rst
@@ -0,0 +1,21 @@
+COPYRIGHT
+=========
+
+This utility is released under the GNU General Public License.
+
+AUTHORS
+=======
+
+This utility was written by Jindrich Kubec, AKA Jindroush.
+
+This page was written by B. Watson <urchlay@slackware.uk>.
+
+SEE ALSO
+========
+
+**acvt**\(1),
+**aext**\(1),
+**bas2boot**\(1),
+**chkbas**\(1),
+**chkexe**\(1),
+**chkrom**\(1).
diff --git a/jindroush/man/manhdr.rst b/jindroush/man/manhdr.rst
new file mode 100644
index 0000000..b3db233
--- /dev/null
+++ b/jindroush/man/manhdr.rst
@@ -0,0 +1,7 @@
+.. |date| date::
+
+:Manual section: 1
+:Manual group: Jindroush's Atari 8-bit tools
+:Date: |date|
+:Version: |version|
+
diff --git a/jindroush/switches.pl b/jindroush/switches.pl
new file mode 100644
index 0000000..71f78be
--- /dev/null
+++ b/jindroush/switches.pl
@@ -0,0 +1,322 @@
+$infile = "switches.def";
+$outfile = "switches.cpp";
+
+if ( @ARGV )
+{
+ $infile = shift @ARGV;
+}
+
+if ( @ARGV )
+{
+ $outfile = shift @ARGV;
+}
+
+############################################################################
+## Script for generating switches.cpp
+##
+############################################################################
+
+open INFILE, $infile or die;
+@inf = <INFILE>;
+close INFILE;
+
+unshift @inf, "=";
+unshift @inf, "=bRet = SWFN_HELP( USAGE );";
+unshift @inf, "this help";
+unshift @inf, "help, ?";
+
+push @out, <<LOOP_START;
+
+BOOL SWITCHES_Init( int* pargc, char** argv )
+{
+BOOL bRet = TRUE;
+
+m_iArgsCurr = *pargc - 1;
+m_iArgsOrig = 1;
+m_ppcArgvOrig = argv + 1;
+m_ppcArgvCurr = argv + 1;
+
+while( m_iArgsCurr )
+{
+if ( !bRet )
+ break;
+
+if ( SWITCHES_GetValue() )
+{
+bRet = TRUE;
+*( m_ppcArgvOrig++ ) = * ( m_ppcArgvCurr - 1 );
+m_iArgsOrig++;
+}
+else
+{
+m_szSwitch++;
+
+bRet = TRUE;
+
+LOOP_START
+
+for(;;)
+{
+ $line = shift @inf;
+
+ last unless defined( $line );
+
+ chomp $line;
+
+ $line =~ s/\s+$//;
+ $line =~ s/^\s+//;
+
+ next unless $line;
+
+ unshift @inf, $line;
+
+ &switch();
+
+};
+
+push @out, <<LOOP_END;
+
+printf( "Invalid switch: %s\\n", *( m_ppcArgvCurr - 1 ) );
+return FALSE;
+} //endif
+} //while
+
+*pargc = m_iArgsOrig;
+return bRet;
+}
+LOOP_END
+
+if ( $CODE_INCLUDE{ 'SWFN_GETPATH' } )
+{
+ unshift @out, <<SWFN_GETPATH_CODE;
+
+BOOL SWFN_GETPATH( char* szPath )
+{
+char* szOrigSw = m_szSwitch;
+
+if ( !SWITCHES_GetValue() )
+{
+printf( "Missing value for switch '%s'\\n", szOrigSw );
+return FALSE;
+}
+
+strcpy( szPath, m_szSwitch );
+return TRUE;
+}
+
+SWFN_GETPATH_CODE
+}
+
+if ( $CODE_INCLUDE{ 'SWFN_NUMH' } )
+{
+ unshift @out, <<SWFN_NUMH_CODE;
+
+BOOL SWFN_NUMH( int* piNum )
+{
+char* szOrigSw = m_szSwitch;
+
+if ( !SWITCHES_GetValue() )
+{
+printf( "Missing value for switch '%s'\\n", szOrigSw );
+return FALSE;
+}
+
+sscanf( m_szSwitch, "%X", piNum );
+
+return TRUE;
+}
+SWFN_NUMH_CODE
+}
+
+unshift @out, <<SWFN_HELP_CODE2;
+return FALSE;
+}
+
+SWFN_HELP_CODE2
+
+$longest = 0;
+
+foreach $line ( @help )
+{
+ my ( $switch, $desc, $par ) = split( /\|/, $line, 3 );
+
+ my $len = length( $switch ) + length( $par );
+
+ $longest = $len if ( $len > $longest );
+}
+
+$longest += 2 + 9;
+foreach $line ( @help )
+{
+ my ( $switch, $desc, $par ) = split( /\|/, $line, 3 );
+
+ my $len = length( $switch ) + length( $par );
+
+ my $l = "printf( \"-$switch";
+
+ if ( $par )
+ {
+ $l .= " $par";
+ }
+
+ $l .= ' ' x ( $longest - length( $l ) );
+
+ $l .= " -$desc\\n\" );\n";
+
+ push @helpf, $l;
+
+}
+
+unshift @out, @helpf;
+
+unshift @out, <<SWFN_HELP_CODE1;
+
+BOOL SWFN_HELP( const char* szUsage )
+{
+if ( szUsage )
+ printf( "%s\\n", szUsage );
+SWFN_HELP_CODE1
+
+
+unshift @out, <<SWITCHES_GLOBALS;
+
+int m_iArgsCurr;
+int m_iArgsOrig;
+char** m_ppcArgvOrig;
+char** m_ppcArgvCurr;
+char* m_szSwitch;
+
+//gets one token from cmdline
+BOOL SWITCHES_GetSwitch()
+{
+if ( !m_iArgsCurr )
+ return FALSE;
+
+m_szSwitch = *( m_ppcArgvCurr++ );
+
+m_iArgsCurr--;
+
+return TRUE;
+}
+
+//gets one token, returns TRUE if value
+BOOL SWITCHES_GetValue()
+{
+if ( !SWITCHES_GetSwitch() )
+ return FALSE;
+
+switch( *m_szSwitch )
+{
+case '-':
+ return FALSE;
+default:
+ return TRUE;
+}
+}
+
+SWITCHES_GLOBALS
+
+open OUTFILE, ">$outfile";
+
+print OUTFILE "//THIS IS A GENERATED FILE. DO NOT EDIT!!!\n";
+print OUTFILE "//EDIT $infile INSTEAD!\n\n";
+
+$indent = 0;
+
+$bigline = join( '', @out );
+@out = split( /\n/, $bigline );
+
+foreach $line ( @out )
+{
+ $indent-- if ( $line =~ /}/ );
+
+ print OUTFILE "\t" x $indent, $line, "\n";
+
+ $indent++ if ( $line =~ /{/ );
+
+}
+
+close OUTFILE;
+
+sub switch()
+{
+ my $switch_desc = "";
+
+ my $switches_names = shift @inf;
+ my $switches_desc = shift @inf;
+
+ chomp $switches_desc;
+
+ my @switches = split( /,/, $switches_names );
+
+ foreach $switch ( @switches )
+ {
+ $switch =~ s/\s+$//;
+ $switch =~ s/^\s+//;
+
+ if ( defined ( $SWITCHES{ $switch } ) )
+ {
+ die "Duplicate switch $switch";
+ }
+
+ $SWITCHES{ $switch } = 1;
+
+ }
+
+ $switches_count = @switches;
+
+ $switch_desc = $switches[ 0 ] . "|" . $switches_desc . "|";
+
+ push @out, "if (";
+
+ my @asc;
+
+ foreach $switch (@switches )
+ {
+ push @asc, "!strcmp( m_szSwitch, \"$switch\" )";
+ }
+
+ push @out, join( " || ", @asc );
+
+ push @out, ")";
+
+ push @out, "\n{\n";
+
+ my @switch_pars = ();
+
+ for(;;)
+ {
+ my $par_desc = shift @inf;
+
+ my ( $par, $code ) = split( /=/, $par_desc, 2 );
+
+ $par =~ s/\s+$//;
+ $par =~ s/^\s+//;
+
+ $code =~ s/\s+$//;
+ $code =~ s/^\s+//;
+
+ last if ( !$par && !$code );
+
+ if ( $code =~ /(SWFN_\w+)/ )
+ {
+ $CODE_INCLUDE{ $1 } = 1;
+ }
+
+ if ( $par )
+ {
+ push @switch_pars, $par;
+ }
+
+ push @out, $code . "\n";
+ }
+
+ push @out, "continue;\n";
+
+ $switch_desc .= join( ' ', @switch_pars );
+
+ push @help, $switch_desc;
+
+ push @out, "}\n";
+
+}