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_d64.h"
36 #include "loader_common.h"
37 #include "configuration.h"
38 #include "vm68k_macros.h"
39 
40 #define D64_IMAGESIZE   174848
41 #define D64_TRACKNUM    40
42 #define D64_SECTORSIZE  256
43 #define D64_MAXENTRIES  64
44 #define D64_BITMASKSIZE 6080    // pictures have a resolution of 160x152 pixels
45 
46 typedef enum _eGame
47 {
48 	GAME_UNKNOWN,
49 	GAME_JINXTER,
50 	GAME_CORRUPTION,
51 	GAME_FISH,
52 	GAME_MYTH,
53 	GAME_PAWN,
54 	GAME_GUILD
55 } eGame;
56 
57 typedef enum _eFileType
58 {
59 	TYPE_UNKNOWN,
60 	TYPE_CODE1,
61 	TYPE_CODE2,
62 	TYPE_CODE1_ENCRYPTED,
63 	TYPE_CODE2_ENCRYPTED,
64 	TYPE_STRING1,
65 	TYPE_STRING2,
66 	TYPE_DICTIONARY,
67 	TYPE_PICTURE,
68 	TYPE_CAMEO
69 } eFileType;
70 
71 typedef struct _tFileEntry
72 {
73 	unsigned int offset;    // where in the image is the file?
74 	unsigned char track;    // track
75 	unsigned char sector;   // sector
76 	int len;                // do not trust this one
77 	int side;               // A, B or both?
78 	eFileType	fileType;
79 } tFileEntry;
80 
81 
82 typedef struct _tGameInfo
83 {
84 	eGame game;			// the enumeration for the game
85 	int sides;			// how many floppy sides did this game occupy?
86 	char magicword[5];		// the word, that is hidden in the second sector of the disk image
87 	int version;			// the virtual machine's version
88 	char name[32];			// human readable
89 	signed char order[32];		// the order in which the pictures can be found in the images are not the same as in other releases.
90 } tGameInfo;
91 
92 const tGameInfo loader_d64_gameinfo[6]=
93 {
94 								// the pictures are ordered different from the other releases. there, this list would have been 0 1 2 3 4...
95 								// but the C64 had only a limited amount of floppy disk space.
96 	{GAME_JINXTER	,2,"ARSE",2,"Jinxter",			 { 4, 0, 5, 6, 7,-1, 8, 1, 9,10,11,12, 13,14,15,16, 17, 2, 3,27, 18,19,20,21, 22,23,24,25, 26,27,26,26}},
97 	{GAME_CORRUPTION,2,"COKE",3,"Corruption",		 { 24, 8, 9,25, 10,13,15,16, 17, 1,18,23, 21, 6, 5, 4, 12,14, 2, 3, 11,20, 7,22, 19, 0,-1,-1, -1,-1,-1,-1 }},
98 	{GAME_FISH	,2,"GLUG",3,"Fish!",			 { 3,21, 8,11, 18,16,17, 4, 2, 5, 1, 6, 9,10,14,20, 22,24,25, 0, 15,23, 7,19, 13,-1,26,-1, -1,-1,-1,-1 }},
99 	{GAME_MYTH	,1,"GODS",3,"Myth",			 { 0, 1, 2, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}},
100 	{GAME_PAWN	,2,"PAWN",0,"The Pawn",			 { 4,26,13,23, 0, 8,29, 5, 18,19, 3, 9, 12,11,16,22, 17,21,28, 6, 27,25,24, 2, 1,20,14, 7, 15,10,-1,-1 }},
101 	{GAME_GUILD	,2,"SWAG",1,"The Guild of Thieves",	 { 9,17,20, 0,26,19,11,12, 4, 5, 2,13,14, 8, 6, 1,15,16, 3,24,21,28,22,25,18,23, 7,10,27,-1,-1,-1}},
102 };
103 
loader_d64_detectgame(unsigned char * diskram)104 int loader_d64_detectgame(unsigned char* diskram)
105 {
106 
107 	// find the magic word
108 	int i;
109 	char tmp[5];
110 #define	MAGIC_WORD_LOCATION	0x1eb
111 	// at those positions in the image, a magic word is hidden.
112 	// it can be used to detect the game
113 	tmp[0]=diskram[MAGIC_WORD_LOCATION+0];
114 	tmp[1]=diskram[MAGIC_WORD_LOCATION+1];
115 	tmp[2]=diskram[MAGIC_WORD_LOCATION+2];
116 	tmp[3]=diskram[MAGIC_WORD_LOCATION+3];
117 	tmp[4]=0;
118 
119 	for (i=0;i<6;i++)
120 	{
121 		if (strncmp(tmp,loader_d64_gameinfo[i].magicword,4)==0) return i;
122 	}
123 
124 	return -1;
125 }
126 const unsigned char loader_d64_sectorcnt[D64_TRACKNUM]=
127 {
128 	21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,     // track 1-17
129 	19,19,19,19,19,19,19,   // track 18-24
130 	18,18,18,18,18,18,      // track 25-30
131 	17,17,17,17,17,17,17,17,17,17   // track 31-40
132 };
133 
loader_d64_readEntries(unsigned char * d64image,int d64size,tFileEntry * pEntries,int * pEntrynum)134 void loader_d64_readEntries(unsigned char* d64image,int d64size,tFileEntry* pEntries,int* pEntrynum)
135 {
136 	int i;
137 	int offsets[40];
138 	int cnt;
139 
140 	// first step: calculate the offsets for the tracks
141 	offsets[0]=0;
142 	for (i=1;i<D64_TRACKNUM;i++)
143 	{
144 		offsets[i]=offsets[i-1]+loader_d64_sectorcnt[i-1]*D64_SECTORSIZE;
145 	}
146 	cnt=0;
147 	// read the entries, and translate it into offsets within the d64 image
148 	for (i=0;i<D64_MAXENTRIES;i++)
149 	{
150 		unsigned char track;
151 		unsigned char sect;
152 		unsigned char side;
153 		unsigned char len;
154 		int newoffs;
155 
156 		// 1, entry, 4 bytes. in sector 2.
157 		track=d64image[2*D64_SECTORSIZE+i*4+0];
158 		sect =d64image[2*D64_SECTORSIZE+i*4+1];
159 		len  =d64image[2*D64_SECTORSIZE+i*4+2];
160 		side =d64image[2*D64_SECTORSIZE+i*4+3]&3;
161 
162 
163 		if (len)
164 		{
165 			newoffs=offsets[track]+sect*D64_SECTORSIZE;
166 			pEntries[cnt].offset=newoffs;
167 			pEntries[cnt].track=track;
168 			pEntries[cnt].sector=sect;
169 			pEntries[cnt].len=len;
170 			pEntries[cnt].side=side;
171 			pEntries[cnt].fileType=TYPE_UNKNOWN;
172 
173 			cnt++;
174 		}
175 	}
176 	*pEntrynum=cnt;
177 }
178 
loader_d64_readSector(unsigned char * d64image,int track,int sect,unsigned char * buf)179 void loader_d64_readSector(unsigned char* d64image,int track,int sect,unsigned char* buf)
180 {
181 	int i;
182 	int offset;
183 
184 	// first step: calculate the offsets for the tracks
185 	offset=sect*D64_SECTORSIZE;
186 	for (i=1;i<track;i++)
187 	{
188 		offset+=loader_d64_sectorcnt[i-1]*D64_SECTORSIZE;
189 	}
190 	if ((offset+256)>D64_IMAGESIZE)
191 	{
192 		return;
193 	}
194 	for (i=0;i<256;i++) buf[i]=d64image[offset++];
195 }
196 
loader_d64_identifyEntries(unsigned char * d64image,tFileEntry * pEntries,int entryNum)197 void loader_d64_identifyEntries(unsigned char* d64image,tFileEntry* pEntries,int entryNum)
198 {
199 	int i;
200 	unsigned char tmp1[256];
201 	unsigned char tmp2[256];
202 	int sideoffsets[4]={-1,-1,-1,-1};
203 
204 	// some file types have a fixed position in the list
205 	pEntries[2].fileType=TYPE_STRING1;
206 	pEntries[3].fileType=TYPE_STRING2;
207 	pEntries[4].fileType=TYPE_CAMEO;
208 	// first: find the code block
209 	for (i=0;i<entryNum;i++)
210 	{
211 		loader_d64_readSector(&d64image[0],pEntries[i].track,pEntries[i].sector,tmp1);
212 		loader_d64_readSector(&d64image[D64_IMAGESIZE],pEntries[i].track,pEntries[i].sector,tmp2);
213 
214 		if (tmp1[0]==0x49 && tmp1[1]==0xfa)	// 0x49fa is ALWAYS the first instruction.
215 		{
216 			pEntries[i].fileType=TYPE_CODE1;
217 			pEntries[1].fileType=TYPE_CODE2;
218 			pEntries[i+1].fileType=TYPE_DICTIONARY;
219 			sideoffsets[pEntries[i].side]=0;
220 		}
221 		else if (tmp2[0]==0x49 && tmp2[1]==0xfa)	// 0x49fa is ALWAYS the first instruction.
222 		{
223 			pEntries[i].fileType=TYPE_CODE1;
224 			pEntries[1].fileType=TYPE_CODE2;
225 			pEntries[i+1].fileType=TYPE_DICTIONARY;
226 			sideoffsets[pEntries[i].side]=D64_IMAGESIZE;
227 		} else {
228 			loader_common_descramble(tmp1,tmp1,0,NULL,0);
229 			loader_common_descramble(tmp2,tmp2,0,NULL,0);
230 			if ((tmp1[0]==0x49 || tmp1[2]==0x49) && (tmp1[1]==0xfa || tmp1[3]==0xfa))	// 0x49fa is ALWAYS the first instruction. run level encoded files start with a 2 byte header.
231 			{
232 				pEntries[i].fileType=TYPE_CODE1_ENCRYPTED;
233 				pEntries[1].fileType=TYPE_CODE2_ENCRYPTED;
234 				pEntries[i+1].fileType=TYPE_DICTIONARY;
235 				sideoffsets[pEntries[i].side]=0;
236 			}
237 			if ((tmp2[0]==0x49 || tmp2[2]==0x49) && (tmp2[1]==0xfa || tmp2[3]==0xfa))	// 0x49fa is ALWAYS the first instruction. run level encoded files start with a 2 byte header.
238 			{
239 				pEntries[i].fileType=TYPE_CODE1_ENCRYPTED;
240 				pEntries[1].fileType=TYPE_CODE2_ENCRYPTED;
241 				pEntries[i+1].fileType=TYPE_DICTIONARY;
242 				sideoffsets[pEntries[i].side]=D64_IMAGESIZE;
243 			}
244 		}
245 	}
246 	if (sideoffsets[1]==-1)		sideoffsets[1]=D64_IMAGESIZE-sideoffsets[2];
247 	else if (sideoffsets[2]==-1)	sideoffsets[2]=D64_IMAGESIZE-sideoffsets[1];
248 	sideoffsets[0]=0;
249 	sideoffsets[3]=0;
250 
251 	// step2: identify all the pictures
252 	// maybe there is a proper way to determine it from the data. through some form of directory i have not found yet.
253 	// so here is what i do: I just check if the sector starts with the sequence 3d 82 81... or 3e 82 81, heralding
254 	// the size of the huffman tree and the first two branches which are never a terminal symbol.
255 	// (at least in the releases I dealt with)
256 	for (i=0;i<entryNum;i++)
257 	{
258 		pEntries[i].offset+=sideoffsets[pEntries[i].side];
259 		if (pEntries[i].fileType==TYPE_UNKNOWN)
260 		{
261 			loader_d64_readSector(&d64image[sideoffsets[pEntries[i].side]],pEntries[i].track,pEntries[i].sector,tmp1);
262 			if ((tmp1[0]==0x3d || tmp1[0]==0x3e) && tmp1[1]==0x82 && tmp1[2]==0x81) pEntries[i].fileType=TYPE_PICTURE;
263 		}
264 	}
265 
266 }
loader_d64_advanceSector(int * pTrack,int * pSector)267 void loader_d64_advanceSector(int *pTrack,int *pSector)
268 {
269 	int sect;
270 	int track;
271 
272 	track=*pTrack;
273 	sect=*pSector;
274 	sect=sect+1;
275 	if (sect==loader_d64_sectorcnt[track-1])
276 	{
277 		sect=0;
278 		track++;
279 		if (track==18) track+=1;        // skip the directory track
280 	}
281 	*pTrack=track;
282 	*pSector=sect;
283 }
284 
loader_d64_readCode1(unsigned char * d64image,tFileEntry * pEntries,int entryNum,unsigned char * pCode1Buf,int * pCode1Size)285 int loader_d64_readCode1(unsigned char* d64image,tFileEntry *pEntries,int entryNum,unsigned char* pCode1Buf,int* pCode1Size)
286 {
287 	int i;
288 	int j;
289 	int outcnt;
290 	int rle;
291 	int inputsize;
292 	int track;
293 	int sect;
294 	int len;
295 	int offset;
296 	int encrypted;
297 	unsigned char tmp[256];
298 
299 	outcnt=0;
300 	rle=0;
301 	offset=0;
302 	encrypted=0;
303 
304 	track=sect=len=0;
305 	inputsize=len*256;
306 	for (i=0;i<entryNum;i++)
307 	{
308 		if (pEntries[i].fileType==TYPE_CODE1 || pEntries[i].fileType==TYPE_CODE1_ENCRYPTED)
309 		{
310 			if (pEntries[i].fileType==TYPE_CODE1_ENCRYPTED) encrypted=1;
311 			if (pEntries[i].offset>=D64_IMAGESIZE) offset=D64_IMAGESIZE;
312 
313 			track=pEntries[i].track;
314 			sect =pEntries[i].sector;
315 			len  =pEntries[i].len;
316 		}
317 	}
318 
319 	rle=0;
320 	inputsize=len*D64_SECTORSIZE;
321 	for (i=0;i<len;i++)
322 	{
323 		int start;
324 		loader_d64_readSector(&d64image[offset],track,sect,tmp);
325 		loader_d64_advanceSector(&track,&sect);
326 		start=0;
327 		if (encrypted)
328 		{
329 			loader_common_descramble(tmp,tmp,i,NULL,0);
330 		}
331 		if (i==0)
332 		{
333 			if (tmp[0]==0x49 && tmp[1]==0xfa)
334 			{
335 				rle=0;
336 			} else {
337 				inputsize=tmp[0]*256+tmp[1]-2;
338 				rle=1;
339 				start=2;
340 			}
341 		}
342 		for (j=start;j<D64_SECTORSIZE && inputsize;j++,inputsize--)
343 		{
344 			if (rle==2)
345 			{
346 				int k;
347 				for (k=0;k<tmp[j]-1;k++) pCode1Buf[outcnt++]=0;
348 				rle=1;
349 			} else {
350 				pCode1Buf[outcnt++]=tmp[j];
351 			}
352 			if (tmp[j]==0x00 && rle==1)
353 			{
354 				rle=2;
355 			}
356 		}
357 	}
358 	*pCode1Size=outcnt;
359 	return 0;
360 }
361 
loader_d64_readCode2(unsigned char * d64image,tFileEntry * pEntries,int entryNum,unsigned char * pCode2Buf,int * pCode2Size)362 int loader_d64_readCode2(unsigned char* d64image,tFileEntry *pEntries,int entryNum,unsigned char* pCode2Buf,int* pCode2Size)
363 {
364 	int i;
365 	int j;
366 	int outcnt;
367 	int track,sect,len;
368 	int offset;
369 	int encrypted;
370 	int scrambleoffs;
371 	unsigned char tmp[256];
372 
373 	track=sect=len=0;
374 	offset=0;
375 	encrypted=0;
376 	scrambleoffs=0;
377 	for (i=0;i<entryNum;i++)
378 	{
379 		if (pEntries[i].fileType==TYPE_CODE1_ENCRYPTED)
380 		{
381 			scrambleoffs=pEntries[i].len;
382 		}
383 		if (pEntries[i].fileType==TYPE_CODE2 || pEntries[i].fileType==TYPE_CODE2_ENCRYPTED)
384 		{
385 			if (pEntries[i].fileType==TYPE_CODE2_ENCRYPTED) encrypted=1;
386 			if (pEntries[i].offset>=D64_IMAGESIZE) offset=D64_IMAGESIZE;
387 			track=pEntries[i].track;
388 			sect =pEntries[i].sector;
389 			len  =pEntries[i].len;
390 		}
391 	}
392 
393 
394 	outcnt=0;
395 	for (i=0;i<len;i++)
396 	{
397 		loader_d64_readSector(&d64image[offset],track,sect,tmp);
398 		if (encrypted) loader_common_descramble(tmp,tmp,i+scrambleoffs,NULL,0);
399 		loader_d64_advanceSector(&track,&sect);
400 		for (j=0;j<256;j++)
401 		{
402 			pCode2Buf[outcnt++]=tmp[j];
403 		}
404 	}
405 	*pCode2Size=outcnt;
406 	return 0;
407 }
loader_d64_readStrings(unsigned char * d64image,tFileEntry * pEntries,int entryNum,unsigned char * pStringBuf,int * string1size,int * string2size,int * dictsize)408 int loader_d64_readStrings(unsigned char* d64image,tFileEntry* pEntries,int entryNum,unsigned char* pStringBuf,int* string1size,int* string2size,int* dictsize)
409 {
410 	int i;
411 	int j;
412 	int k;
413 	int outcnt;
414 	unsigned char tmp[256];
415 	int track,sect,len;
416 	int cnt[3]={0};
417 	int number=0;
418 	int offset;
419 	int encrypted;
420 
421 
422 	outcnt=0;
423 	for (i=0;i<entryNum;i++)
424 	{
425 		track=sect=len=offset=0;
426 
427 		if (pEntries[i].fileType==TYPE_STRING1 || pEntries[i].fileType==TYPE_STRING2 || pEntries[i].fileType==TYPE_DICTIONARY)
428 		{
429 			encrypted=0;
430 			track=pEntries[i].track;
431 			sect =pEntries[i].sector;
432 			len  =pEntries[i].len;
433 			if (pEntries[i].fileType==TYPE_DICTIONARY)
434 			{
435 				encrypted=1;
436 			}
437 			if (pEntries[i].offset>=D64_IMAGESIZE)
438 			{
439 				offset=D64_IMAGESIZE;
440 			} else {
441 				offset=0;
442 			}
443 
444 			for (j=0;j<len;j++)
445 			{
446 				loader_d64_readSector(&d64image[offset],track,sect,tmp);
447 				if (encrypted) loader_common_descramble(tmp,tmp,j,NULL,0);
448 				loader_d64_advanceSector(&track,&sect);
449 				for (k=0;k<256;k++)
450 				{
451 					pStringBuf[outcnt++]=tmp[k];
452 				}
453 				cnt[number]+=256;
454 			}
455 			number++;
456 		}
457 	}
458 	*string1size	=cnt[0];
459 	*string2size	=cnt[1];
460 	*dictsize	=cnt[2];
461 	return 0;
462 }
loader_d64(char * d64name,char * magbuf,int * magsize,char * gfxbuf,int * gfxsize)463 int loader_d64(char* d64name,
464 		char *magbuf,int* magsize,
465 		char* gfxbuf,int* gfxsize)
466 {
467 	char* filename[2];
468 	int i;
469 	int l;
470 	int gfxsize0;
471 	unsigned char *d64image;
472 	int sidecnt;
473 	int gameID;
474 	int entryNum;
475 	tFileEntry entries[D64_MAXENTRIES];
476 	FILE *f;
477 	int code1size,code2size,string1size,string2size,dictsize;
478 	unsigned char *gfxptr;
479 
480 
481 	// i am using the gfx buffer as temporary memory. I suppose I could malloc. But why? ;)
482 	gfxsize0=*gfxsize;
483 	gfxptr=(unsigned char*)gfxbuf;
484 
485 	if (gfxsize0<4*D64_IMAGESIZE)
486 	{
487 		fprintf(stderr,"not enough memory to load D64 images. sorry.\n");
488 		return -1;
489 	}
490 
491 	d64image=(unsigned char*)&gfxbuf[2*D64_IMAGESIZE];
492 
493 	filename[0]=&d64name[0];
494 	filename[1]=&d64name[0];
495 	sidecnt=1;
496 	l=strlen(d64name);
497 	for (i=0;i<l;i++)
498 	{
499 		if (d64name[i]==',')
500 		{
501 			d64name[i]=0;
502 			filename[1]=&d64name[i+1];
503 			sidecnt++;
504 			if (sidecnt>2)
505 			{
506 				fprintf(stderr,"Please provide no more than 2 filenames, separated by ,\n");
507 				return -1;
508 			}
509 		}
510 	}
511 	// load the game
512 	for (i=0;i<sidecnt;i++)
513 	{
514 		int n;
515 		f=fopen(filename[i],"rb");
516 		if (!f)
517 		{
518 			fprintf(stderr,"unable to open [%s]. Sorry.\n",filename[i]);
519 			return -1;
520 		}
521 		n=fread(&d64image[i*D64_IMAGESIZE],sizeof(char),D64_IMAGESIZE,f);
522 		fclose(f);
523 		if (n!=D64_IMAGESIZE)
524 		{
525 			fprintf(stderr,"[%s] does not look like a D64 image\n",filename[i]);
526 			return -1;
527 		}
528 	}
529 	// now the images are in memory. now we can parse them.
530 	// first, find out which game it is
531 	gameID=loader_d64_detectgame(d64image);
532 	if (gameID==-1)
533 	{
534 		fprintf(stderr,"unable to determine the game\n");
535 		return -1;
536 	}
537 
538 	if (loader_d64_gameinfo[gameID].sides!=sidecnt)
539 	{
540 		fprintf(stderr,"please provide all the floppy images.\n");
541 		return -1;
542 	}
543 
544 	// then, find the entries in the file list
545 	loader_d64_readEntries(d64image,D64_IMAGESIZE,entries,&entryNum);
546 	loader_d64_identifyEntries(d64image,entries,entryNum);	// and figure out if they are code, pictures or something else
547 
548 
549 	{
550 		int huffmantreeidx;
551 		int magidx;
552 		////////////////// LOAD THE MAG BUFFER /////////////////
553 		magidx=42;	// leave some room for the header
554 		loader_d64_readCode1(d64image,entries,entryNum,(unsigned char*)&magbuf[magidx],&code1size);
555 		magidx+=code1size;
556 		loader_d64_readCode2(d64image,entries,entryNum,(unsigned char*)&magbuf[magidx],&code2size);
557 		magidx+=code2size;
558 		loader_d64_readStrings(d64image,entries,entryNum,(unsigned char*)&magbuf[magidx],&string1size,&string2size,&dictsize);
559 		huffmantreeidx=0;
560 
561 		// within the string buffer, there is the beginning of the huffman tree
562 		if (loader_d64_gameinfo[gameID].version<=1)
563 		{
564 			huffmantreeidx=string1size;		// the PAWN and GUILD of Thieves had the beginning of the huffman tree in the second string buffer.
565 		} else {
566 			int i;
567 			// there might be a better way to look for it, but in every C64 game, it starts with 01 02 03.
568 			// and before that, there are a handful of bytes that are =0.
569 			// in addition to this, it is aligned to sectors, so its indes has to be a multiple of 256.
570 			for (i=0x100;i<string1size+string2size;i+=0x100)
571 			{
572 				if (	magbuf[magidx+i-3]==0x00 && magbuf[magidx+i-2]==0x00 && magbuf[magidx+i-1]==0x00 &&			// the previous sector ends with 0x00
573 					magbuf[magidx+i+0]==0x01 && magbuf[magidx+i+1]==0x02 && magbuf[magidx+i+2]==0x03) huffmantreeidx=i;	// the sector with the huffmann tree starts with 0x01 0x02 0x03
574 			}
575 		}
576 
577 		magidx+=string1size+string2size+dictsize;
578 		loader_common_addmagheader((unsigned char*)magbuf,magidx,loader_d64_gameinfo[gameID].version,code1size+code2size,string1size,string2size,dictsize,huffmantreeidx);
579 
580 		if (loader_d64_gameinfo[gameID].game==GAME_MYTH && magbuf[0x3080]==0x66) magbuf[0x3080]=0x60;	// final touch
581 
582 		*magsize=magidx;
583 		/////////// MAG IS FINISHED ////////////////////////////////
584 	}
585 	{
586 		unsigned int picoffs[32]={0};
587 		int side;
588 		int piccnt;
589 		int gfxidx;
590 
591 
592 
593 		side=-1;
594 		piccnt=0;
595 
596 		////////////// LOAD THE GFX BUFFER /////////////////
597 		gfxidx=4+4*32+1;	// leave some room for the magic word, offsets and the game's version
598 
599 		// just copy the picture data into the GFX buffer. It will be parsed and unpacked later.
600 		for (i=0;i<entryNum;i++)
601 		{
602 			if (entries[i].fileType==TYPE_PICTURE)
603 			{
604 				int track,sector,offset,len;
605 				int j;
606 				if (side==-1)
607 				{
608 					side=entries[i].side;
609 				}
610 				else if (side!=entries[i].side)
611 				{
612 					side=entries[i].side;
613 				}
614 				track	=entries[i].track;
615 				sector	=entries[i].sector;
616 				offset	=entries[i].offset;if (offset>=D64_IMAGESIZE) offset=D64_IMAGESIZE; else offset=0;
617 				len	=entries[i].len;
618 
619 				picoffs[piccnt]=gfxidx;
620 				for (j=0;j<len && track<36;j++)
621 				{
622 					loader_d64_readSector(&d64image[offset],track,sector,(unsigned char*)&gfxbuf[gfxidx]);
623 					loader_d64_advanceSector(&track,&sector);
624 					gfxidx+=D64_SECTORSIZE;
625 				}
626 				piccnt++;
627 			}
628 		}
629 
630 		*gfxsize=gfxidx;
631 
632 		gfxidx=0;
633 		// now the buffer is complete. write the header.
634 		gfxbuf[gfxidx++]='M';
635 		gfxbuf[gfxidx++]='a';
636 		gfxbuf[gfxidx++]='P';
637 		gfxbuf[gfxidx++]='5';
638 		for (i=0;i<32;i++)
639 		{
640 			int order;
641 			order=loader_d64_gameinfo[gameID].order[i];
642 			WRITE_INT32BE(gfxptr,gfxidx ,(order==-1)?0xffffffff:picoffs[loader_d64_gameinfo[gameID].order[i]]);
643 			gfxidx+=4;
644 		}
645 		gfxbuf[4+4*32]=loader_d64_gameinfo[gameID].version;
646 		/////////// GFX is finished ///////////////
647 	}
648 	return 0;
649 }
650 
651 
652