{ This program's target is to append more than one disk image to a disk file what can be accessed by Miha Peternel's C64S.EXE or any other c64 emulators. This program is only for educ use coz Miha's emulator doesn't allow reading from after 35th. track and without it this proggy is unusable. Theory of the appending: First, I'll talk about the discs on C64. There are 35 tracks and 21/19/18/17 sectors on every tracks. All of the sectors (called blocks) are beginning with two bytes: 1st: the next track's number, if any 2nd: and the sector's number. So if we convert the second, third, fourth disk we must rewrite its track numbers (e.g. if there was a following block on 1. track 18. sector, and this is the second disk, then we must update the first byte with 35d+1d.) The directory area: 12/01=16600h= 0,1: the following DIRECTORY BLOCK's track and sector 02h-1fh: 1st. file 22 3f 2nd. 42 5f 3rd. 62 7f 4th. 82 9f 5th. a2 bf 6th. c2 df 7th. e2 ff 8th. When the following dir block is 00/ffh, then this is the latest block. And the unused blocks in the directory area contain 00/00 begin so we can simply check if the checked is a free dir block or not. When free, we can use it and the following some blocks, too; and the pointer in that block what has 00/ffh must be updated to its adress (12/sg). We can simply copy the second, third etc... directory areas (from 16600h) to the first free area BUT we must ALWAYS _ADD_ the beginning address (if the free space begun on 5h block, then its adress is 5th. block etc...). Ofcourse the file adress must be updated in the dir area, too; in the 2nd, 3rd etc... disks. Directory entry format: 0: type of file 1,2: the first data block's __track__ and sector address !!!!!!!!!! 03h-12h: name (w/ a0 end) 13h,14h: only rel files! 15h: rel files only! 16h-19h: unused 1ah-1bh: the new file's track & sector adress when we overwrite it w/ @s. 1ch, 1dh: number of blocks in the file. Type of file: 7th. bit: was it closed? The row of the blocks: as I mentioned before the LAST block always contains 00 follow track and NUMBER OF BYTES WHAT ARE BELONGING TO THE FILE!! AS SECTOR NUMBER!!! (So you can understand why are there ffh in the latest dir block's following sector!) So the best way to append: 1, COPY /b 2, RESET (result) 1st. disk 3, filepos to 16600h 4, read two TEMPBYTE bytes: does the first OR the second contain 0? 5, neither: filepos:=filepos+100h, goto 4. 6, first is 0, second is not: last_dir_block:=filepos-2; filepos:=filepos+100h, goto 4. (search for first free block) 7, both is 0: first_free_block:= filepos-2; to_add_to_all_dir_blocks:=(filepos-2 - 16600h) / 256; blocks_used_in_the_first_dir:=0; 2nd. disk: 8, for i:=1 to 684 do begin (there are 684 blocks w/ dir area ofkoz) filepos to 174848+i*256; read next track add 35d to the first byte, and write back (Assuming we are working on the testdisk.d64 with its final size) end for; 9, filepos to 174848+16600h 10, aren't both bytes 0 here? yes: goto third disk. Third disk ofcoz EQUALS TO SECOND, recursively; but we have to filepos to 2*174848+ values; add track numbers 2*35 etc...) 11, if the_first_byte<>0 and the_second_byte<>0 then j:=8, else, if if the_first_byte=0 and the_second_byte<>0, then j:=the_second_byte; (reading ONLY so many dir entries what the bloc contains. There aren't big problmes if we fill one dir BLOCK entirely with unused dir entries coz in this positioning scheme we can only filepos to a brand new BLOCK's begin! So we won't write down this OR in the program, and before the NEXT we use simple i=?8 instead of i=?j) if blocks_used_in_the_first_dir=18 then abort('Too many dir entries!!'); filepos to (16600h+(blocks_used_in_the_first_dir*256)); ( position to the next free dir block ) write(12h,blocks_used_in_the_first_dir+1) ( and soon we write out the position of the PHISICAL NEXT block's adress to the begin two bytes of the new block. If there wasn't any program errors, then ) inc(blocks_used_in_the_first_dir); if blocks_used_in_the_first_dir=18 then abort('Too many dir entries!!'); for i:=1 to 8 (there are 8 dir entries in every blocks) read 31 bytes add 35d to the 1st byte (counting from 0) filepos to (16600h+(blocks_used_in_the_first_dir*256)+(i-1)*31+2) write BACK the modified 31d bytes; (we are on the beginning byte what we just read coz of re-fileposing) end for inc(blocks_used_in_the_first_dir) goto 10, (read the following directory BLOCK) third disk: filepos to (16600h+((blocks_used_in_the_first_dir-1)*256)) (we write out to the last DIR BLOCK's beginning a 00 ff. OfCuZ we will update it if we'll have another disk!)) end prog} type one_dir_entry= array [0..31] of byte; var blocks_used_in_the_first_dir, first_free_block:integer; NUMBER_OF_FILES,j:INTEGER; B1,b2:BYTE; I, _filepos, last_dir_block, to_add_to_all_dir_blocks, dir_read_actual_pos : longint; BYTEFILE1_IN,BYTEFILE2_IN,BYTEFILE3_IN,BYTEFILE4_IN,BYTEFILE5_IN, BYTEFILE6_IN,OUTFILE:FILE OF BYTE; _32_add_filepos,phisical_addr_of_entry,temp:longint; block,entry:longint; filename:string; tempint:integer; dir_entries_of_second_disk: array [1..144] of one_dir_entry; dir_entries_of_third_disk: array [1..144] of one_dir_entry; ptr_to_second_dir:byte; { 1..144 } ptr_to_third_dir:byte; { 1..144 } begin NUMBER_OF_FILES:=PARAMCOUNT; ASSIGN(BYTEFILE1_IN,PARAMSTR(1)); RESET(BYTEFILE1_IN); ASSIGN(BYTEFILE2_IN,PARAMSTR(2)); RESET(BYTEFILE2_IN); ASSIGN(BYTEFILE3_IN,PARAMSTR(3)); RESET(BYTEFILE3_IN); ASSIGN(OUTFILE,'TESTDISK.D64'); REset(OUTFILE); { ********* } { now we fill dir_entries_of_second_disk } seek(outfile,($16602+174848)); for i:=1 to 144 do begin for j:=0 to 31 do read(outfile,dir_entries_of_second_disk[i,j]); { and we automatically update the second byte } dir_entries_of_second_disk[i,1]:=dir_entries_of_second_disk[i,1]+35; end; { reading second dir } { now we fill dir_entries_of_third_disk } seek(outfile,($16602+2*174848)); for i:=1 to 144 do begin for j:=0 to 31 do read(outfile,dir_entries_of_third_disk[i,j]); { and we automatically update the second byte } dir_entries_of_third_disk[i,1]:=dir_entries_of_third_disk[i,1]+70; end; { reading third dir } { now we search for an empty dir entry in the first dir. Read my remarks in COPY2DSK.PAS! } _filepos:=$16602; ptr_to_SECOND_dir:=1; ptr_to_third_dir:=1; block:=0; { counting the block } entry:=1; { counting the entry in all blocks } repeat seek(outfile,_filepos); _32_add_filepos:=_filepos; read(outfile,b1); { searching for a unused or deleted file in first dir. We'll put EACH entries from 2nd and 3rd disk _separately_ to first dir- this is the most dir size-saving system. So where there are free space, we fill it with a new entry } if (b1=0) or (b1=$80) then begin phisical_addr_of_entry:=_filepos; _filepos:=$16600+block*256; seek(outfile,_filepos); read(outfile,b2); read(outfile,b2); if b2=0 then begin { this is the worst case: we have the first empty entry in an unused block! } _filepos:=$16600+(block-1)*256; { always the PREVIOUS block is the last-but-one block! } b2:=18; write(outfile,b2); b2:=block; write(outfile,b2); end; seek(outfile,phisical_addr_of_entry); { and now: search for a non-empty entry in 2nd dir, and copy! } if (dir_entries_of_second_disk[ptr_to_second_dir,0]>80) then { yes, we have found a converted 2nd entry! } for i:=0 to 29 do write(outfile,dir_entries_of_second_disk[ptr_to_second_dir,i]); inc(ptr_to_second_dir); { and read the next entry if there are } end; { if we found an unused entry in the first dir } _filepos:=_32_add_filepos+32; inc(entry); if entry=9 then begin inc(block); entry:=1; end; until (dir_entries_of_second_disk[ptr_to_second_dir,3]=0) or (_filepos>=96256) or (dir_entries_of_second_disk[ptr_to_second_dir,0]=0); { we continue copying until we reach a dir entry in second dir where the first letter of the name is a 0. This means that this is the end of the dir. } if _filepos>=96256 then begin writeln(' Argh... Not enough dir entry... DELETE testdisk.d64!'); exit; end; repeat seek(outfile,_filepos); _32_add_filepos:=_filepos; read(outfile,b1); { searching for a unused or deleted file in first dir. We'll put EACH entries from 2nd and 3rd disk _separately_ to first dir- this is the most dir size-saving system. So where there are free space, we fill it with a new entry } if (b1=0) or (b1=$80) then begin phisical_addr_of_entry:=_filepos; _filepos:=$16600+block*256; seek(outfile,_filepos); read(outfile,b2); read(outfile,b2); if b2=0 then begin { this is the worst case: we have the first empty entry in an unused block! } _filepos:=$16600+(block-1)*256; { always the PREVIOUS block is the last-but-one block! } b2:=18; write(outfile,b2); b2:=block; write(outfile,b2); end; seek(outfile,phisical_addr_of_entry); { and now: search for a non-empty entry in 2nd dir, and copy! } if (dir_entries_of_third_disk[ptr_to_third_dir,0]>80) then { yes, we have found a converted 2nd entry! } for i:=0 to 29 do write(outfile,dir_entries_of_third_disk[ptr_to_third_dir,i]); inc(ptr_to_third_dir); { and read the next entry if there are } end; { if we found an unused entry in the first dir } _filepos:=_32_add_filepos+32; inc(entry); if entry=9 then begin inc(block); entry:=1; end; until (dir_entries_of_third_disk[ptr_to_third_dir,3]=0) or (_filepos>=96256) or (dir_entries_of_third_disk[ptr_to_third_dir,0]=0); { we continue copying until we reach a dir entry in third dir where the first letter of the name is a 0. This means that this is the end of the dir. } if _filepos>=96256 then begin writeln(' Argh... Not enough dir entry... DELETE testdisk.d64!'); exit; end; { INC SECOND AND THIRD DISKS' BLOCK STRING PTR } for i:=1 to 684 do begin {there are 684 blocks w/ dir area oFCuZ} {SECOND} if (i<358) or (i>358+18) then begin {we don't modify directory blocks' begin coz we won't use them anymore!} _filepos:=174848+(i-1)*256; seek(outfile,_filepos); read(outfile,b1); b1:=b1+35; _filepos:=filepos(outfile)-1; { position back to the first byte of all stored blocks } seek(outfile,_filepos); write(outfile,b1); end; {if} end; { for } for i:=1 to 683 do begin {there are 684 blocks w/ dir area oFCuZ} {THIRD} if (i<358) or (i>358+18) then begin {we don't modify directory blocks' begin coz we won't use them anymore!} _filepos:=2*174848+(i-1)*256; seek(outfile,_filepos); read(outfile,b1); b1:=b1+70; _filepos:=filepos(outfile)-1; { position back to the first byte of all stored blocks } seek(outfile,_filepos); write(outfile,b1); end; {if} end; { for } close(outfile); end. OR I:=1 TO 174848 DO BEGIN { copying the first disk } READ(BYTEFILE1_IN,B1); WRITE(outfile,B1); end; FOR I:=1 TO 174848 DO BEGIN { copying the second disk } READ(BYTEFILE2_IN,B1); WRITE(outfile,B1); end; FOR I:=1 TO 174848 DO BEGIN { copying the third disk } READ(BYTEFILE3_IN,B1); WRITE(outfile,B1); end; }