1 /*
2
3 Copyright 2021, dettus@dettus.net
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
14
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
27 */
28
29 // the purpose of this file is to read the D64 disk image files
30 // and to translate them into the .mag/.gfx format.
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "loader_appleii.h"
36 #include "loader_common.h"
37 #include "configuration.h"
38 #include "vm68k_macros.h"
39
40 #define PREAMBLE_SIZE 3
41 #define EPILOGUE_SIZE 3
42 #define ADDRBUF_SIZE 8
43 #define DATABUF_SIZE 343
44
45 #define MAXDISKS 3
46 #define MAXTRACKS 35
47 #define MAXSECTORS 16
48 #define SECTORBYTES 256
49 #define DSKTRACKSIZE (MAXSECTORS*SECTORBYTES)
50 #define DSKSIZE (MAXTRACKS*MAXSECTORS*SECTORBYTES)
51 #define NIBTRACKSIZE (MAXSECTORS*416) // TODO: why 416?
52
53
54
55 #define GAME_PAWN 0
56 #define GAME_GUILD 1
57 #define GAME_JINXTER 2
58 #define GAME_CORRUPTION 3
59 #define MAXPICTURES 32
60
61
62
63
64 #define WOZ_MAXQUARTERTRACKS (4*MAXTRACKS) // TODO: not sure what to do with this...
65 #define WOZ_BLOCKSIZE 512 // the woz format has been designed to work on SD cards. So blocks are aligned to 512 to speed up processing
66
67
68 // the most important information, parsed from the WOZ header
69 typedef struct _tWozInfo
70 {
71 int quarterTrack[WOZ_MAXQUARTERTRACKS]; // TODO: not sure what to do with this...
72 int trackStart[WOZ_MAXQUARTERTRACKS]; // the block offset within the WOZ file
73 int trackBits[WOZ_MAXQUARTERTRACKS]; // the number of bits for a track
74 unsigned int crc32_expected;
75 } tWozInfo;
76
77
loader_appleii_woz_parseheader(unsigned char * pWozBuf,int wozsize,tWozInfo * pWozInfo)78 int loader_appleii_woz_parseheader(unsigned char* pWozBuf,int wozsize,tWozInfo *pWozInfo)
79 {
80 int idx;
81 int len;
82 unsigned char donemask;
83 idx=0;
84 donemask=0;
85 while (idx<wozsize && donemask!=3)
86 {
87 if (memcmp(&pWozBuf[idx],"WOZ2",4)==0)
88 {
89 if (pWozBuf[idx+4]!=0xff || pWozBuf[idx+5]!=0xa || pWozBuf[idx+6]!=0xd || pWozBuf[idx+7]!=0xa)
90 {
91 fprintf(stderr," WOZ2 eader corruption? Expected FF 0A 0D 0A, got %02X %02X %02X %02X \n",pWozBuf[idx+4],pWozBuf[idx+5],pWozBuf[idx+6],pWozBuf[idx+7]);
92 return -1;
93 }
94 pWozInfo->crc32_expected=READ_INT32BE(pWozBuf,idx+8);
95 idx+=12;
96 }
97 else if (memcmp(&pWozBuf[idx],"INFO",4)==0)
98 {
99 len=READ_INT32LE(pWozBuf,idx+4);
100 idx+=8;
101 // skip the info chunk
102 idx+=len;
103 }
104 else if (memcmp(&pWozBuf[idx],"TMAP",4)==0)
105 {
106 int i;
107 len=READ_INT32LE(pWozBuf,idx+4);
108 idx+=8;
109 for (i=0;i<WOZ_MAXQUARTERTRACKS;i++)
110 {
111 unsigned char x;
112 x=pWozBuf[idx+i];
113 if (x>=0 && x<MAXTRACKS)
114 {
115 pWozInfo->quarterTrack[i]=x;
116 }
117 }
118 idx+=len;
119 donemask|=1;
120 }
121 else if (memcmp(&pWozBuf[idx],"TRKS",4)==0)
122 {
123 int i;
124 int idx2;
125 len=READ_INT32LE(pWozBuf,idx+4);
126 idx+=8;
127 idx2=idx;
128 for (i=0;i<WOZ_MAXQUARTERTRACKS;i++)
129 {
130 pWozInfo->trackStart[i]=WOZ_BLOCKSIZE*READ_INT16LE(pWozBuf,idx2);idx2+=2;
131 idx2+=2; //skip the block count
132 pWozInfo->trackBits[i]=READ_INT32LE(pWozBuf,idx2);idx2+=4;
133 }
134 idx+=len;
135 donemask|=2;
136
137 }
138 else if (memcmp(&pWozBuf[idx],"META",4)==0)
139 {
140 len=READ_INT32LE(pWozBuf,idx+4);
141 idx+=8;
142 // skip the info chunk
143 idx+=len;
144 }
145 else
146 {
147 fprintf(stderr,"Unknown Tag in WOZ2 detected %02X %02X %02X %02X\n",pWozBuf[idx+0],pWozBuf[idx+1],pWozBuf[idx+2],pWozBuf[idx+3]);
148 return -1;
149 }
150 }
151 if (donemask!=3)
152 {
153 fprintf(stderr," Error parsing the WOZ header\n");
154 return -1;
155 }
156 return 0;
157 }
158 // when the woz bit stream is synchronized, it can be interpreted as a nib stream.
loader_appleii_woz_synchronize(unsigned char * trackbuf,unsigned char * wozbuf,int len)159 int loader_appleii_woz_synchronize(unsigned char* trackbuf,unsigned char* wozbuf,int len)
160 {
161 int i;
162 unsigned char byte;
163 unsigned char bit;
164 unsigned int reg;
165 int addrcnt;
166 int datacnt;
167 int part_cnt;
168 int outidx;
169
170
171
172 reg=0;
173 byte=0;
174 bit=0;
175 addrcnt=0;
176 datacnt=0;
177 part_cnt=0;
178 i=0;
179 outidx=0;
180 for (i=0;i<NIBTRACKSIZE;i++) trackbuf[i]=0xff; // initialize
181 while (outidx<NIBTRACKSIZE && i<(len*2) && (part_cnt!=0 || addrcnt!=MAXSECTORS || datacnt!=MAXSECTORS))
182 {
183 int wozbyte;
184 int wozbit;
185
186 wozbyte=(i%len)/8;
187 wozbit=(i%len)%8;
188 bit=(wozbuf[wozbyte]>>(7-wozbit))&1;
189 byte<<=1;
190 byte|=bit;
191 if (byte&0x80) // byte is synchronized when the highest bit is set.
192 {
193 reg<<=8;
194 reg|=((unsigned int)byte)&0xff;
195 reg&=0x00ffffff;
196 if (part_cnt==0)
197 {
198 if (reg==0xD5AA96) // addr preamble found
199 {
200 addrcnt++;
201 trackbuf[outidx++]=0xD5; // write the preamble
202 trackbuf[outidx++]=0xAA;
203 trackbuf[outidx++]=0x96;
204 part_cnt=ADDRBUF_SIZE+EPILOGUE_SIZE; // collect 11 bytes
205 }
206 if (reg==0xD5AAAD) // data preamble found
207 {
208 datacnt++;
209 trackbuf[outidx++]=0xD5; // write the preamble
210 trackbuf[outidx++]=0xAA;
211 trackbuf[outidx++]=0xAD;
212 part_cnt=DATABUF_SIZE+EPILOGUE_SIZE; // collect 346 bytes
213 }
214 } else {
215 trackbuf[outidx++]=byte;
216 part_cnt--;
217 }
218 byte=0;
219 }
220 i++;
221 }
222 // at this point, the trackbuf contains the NIB stream, even though there is no padding between the sectors.
223 // the nib decoder will be able to handle it, even though a physical drive might not be able to.
224 return 0;
225 }
226
loader_appleii_decode_addrbuf(unsigned char * pAddrBuf,unsigned char * volume,unsigned char * track,unsigned char * sector,unsigned char * checksum)227 int loader_appleii_decode_addrbuf(unsigned char* pAddrBuf,unsigned char* volume,unsigned char* track,unsigned char* sector,unsigned char* checksum)
228 {
229 const unsigned char loader_appleii_deinterleave[16]={ 0x0,0x7,0xe,0x6,0xd,0x5,0xc,0x4,0xb,0x3,0xa,0x2,0x9,0x1,0x8,0xf };
230 int ridx;
231 unsigned char x;
232 unsigned char check;
233 ridx=0;
234 check=0;
235 #define ROL(x) ((((x)&0x80)>>7|(x)<<1)&0xff)
236 x=pAddrBuf[ridx++];x=ROL(x);x&=pAddrBuf[ridx++];*volume=x;check^=x;
237 x=pAddrBuf[ridx++];x=ROL(x);x&=pAddrBuf[ridx++];*track=x;check^=x;
238 x=pAddrBuf[ridx++];x=ROL(x);x&=pAddrBuf[ridx++];*sector=loader_appleii_deinterleave[x&0xf];check^=x;
239 x=pAddrBuf[ridx++];x=ROL(x);x&=pAddrBuf[ridx++];*checksum=x;check^=x;
240 if (check)
241 {
242 fprintf(stderr,"Warning. Checksum mismatch\n");
243 }
244 return check;
245 }
246
loader_appleii_decodenibtrack(unsigned char * pTrackBuf,int track,unsigned char * pDskBuf)247 int loader_appleii_decodenibtrack(unsigned char* pTrackBuf,int track,unsigned char* pDskBuf)
248 {
249 #define PREAMBLESIZE 3
250 #define DECODEROFFS 0x96
251 #define SECTORLSB 86
252 const unsigned char loader_appleii_addr_preamble[PREAMBLESIZE]={0xD5,0xAA,0x96};
253 const unsigned char loader_appleii_data_preamble[PREAMBLESIZE]={0xD5,0xAA,0xAD};
254 //const unsigned char loader_appleii_epilog[PREAMBLESIZE]={0xDE,0xAA,0xEB};
255
256 const unsigned char loader_appleii_translatetab[106]={
257 0x00,0x01,0xFF,0xFF,0x02,0x03,0xFF,0x04,
258 0x05,0x06,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
259 0x07,0x08,0xFF,0xFF,0xFF,0x09,0x0A,0x0B,
260 0x0C,0x0D,0xFF,0xFF,0x0E,0x0F,0x10,0x11,
261 0x12,0x13,0xFF,0x14,0x15,0x16,0x17,0x18,
262 0x19,0x1A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
263 0xFF,0xFF,0xFF,0xFF,0xFF,0x1B,0xFF,0x1C,
264 0x1D,0x1E,0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,
265 0x20,0x21,0xFF,0x22,0x23,0x24,0x25,0x26,
266 0x27,0x28,0xFF,0xFF,0xFF,0xFF,0xFF,0x29,
267 0x2A,0x2B,0xFF,0x2C,0x2D,0x2E,0x2F,0x30,
268 0x31,0x32,0xFF,0xFF,0x33,0x34,0x35,0x36,
269 0x37,0x38,0xFF,0x39,0x3A,0x3B,0x3C,0x3D,
270 0x3E,0x3F};
271
272
273 unsigned char addr_track=0;
274 unsigned char addr_sector=0;
275 unsigned char addr_volume=0;
276 unsigned char addr_checksum=0;
277 int volumeid;
278 int foundsectors;
279 int ridx;
280 int state;
281
282 volumeid=-1;
283 foundsectors=0;
284 ridx=0;
285 state=0;
286 while (ridx<(NIBTRACKSIZE+SECTORBYTES+SECTORLSB+1+9*PREAMBLESIZE))
287 {
288 switch(state)
289 {
290 case 0: // find the ADDR preamble
291 {
292 if ( pTrackBuf[(ridx+0)%NIBTRACKSIZE]==loader_appleii_addr_preamble[0] && pTrackBuf[(ridx+1)%NIBTRACKSIZE]==loader_appleii_addr_preamble[1] && pTrackBuf[(ridx+2)%NIBTRACKSIZE]==loader_appleii_addr_preamble[2])
293 {
294 ridx+=PREAMBLE_SIZE;
295 state=1;
296 foundsectors++;
297 } else ridx++;
298 }
299 break;
300 case 1: // decode the ADDR data
301 {
302 unsigned char addrbuf[ADDRBUF_SIZE];
303 int i;
304 for (i=0;i<ADDRBUF_SIZE;i++)
305 {
306 addrbuf[i]=pTrackBuf[(ridx++)%NIBTRACKSIZE];
307 }
308 loader_appleii_decode_addrbuf(addrbuf,&addr_volume,&addr_track,&addr_sector,&addr_checksum);
309 if (volumeid==-1 || volumeid==addr_volume)
310 {
311 volumeid=addr_volume;
312 } else {
313 printf("volumeid mismatch\n");
314 return -1;
315 }
316 if (addr_track!=track)
317 {
318 printf("track mismatch %d vs %d\n",addr_track,track);
319 return -1;
320 }
321 ridx+=PREAMBLESIZE; // skip over the epilogue
322 state=2; // start looking for data
323 }
324 break;
325 case 2: // find the DATA preamble
326 {
327 if ( pTrackBuf[(ridx+0)%NIBTRACKSIZE]==loader_appleii_data_preamble[0] && pTrackBuf[(ridx+1)%NIBTRACKSIZE]==loader_appleii_data_preamble[1] && pTrackBuf[(ridx+2)%NIBTRACKSIZE]==loader_appleii_data_preamble[2])
328 {
329 ridx+=PREAMBLE_SIZE;
330 state=3;
331 } else ridx++;
332 }
333 break;
334 case 3: // decode the DATA
335 {
336 unsigned char lsbbuf[SECTORLSB];
337 unsigned char accu;
338 int j;
339 accu=0;
340 for (j=0;j<SECTORLSB;j++)
341 {
342 accu^=loader_appleii_translatetab[pTrackBuf[ridx%NIBTRACKSIZE]-DECODEROFFS];
343 lsbbuf[j]=accu;
344 ridx++;
345 }
346 for (j=0;j<SECTORBYTES;j++)
347 {
348 int widx;
349 accu^=loader_appleii_translatetab[pTrackBuf[ridx%NIBTRACKSIZE]-DECODEROFFS];
350 widx=j+SECTORBYTES*addr_sector;
351 pDskBuf[widx]=accu;
352 pDskBuf[widx]<<=1;pDskBuf[widx]|=(1&lsbbuf[j%SECTORLSB]);lsbbuf[j%SECTORLSB]>>=1;
353 pDskBuf[widx]<<=1;pDskBuf[widx]|=(1&lsbbuf[j%SECTORLSB]);lsbbuf[j%SECTORLSB]>>=1;
354 ridx++;
355 }
356 ridx+=PREAMBLESIZE; // skip over the epilogue
357 state=0; // search for the next ADDR preamble
358 }
359 break;
360 }
361
362 }
363 return volumeid;
364 }
365
loader_appleii_mkgfx(unsigned char * gfxbuf,int * gfxsize,int gameid,int diskcnt,int * pDskOffs)366 int loader_appleii_mkgfx(unsigned char *gfxbuf,int* gfxsize,int gameid,int diskcnt,int *pDskOffs)
367 {
368 #define PICTURE_HOTFIX1 0x80000000
369 #define PICTURE_HOTFIX2 0x40000000
370 #define PICTURE_HOTFIX3 0x20000000
371 #define PICTURENUM 26
372 #define CODESECTIONS 5
373 #define TOTALSECTIONS (PICTURENUM+CODESECTIONS)
374
375 unsigned int hotfix1=(1<<1)|(1<< 7);
376 unsigned int hotfix2=(1<<2)|(1<<13);
377 unsigned int hotfix3=(1<<16);
378
379 if (gameid!=GAME_CORRUPTION)
380 {
381 *gfxsize=0;
382 return 0;
383 }
384 if (diskcnt!=MAXDISKS)
385 {
386 fprintf(stderr,"wrong number of floppy disks\n");
387 return -1;
388 }
389 *gfxsize=4+4*32+diskcnt*DSKSIZE;
390 {
391 unsigned char mask;
392 unsigned char byte;
393 #define UNHUFFSTART 0x00a00
394 #define DIR_START 0x997
395 #define DIR_END 0x9d5
396
397 int outidx;
398 int tracks[MAXPICTURES];
399 int sectors[MAXPICTURES];
400 int i;
401 int cnt;
402 int unhuffsize;
403 unsigned char terminal;
404 int treeoffs;
405 int bitidx;
406 int unhuffoffs;
407 int treeidx=0;
408 outidx=0;
409 cnt=0;
410
411 unhuffoffs=4+4*MAXPICTURES+pDskOffs[0]+UNHUFFSTART;
412 terminal=0;
413 unhuffsize=READ_INT16LE(gfxbuf,unhuffoffs);
414 treeoffs=unhuffoffs+2;
415 bitidx=treeoffs+16+16;
416 treeidx=0;
417 mask=0;
418 byte=0;
419 while (outidx<unhuffsize || mask)
420 {
421 unsigned char branchl,branchr;
422 unsigned char branch;
423
424 if (mask==0x00)
425 {
426 mask=0x80;
427 byte=gfxbuf[bitidx++];
428 }
429
430 branchl=gfxbuf[treeoffs+ 0+treeidx];
431 branchr=gfxbuf[treeoffs+16+treeidx];
432 branch=(byte&mask)?branchl:branchr;
433 mask>>=1;
434
435 if (branch&0x80)
436 {
437 treeidx=branch&0xf;
438 } else {
439 treeidx=0;
440 terminal<<=4;
441 terminal|=(branch&0xf);
442 terminal&=0xff;
443 if (outidx>=(DIR_START*2) && outidx<=(DIR_END*2) && ((outidx&1)==1))
444 {
445 if (cnt<TOTALSECTIONS) tracks[cnt]=terminal;
446 else {
447 sectors[cnt-TOTALSECTIONS]=terminal;
448 }
449 cnt++;
450 }
451 outidx++;
452 }
453 }
454 // read the locations of the pictures. skip over the code sections
455 for (i=0;i<PICTURENUM;i++)
456 {
457 unsigned int offs;
458 offs=4+MAXPICTURES*4;
459
460
461 offs+=((tracks[i+CODESECTIONS]&0x1f)<<12);
462 offs+=(sectors[i+CODESECTIONS]<<8);
463 if (tracks[i+CODESECTIONS]&0x80) offs+=pDskOffs[2]; // picture is on disk 3
464 else if (tracks[i+CODESECTIONS]&0x40) offs+=pDskOffs[1]; // picture is on disk 2
465 else offs+=pDskOffs[0]; // picture is on disk 1
466
467 if (hotfix1&1) offs|=PICTURE_HOTFIX1;
468 if (hotfix2&1) offs|=PICTURE_HOTFIX2;
469 if (hotfix3&1) offs|=PICTURE_HOTFIX3;
470 hotfix1>>=1;
471 hotfix2>>=1;
472 hotfix3>>=1;
473 WRITE_INT32BE(gfxbuf,4+i*4,offs);
474 }
475
476 }
477
478
479 gfxbuf[0]='M';gfxbuf[1]='a';gfxbuf[2]='P';gfxbuf[3]='8';
480
481 return 0;
482 }
483 typedef struct _tSection
484 {
485 int track;
486 int sector;
487 int disk;
488 int len;
489 int scrambled;
490 int rle;
491 } tSection;
loader_appleii_readsection(unsigned char * pOut,tSection section,unsigned char * pDskBuf,int diskcnt,int * pDskOffs,int pivot)492 int loader_appleii_readsection(unsigned char* pOut,tSection section,unsigned char* pDskBuf,int diskcnt,int* pDskOffs,int pivot)
493 {
494 int idx;
495 int outidx;
496 int firstsector;
497 int rle;
498 int rlecutoff=DSKSIZE;
499 unsigned char tmp[SECTORBYTES];
500 unsigned char lc;
501 int i;
502
503 rle=section.rle;
504 outidx=0;
505 firstsector=1;
506 idx=(section.track*MAXSECTORS+section.sector)*SECTORBYTES+pDskOffs[section.disk];
507 lc=0xff;
508
509 while (outidx<section.len)
510 {
511 int ridx;
512 int removeendmarker;
513 memcpy(tmp,&pDskBuf[idx],SECTORBYTES);
514 idx+=SECTORBYTES;
515 ridx=0;
516 removeendmarker=0;
517 if (section.scrambled)
518 {
519 loader_common_descramble(tmp,tmp,pivot,NULL,0);
520 pivot=(pivot+1)%8;
521 if (firstsector && rle)
522 {
523 rlecutoff=READ_INT16BE(tmp,0);
524 ridx=2;
525 firstsector=0;
526 }
527 }
528 for (;ridx<SECTORBYTES;ridx++)
529 {
530 unsigned char c;
531 int n;
532 c=tmp[ridx];
533 if (lc!=0 || !rle)
534 {
535 n=1;
536 lc=c;
537 } else {
538 lc=c;
539 n=c-1;
540 c=0;
541 }
542 for (i=0;i<n;i++)
543 {
544 pOut[outidx++]=c;
545 }
546 rlecutoff--;
547 if (rle && rlecutoff==0)
548 {
549 rle=0;
550 removeendmarker=1;
551 }
552 }
553 if (removeendmarker==1)
554 {
555 outidx-=4; // remove the last 4 bytes
556 }
557 }
558 if (outidx>section.len) outidx=section.len;
559
560 return outidx;
561 }
loader_appleii_mkmag(unsigned char * magbuf,int * magsize,int gameid,unsigned char * pDskBuf,int diskcnt,int * pDskOffs)562 int loader_appleii_mkmag(unsigned char* magbuf,int* magsize,int gameid,unsigned char* pDskBuf,int diskcnt,int* pDskOffs)
563 {
564 int magidx;
565 int codesize;
566 int stringidx0;
567 int string1size;
568 int string2size;
569 int dictsize;
570 int huffmantreeidx;
571 int i;
572 typedef struct _tGameInfo
573 {
574 int name_track;
575 int name_sector;
576 tSection code_section;
577 tSection code2_section;
578 int pivot_code2;
579 tSection string1_section;
580 tSection string2_section;
581 tSection dict_section;
582 int version;
583 char gamename[21];
584 } tGameInfo;
585
586 const tGameInfo loader_appleii_gameInfo[4]={
587 {0x01,0x0, {0x04,0x0,0,65536,1,0},{-1,-1,-1,-1,0,0}, -1,{0x12,0x0,0,0xc000,0,0}, {0x1e,0x0,0,0xb00,0,0}, {-1,-1,-1,0,0,0}, 0,"The Pawn"},
588 {0x00,0x9, {0x03,0x9,0,65536,1,1},{-1,-1,-1,-1,0,0}, -1,{0x12,0xb,0,0xf100,0,0}, {0x21,0xc,0,0xe00,0,0}, {-1,-1,-1,0,0,0}, 1,"The Guild of Thieves"},
589
590 {0x00,0x9, {0x08,0x2,0,0x3300,1,1},{0x00,0x0,1,0xcd00,1,0}, 7,{0x0c,0xc,1, 57344,0,0}, {0x1a,0xc,1, 24832,0,0}, {0x06,0x0,0, 8704,1,0}, 2,"Jinxter"},
591 {0x00,0x9, {0x04,0x0,0,0x4200,1,0},{0x00,0x0,1,0xbe00,1,0}, 2,{0x0b,0xe,1, 57344,0,0}, {0x19,0xe,1, 37120,0,0}, {0x08,0x2,0, 7680,1,0}, 3,"Corruption"}
592 };
593 {
594 int offs;
595 int i;
596 unsigned char c;
597 printf("Detected '%s'\n",loader_appleii_gameInfo[gameid].gamename);
598 offs=(loader_appleii_gameInfo[gameid].name_track*MAXSECTORS+loader_appleii_gameInfo[gameid].name_sector)*SECTORBYTES;
599 offs+=3;
600 i=0;
601 c=0;
602 printf("[");
603 while (i<0x2c && c!=0xa9)
604 {
605 c=pDskBuf[pDskOffs[0]+offs];
606 i++;
607 offs++;
608 if (c>=' ' && c<127) printf("%c",c);
609 }
610 printf("]\n");
611 }
612
613 magidx=42;
614 codesize=loader_appleii_readsection(&magbuf[magidx],loader_appleii_gameInfo[gameid].code_section,pDskBuf,diskcnt,pDskOffs,0);
615 codesize+=loader_appleii_readsection(&magbuf[magidx+codesize],loader_appleii_gameInfo[gameid].code2_section,pDskBuf,diskcnt,pDskOffs,loader_appleii_gameInfo[gameid].pivot_code2);
616 magidx+=codesize;
617
618 stringidx0=magidx;
619 string1size=loader_appleii_readsection(&magbuf[magidx],loader_appleii_gameInfo[gameid].string1_section,pDskBuf,diskcnt,pDskOffs,0);
620 magidx+=string1size;
621 string2size=loader_appleii_readsection(&magbuf[magidx],loader_appleii_gameInfo[gameid].string2_section,pDskBuf,diskcnt,pDskOffs,0);
622 magidx+=string2size;
623 dictsize=loader_appleii_readsection(&magbuf[magidx],loader_appleii_gameInfo[gameid].dict_section,pDskBuf,diskcnt,pDskOffs,0);
624 magidx+=dictsize;
625
626
627 {
628 int j;
629 int matchcnt;
630 huffmantreeidx=0;
631 for (i=string1size;i<string1size+string2size-6 && huffmantreeidx==0;i++)
632 {
633 matchcnt=0;
634 for (j=0;j<6;j++)
635 {
636 if (magbuf[stringidx0+i+j]==(j+1)) matchcnt++;
637 }
638 if (matchcnt>=4)
639 {
640 huffmantreeidx=i;
641 }
642 }
643 }
644
645 if (gameid==GAME_CORRUPTION) for (i=0x212a;i<0x232a;i++) magbuf[i]=0; // finishing touches on corruption
646
647 loader_common_addmagheader(magbuf,magidx,loader_appleii_gameInfo[gameid].version,codesize,string1size,string2size,dictsize,huffmantreeidx);
648 *magsize=magidx;
649 return 0;
650
651 }
652
loader_appleii(char * appleiiname,char * magbuf,int * magsize,char * gfxbuf,int * gfxsize)653 int loader_appleii(char *appleiiname,
654 char *magbuf,int* magsize,
655 char *gfxbuf,int* gfxsize)
656 {
657 unsigned char* pDskBuf;
658 char filename[1024];
659 unsigned char trackbuf[NIBTRACKSIZE];
660 int i,l;
661 int j;
662 int diskcnt;
663 int volumeids[MAXDISKS];
664 int dskidx;
665 int gameid;
666 int diskoffs[MAXDISKS];
667 tWozInfo wozInfo;
668 FILE *f;
669
670 #define SIZE_NIBIMAGE 232960
671 #define SIZE_2MGIMAGE 143424
672 #define SIZE_DSKIMAGE 143360
673
674 pDskBuf=(unsigned char*)&gfxbuf[4+MAXPICTURES*4];
675 l=strlen(appleiiname);
676 j=0;
677 diskcnt=0;
678 dskidx=0;
679 for (i=0;i<l+1 && diskcnt<MAXDISKS;i++)
680 {
681 if (appleiiname[i]!=',') filename[j++]=appleiiname[i];
682 filename[j]=0;
683
684 if (appleiiname[i]==',' || appleiiname[i]==0)
685 {
686 int n;
687 int filesize;
688 f=fopen(filename,"rb");
689 if (!f)
690 {
691 fprintf(stderr,"Unable to open [%s]\n",filename);
692 return -1;
693 }
694 fseek(f,0L,SEEK_END);
695 filesize=ftell(f);
696 fseek(f,0L,SEEK_SET);
697 n=0;
698 if (filesize==SIZE_NIBIMAGE)
699 {
700 for (j=0;j<MAXTRACKS;j++)
701 {
702 n+=fread(trackbuf,sizeof(char),NIBTRACKSIZE,f);
703 volumeids[diskcnt]=loader_appleii_decodenibtrack(trackbuf,j,&pDskBuf[dskidx]);
704 dskidx+=MAXSECTORS*SECTORBYTES;
705 }
706 }
707 else if (filesize==SIZE_2MGIMAGE)
708 {
709 n+=fread(&pDskBuf[dskidx],sizeof(char),0x40,f); // read in the header. https://apple2.org.za/gswv/a2zine/Docs/DiskImage_2MG_Info.txt
710 volumeids[diskcnt]=pDskBuf[dskidx+0x10]; // according to my observations, this is where the volume ID is
711 n+=fread(&pDskBuf[dskidx],sizeof(char),DSKSIZE,f);
712 dskidx+=DSKSIZE;
713 }
714 else
715 {
716 n+=fread(&pDskBuf[dskidx],sizeof(char),filesize,f); // read in the full file. maybe it is a .WOZ?
717 if (pDskBuf[dskidx+0]=='W' && pDskBuf[dskidx+1]=='O' && pDskBuf[dskidx+2]=='Z' && pDskBuf[dskidx+3]=='2')
718 {
719
720 int dskidx0;
721 // the file is a .woz file, basically an unsynchronized .nib file with a header.
722 // the idea is to synchronize the tracks and treat it as a NIB file.
723
724 // first, the wo header needs to be parsed, to find the tracks within the diskfile
725 if (loader_appleii_woz_parseheader(&pDskBuf[dskidx],filesize,&wozInfo))
726 {
727 return -1;
728 }
729 // at this point, the header information has been read. the tracks can be found, and the translation from WOZ to DSK can be written into the DskBuf (inplace)
730 dskidx0=dskidx;
731 for (j=0;j<MAXTRACKS;j++)
732 {
733 int start;
734 int len;
735 int quarterTrack;
736
737 quarterTrack=j;//wozInfo.quarterTrack[j];
738 start=wozInfo.trackStart[quarterTrack];
739 len=wozInfo.trackBits[quarterTrack];
740
741 if (start)
742 {
743 loader_appleii_woz_synchronize(trackbuf,&pDskBuf[dskidx0+start],len);
744 volumeids[diskcnt]=loader_appleii_decodenibtrack(trackbuf,j,&pDskBuf[dskidx]);
745 }
746 dskidx+=MAXSECTORS*SECTORBYTES;
747 }
748
749
750 } else {
751 fprintf(stderr,"Unexpected filesize %d bytes.\n",filesize);
752 return -1;
753 }
754 }
755 fclose(f);
756 printf("read %d bytes from [%s]. Volume ID [%02X]\n",n,filename,volumeids[diskcnt]);
757 diskcnt++;
758 j=0;
759 }
760 }
761 gameid=-1;
762
763 for (i=0;i<diskcnt;i++)
764 {
765 int newgameid;
766 int disknum;
767
768 disknum=-1;
769 switch(volumeids[i])
770 {
771 case 0x68: newgameid=GAME_PAWN; disknum=volumeids[i]-0x68;break;
772 case 0x69: newgameid=GAME_GUILD; disknum=volumeids[i]-0x69;break;
773 case 0x70:
774 case 0x71: newgameid=GAME_JINXTER; disknum=volumeids[i]-0x70;break;
775 case 0x72:
776 case 0x73:
777 case 0x74: newgameid=GAME_CORRUPTION; disknum=volumeids[i]-0x72;break;
778 default:
779 return -1;
780 }
781 if (gameid==-1 || gameid==newgameid) gameid=newgameid;
782 else {
783 fprintf(stderr,"Game detection ambigous\n");
784 return -1;
785 }
786 if (disknum>=0 && disknum<MAXDISKS)
787 {
788 diskoffs[disknum]=i*DSKSIZE;
789 }
790 }
791 if (gameid==-1)
792 {
793 fprintf(stderr,"Unable to detect the game\n");
794 return -1;
795 }
796
797
798 loader_appleii_mkmag((unsigned char*)magbuf,magsize,gameid,pDskBuf,diskcnt,diskoffs); // since the memory for the gfx buffer includes the dskbuf, this is enough
799 return loader_appleii_mkgfx((unsigned char*)gfxbuf,gfxsize,gameid,diskcnt,diskoffs); // since the memory for the gfx buffer includes the dskbuf, this is enough
800
801 }
802
803
804