1 /*  Sarien - A Sierra AGI resource interpreter engine
2  *  Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka
3  *
4  *  $Id: agi_v4.c,v 1.8 2001/09/06 18:52:14 cmatsuoka Exp $
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; see docs/COPYING for further details.
9  */
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include "sarien.h"
14 #include "agi.h"
15 
16 #if defined PALMOS
17 
18 static int agi_v4_init (void);
19 static int agi_v4_deinit (void);
20 static int agi_v4_detect_game (char *);
21 static int agi_v4_load_resource (int, int);
22 static int agi_v4_unload_resource (int, int);
23 static int agi_v4_load_objects(char *);
24 static int agi_v4_load_words(char *);
25 
26 UINT32 pdb_read_dword(UINT8 *mem);
27 UINT16 pdb_read_word(UINT8 *mem);
28 int load_v2_dir(struct agi_dir *agid, int offset, UINT32 flen, FILE *fp);
29 int load_v3_dir(struct agi_dir *agid, int offs, UINT32 len, FILE *fp);
30 
31 extern struct agi_picture pictures[];
32 extern struct agi_logic logics[];
33 extern struct agi_view views[];
34 extern struct agi_sound sounds[];
35 
36 struct agi_loader agi_v4 = {
37 	4,
38 	0,
39 	agi_v4_init,
40 	agi_v4_deinit,
41 	agi_v4_detect_game,
42 	agi_v4_load_resource,
43 	agi_v4_unload_resource,
44 	agi_v4_load_objects,
45 	agi_v4_load_words
46 };
47 
48 
49 /* this must be kept synchronous with the AGI2PDB headers */
50 #define	PDB_OPT_AGDS		0x0001
51 #define PDB_OPT_AMIGA		0x0002
52 
53 #ifdef __WATCOMC__
54 #pragma pack(1)
55 #endif
56 
57 struct pdb_pdbheader
58 {
59 	UINT8 name[32];
60 				/*
61 				   String - This is the name of the database
62 				    on the PalmPilot device.
63 				    It need not match the name of the PDB file
64 				    in the environment in which it is created.
65 				*/
66 	UINT16 fileAttributes;
67 				/*
68 				   Attributes of the pdb file.
69 				    0x0002 Read-Only
70 				    0x0004 Dirty AppInfoArea
71 				    0x0008 Backup this database
72 				           (i.e. no conduit exists)
73 				    0x0010 Okay to install newer over existing
74 				           copy, if present on PalmPilot
75 				    0x0020 Force the PalmPilot to reset after
76 				           this database is installed
77 				*/
78 	UINT16 version;
79 				/*
80 				   Defined by the application.
81 				*/
82 	UINT32 creationDate;
83 				/*
84 				   Expressed as the number of seconds since
85 				    January 1, 1904. The database will not
86 				    install if this value is zero. (PalmOS
87 				    1.0.6)
88 				*/
89 	UINT32 modificationDate;
90 				/*
91 				   Expressed as the number of seconds since
92 				    January 1, 1904.
93 				    The database will not install if this
94 				    value is zero. (PalmOS 1.0.6)
95 				*/
96 	UINT32 lastBackupDate;
97 				/*
98 				   Expressed as the number of seconds since
99 				    January 1, 1904. This can be left at zero
100 				    and the database will install.
101 				*/
102 	UINT32 modificationNumber;
103 				/*
104 				   Set to zero.
105 				*/
106 	UINT32 appInfoArea;
107 				/*
108 				   The byte number in the PDB file (counting
109 				    from zero) at which the AppInfoArea is
110 				    located. This must be the first entry
111 				    in the Data portion of the PDB file.
112 				    If this database does not have an
113 				    AppInfoArea, set this value to zero.
114 				*/
115 	UINT32 sortInfoArea;
116 				/*
117 				   The byte number in the PDB file (counting
118 				    from zero) at which the SortInfoArea is
119 				    located. This must be placed immediately
120 				    after the AppInfoArea, if one exists,
121 				    within the Data portion of the PDB file.
122 				    If this database does not have a
123 				    SortInfoArea, set this value to zero.
124 				    Do not use this. See Note C below for
125 				    further details.
126 				*/
127 	UINT8 databaseType[4];
128 				/*
129 				   String - Set this to the desired value.
130 				    Generally it should match the Database Type
131 				    used by the corresponding application.
132 				    This is 4 characters long and does not have
133 				    a terminating null.
134 				*/
135 	UINT8 creatorID[4];
136 				/*
137 				   String - Set this to the desired value.
138 				    Generally it should match the Creator ID
139 				    used by the corresponding application. In
140 				    all cases, you should always register your
141 				    Creator ID before using it. This is 4
142 				    characters long and does not have a
143 				    terminating null.
144 				*/
145 	UINT32 uniqueIDSeed;
146 				/*
147 				   This is used to generate the Unique ID
148 				    number of subsequent records. Generally,
149 				    this should be set to zero.
150 				*/
151 	UINT32 nextRecordListID;
152 				/*
153 				   Set this to zero. (This does not appear
154 				    to be used, but that has not been
155 				    verified by a third party.)
156 				*/
157 	UINT16 numberOfRecords;
158 				/*
159 				   This contains the number of records
160 				*/
161 }
162 #ifdef __GNUC__
163 __attribute__((packed))
164 #endif
165 ;
166 
167 struct pdb_recheader{
168 	UINT32 recordDataOffset;
169 				/*
170 				   The byte number in the PDB file (counting
171 				    from zero) at which the record is located.
172 				*/
173 	UINT8 recordAttributes;
174 				/*
175 				   The records attributes.
176  				    0x10 Secret record bit.
177 				    0x20 Record in use (busy bit).
178 				    0x40 Dirty record bit.
179 				    0x80 Delete record on next HotSync.
180 				    The least significant four bits are used
181 				     to represent the category values.
182 				*/
183 	UINT8	uniqueID[3];
184 				/*
185 				   Set this to zero and do not try to
186 				    second-guess what PalmOS will do with
187 				    this value.
188 				*/
189 }
190 #ifdef __GNUC__
191 __attribute__((packed))
192 #endif
193 ;
194 
195 struct agi3vol {
196 	UINT32 sddr;
197 	UINT32 len;
198 };
199 
200 /* a agi v2.xxx game format */
201 struct PalmOSAGI2
202 {
203 	UINT32	logdir[2];
204 	UINT32	picdir[2];
205 	UINT32	viewdir[2];
206 	UINT32	snddir[2];
207 
208 	UINT32	object[2];
209 	UINT32	words[2];
210 
211 	UINT32	vol[16*2];		/* 0=offs, 1=len */
212 };
213 
214 /* an agi v3.xx.yyy game format */
215 struct PalmOSAGI3
216 {
217 	UINT32	dir[2];
218 	UINT32	object[2];
219 	UINT32	words[2];
220 	UINT32	vol[16*2];		/* 0=offs, 1=len */
221 };
222 
223 union PalmOSAGI4
224 {
225 	struct PalmOSAGI2 v2;
226 	struct PalmOSAGI3 v3;
227 };
228 
229 /* PalmOS AGI Header */
230 struct PalmOSAGI
231 {
232 	char	name[32];
233 	UINT16	version;
234 	UINT16	emulation;
235 	UINT32	options;
236 	UINT32	crc;
237 
238 	union PalmOSAGI4 v4;
239 };
240 
241 #ifdef __WATCOMC__
242 #pragma pack()
243 #endif
244 
245 struct PalmOSAGI palmagi;
246 struct pdb_pdbheader PDBHeader;
247 
248 /* our PDB file that contains everything */
249 char	pdb_file[MAX_PATH];
250 UINT32	pdb_start;
251 
agi_v4_detect_game(char * gn)252 static int agi_v4_detect_game (char *gn)
253 {
254 	FILE *fp;
255 	int ec= err_InvalidAGIFile;
256 	int offset;
257 	struct pdb_recheader rh;
258 
259 	/* gn is filename for a .pdb! */
260 
261 	memset(&PDBHeader, 0x0, sizeof(struct pdb_pdbheader));
262 	memset(&palmagi, 0x0, sizeof(struct PalmOSAGI));
263 	strcpy(pdb_file, gn);
264 
265 	fp = fopen (pdb_file, "rb");
266 	if(fp!=NULL)
267 	{
268 		fread(&PDBHeader, 1, sizeof(struct pdb_pdbheader), fp);
269 
270 		if(PDBHeader.creatorID[0]=='F' && PDBHeader.creatorID[1]=='A' &&
271 		   PDBHeader.creatorID[2]=='G' && PDBHeader.creatorID[3]=='I')
272 		{
273 			/* valid palm database with Sarien Creator ID */
274 			/* now skip record headers, read in v4 Header */
275 
276 			fread(&rh, 1, sizeof(struct pdb_recheader), fp);
277 
278 			offset=(int)pdb_read_dword((UINT8*)&rh.recordDataOffset);
279 
280 			/* our data all starts from here. add this to all offsets */
281 			pdb_start=offset;
282 
283 			fseek(fp, offset, SEEK_SET);
284 			fread(&palmagi, 1, sizeof(struct PalmOSAGI), fp);
285 
286 			palmagi.crc=pdb_read_dword((UINT8*)&palmagi.crc);
287 			palmagi.options=pdb_read_word((UINT8*)&palmagi.options);
288 			palmagi.emulation=pdb_read_word((UINT8*)&palmagi.version);
289 			palmagi.version=pdb_read_word((UINT8*)&palmagi.version);
290 
291 			/* setup our options before we call setup game! */
292 			if((palmagi.options&PDB_OPT_AGDS))
293 				opt.agds=1;
294 
295 			if((palmagi.options&PDB_OPT_AMIGA))
296 				opt.amiga=1;
297 
298 			v4id_game(palmagi.crc);
299 
300 			/* if the game is a v2 */
301 
302 			/* use agi_get_release instead of palmagi.emulation */
303 			if((agi_get_release()>>12)==0x2)
304 				agi_v4.int_version = 0x2917;		/* setup for 2.917 */
305 			else
306 				agi_v4.int_version = 0x3149;		/* setup for 3.002.149 */
307 
308 			ec=err_OK;
309 		}
310 
311 		fclose(fp);
312 	}
313 
314 	return ec;
315 }
316 
317 
agi_v4_load_dir(struct agi_dir * agid,int intDirType)318 static int agi_v4_load_dir (struct agi_dir *agid, int intDirType)
319 {
320 	int ec=err_OK;
321 
322 #ifndef PALMOS
323 	FILE *fp;
324 	struct agi3vol agi_vol3[4];
325 	UINT32	offs, flen;
326 	UINT16 xd[4];
327 	int	i;
328 
329 	if ((fp = fopen (pdb_file, "rb")) == NULL) {
330 		return err_BadFileOpen;
331 	}
332 
333 	if((palmagi.emulation>>12)==2)
334 	{
335 		/* load singledir v2 style */
336 		switch(intDirType)
337 		{
338 			case rLOGIC: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.logdir[0], palmagi.v4.v2.logdir[1], fp); break;
339 			case rPICTURE: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.picdir[0], palmagi.v4.v2.picdir[1], fp); break;
340 			case rSOUND: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.snddir[0], palmagi.v4.v2.snddir[1], fp); break;
341 			case rVIEW: ec=load_v2_dir(agid, pdb_start + palmagi.v4.v2.viewdir[0], palmagi.v4.v2.viewdir[1], fp); break;
342 		}
343 	}
344 	else
345 	{
346 		/* load v3 gamedir style */
347 		offs=pdb_start + palmagi.v4.v3.dir[0];
348 		flen=palmagi.v4.v3.dir[1];
349 
350 		fseek(fp, offs, SEEK_SET);
351 
352 		/* FIXME: Not Endian Aware */
353 		fread (&xd, 1, 8, fp);
354 
355 		for(i = 0; i < 4; i++)
356 			agi_vol3[i].sddr = offs + xd[i];
357 
358 		agi_vol3[0].len = agi_vol3[1].sddr - agi_vol3[0].sddr;
359 		agi_vol3[1].len = agi_vol3[2].sddr - agi_vol3[1].sddr;
360 		agi_vol3[2].len = agi_vol3[3].sddr - agi_vol3[2].sddr;
361 		agi_vol3[3].len = ftell(fp) - agi_vol3[3].sddr;
362 
363 		if (agi_vol3[3].len > 256 * 3)
364 			agi_vol3[3].len = 256 * 3;
365 
366 		/* read in all directory file info */
367 		ec=load_v3_dir(game.dir_logic, agi_vol3[0].sddr, agi_vol3[0].len, fp);
368 		if(ec==err_OK)
369 			ec=load_v3_dir(game.dir_pic, agi_vol3[1].sddr, agi_vol3[1].len, fp);
370 		if(ec==err_OK)
371 			ec=load_v3_dir(game.dir_view, agi_vol3[2].sddr, agi_vol3[2].len, fp);
372 		if(ec==err_OK)
373 			ec=load_v3_dir(game.dir_sound, agi_vol3[3].sddr, agi_vol3[3].len, fp);
374 	}
375 
376 	fclose(fp);
377 #endif
378 
379 	return ec;
380 }
381 
load_v2_dir(struct agi_dir * agid,int offset,UINT32 flen,FILE * fp)382 int load_v2_dir(struct agi_dir *agid, int offset, UINT32 flen, FILE *fp)
383 {
384 	UINT8 *mem;
385 	int i;
386 
387 	if ((mem = malloc (flen + 32)) == NULL) {
388 		fclose (fp);
389 		return err_NotEnoughMemory;
390 	}
391 
392 	fseek (fp, offset, SEEK_SET);
393 	fread (mem, 1, flen, fp);
394 
395 	/* set all directory resources to gone */
396 	for (i = 0; i < MAX_DIRS; i++) {
397 		agid[i].volume = 0xff;
398 		agid[i].offset = _EMPTY;
399 	}
400 
401 	/* build directory entries */
402 	for (i = 0; i < flen; i+=3) {
403 		agid[i/3].volume = hilo_getbyte (mem+i) >> 4;
404 		agid[i/3].offset = hilo_getpword (mem+i) & _EMPTY;
405 	}
406 
407 	free (mem);
408 
409 	return err_OK;
410 }
411 
load_v3_dir(struct agi_dir * agid,int offs,UINT32 len,FILE * fp)412 int load_v3_dir(struct agi_dir *agid, int offs, UINT32 len, FILE *fp)
413 {
414 	int ec = err_OK;
415 	UINT8 *mem;
416 	int i;
417 
418 	fseek (fp, offs, SEEK_SET);
419 	if ((mem = malloc (len + 32)) != NULL) {
420 		fread(mem, 1, len, fp);
421 
422 		/* set all directory resources to gone */
423 		for(i = 0; i < MAX_DIRS; i++) {
424 			agid[i].volume = 0xFF;
425 			agid[i].offset = _EMPTY;
426 		}
427 
428 		/* build directory entries */
429 		for(i = 0; i < len; i += 3) {
430 			agid[i / 3].volume = hilo_getbyte (mem + i) >> 4;
431 			agid[i / 3].offset = hilo_getpword (mem+i) & _EMPTY;
432 		}
433 
434 		free(mem);
435 	} else {
436 		ec = err_NotEnoughMemory;
437 	}
438 
439 	return ec;
440 }
441 
442 
agi_v4_init()443 static int agi_v4_init ()
444 {
445 	int ec = err_OK;
446 
447 	/* load directory files */
448 	switch((palmagi.emulation>>12))
449 	{
450 		case 2:
451 			ec = agi_v4_load_dir (game.dir_logic, rLOGIC);
452 			if (ec == err_OK)
453 				ec = agi_v4_load_dir (game.dir_pic, rPICTURE);
454 			if (ec == err_OK)
455 				ec = agi_v4_load_dir (game.dir_view, rVIEW);
456 			if (ec == err_OK)
457 				ec = agi_v4_load_dir (game.dir_sound, rSOUND);
458 			break;
459 		case 3:
460 			/* a v3 game load will load all DIR files,
461 			   so below is just dummy code */
462 			ec=agi_v4_load_dir(game.dir_logic, rLOGIC);
463 			break;
464 	}
465 
466 	return ec;
467 }
468 
469 
agi_v4_deinit()470 static int agi_v4_deinit ()
471 {
472 	int ec = err_OK;
473 	return ec;
474 }
475 
476 
477 
agi_v4_unload_resource(int restype,int resnum)478 static int agi_v4_unload_resource (int restype, int resnum)
479 {
480 	switch (restype) {
481 	case rLOGIC:
482 		unload_logic (resnum);
483 		break;
484 	case rPICTURE:
485 		unload_picture (resnum);
486 		break;
487 	case rVIEW:
488 		unload_view (resnum);
489 		break;
490 	case rSOUND:
491 		unload_sound (resnum);
492 		break;
493 	}
494 
495 	return err_OK;
496 }
497 
498 
499 /*
500  * This function does noting but load a raw resource into memory,
501  * if further decoding is required, it must be done by another
502  * routine. NULL is returned if unsucsessfull.
503  */
504 
agi_v4v2_load_vol_res(struct agi_dir * agid)505 UINT8* agi_v4v2_load_vol_res (struct agi_dir *agid)
506 {
507 #ifndef PALMOS
508 	UINT8 *data = NULL;
509 	FILE *fp;
510 	UINT32	offs;
511 	char	x[16];
512 
513 	/* fill offs with volume offset*/
514 
515 	offs = pdb_start + palmagi.v4.v2.vol[(2*agid->volume)];
516 
517 	/* loading a bad resource */
518 	if(offs==pdb_start)
519 		agid->offset=_EMPTY;
520 
521 	_D ("(agi_dir = [offset:%ld, len:%ld])", agid->offset, agid->len);
522 
523 	if (agid->offset != _EMPTY && (fp = fopen (pdb_file, "rb")) != NULL) {
524 		_D ("loading resource");
525 		fseek (fp, offs + agid->offset, SEEK_SET);
526 		fread (&x, 1, 5, fp);
527 		if (hilo_getword (x) == 0x1234) {
528 			agid->len = lohi_getword (x + 3);
529 			data = calloc (1, agid->len + 32);
530 			if (data != NULL)
531 				fread (data, 1, agid->len, fp);
532 		} else {
533 			/* FIXME: call some panic handler instead of
534 			 *        deiniting directly
535 			 */
536 			deinit_video_mode ();
537 			fprintf (stderr, "ACK! BAD RESOURCE!!!\n");
538 			exit (0);
539 		}
540 		fclose (fp);
541 	} else {
542 		/* we have a bad volume resource */
543 		/* set that resource to NA */
544 		agid->offset = _EMPTY;
545 	}
546 
547 	return data;
548 #endif
549 }
550 
agi_v4v3_load_vol_res(struct agi_dir * agid)551 UINT8* agi_v4v3_load_vol_res (struct agi_dir *agid)
552 {
553 #ifndef PALMOS
554 	UINT8 x[MAX_PATH], *data = NULL, *comp_buffer;
555 	FILE *fp;
556 	UINT32 offs;
557 
558 	_D ("(%p)", agid);
559 
560 	offs = pdb_start + palmagi.v4.v3.vol[2*agid->volume];
561 	/* loading a bad resource */
562 	if(offs==pdb_start)
563 		agid->offset=_EMPTY;
564 
565 	if (agid->offset != _EMPTY && (fp = fopen(pdb_file, "rb")) != NULL) {
566 		fseek (fp, offs + agid->offset, SEEK_SET);
567 		fread (&x, 1, 7, fp);
568 
569 		if (hilo_getword(x) != 0x1234) {
570 			/* FIXME */
571 			deinit_video_mode();
572 			printf("ACK! BAD RESOURCE!!!\n");
573 			exit(0);
574 		}
575 
576 		agid->len = lohi_getword (x + 3);	/* uncompressed size */
577 		agid->clen = lohi_getword (x + 5);	/* compressed len */
578 
579 		comp_buffer = calloc (1, agid->clen + 32);
580 		fread (comp_buffer, 1, agid->clen, fp);
581 
582 		if (x[2] & 0x80 || agid->len == agid->clen) {
583 			/* do not decompress */
584 			data = comp_buffer;
585 		} else {
586 			/* it is compressed */
587 			data = calloc (1, agid->len + 32);
588 			LZW_expand (comp_buffer, data, agid->len);
589 			free (comp_buffer);
590 			agid->flags |= RES_COMPRESSED;
591 		}
592 
593 		fclose(fp);
594 	} else {
595 		/* we have a bad volume resource */
596 		/* set that resource to NA */
597 		agid->offset = _EMPTY;
598 	}
599 
600 	return data;
601 #endif
602 }
603 
604 
605 
606 /*
607  * Loads a resource into memory, a raw resource is loaded in
608  * with above routine, then further decoded here.
609  */
agi_v4_load_resource(int restype,int resnum)610 int agi_v4_load_resource (int restype, int resnum)
611 {
612 	int ec = err_OK;
613 	UINT8 *data = NULL;
614 
615 
616 	_D (_D_WARN "(restype = %d, resnum = %d)", restype, resnum);
617 	if (resnum > MAX_DIRS)
618 		return err_BadResource;
619 
620 	switch (restype) {
621 	case rLOGIC:
622 		if (~game.dir_logic[resnum].flags & RES_LOADED) {
623 			_D (_D_WARN "loading logic resource %d", resnum);
624 			agi_v4.unload_resource (rLOGIC, resnum);
625 			/* load raw resource into data */
626 			if((palmagi.emulation>>12)==2)
627 				data = agi_v4v2_load_vol_res (&game.dir_logic[resnum]);
628 			else
629 				data = agi_v4v3_load_vol_res(&game.dir_logic[resnum]);
630 
631 			ec = (logics[resnum].data = data) ?
632 				decode_logic (resnum) : err_BadResource;
633 
634 			logics[resnum].sIP = 2;
635        	}
636 
637    		logics[resnum].cIP = logics[resnum].sIP;
638 		break;
639 	case rPICTURE:
640 		/* if picture is currently NOT loaded *OR* cacheing is off,
641 		 * unload the resource (caching == off) and reload it
642 		 */
643 
644 		_D (_D_WARN "loading picture resource %d", resnum);
645 		if (game.dir_pic[resnum].flags & RES_LOADED)
646 			break;
647 
648 		/* if loaded but not cached, unload it */
649 		/* if cached but not loaded, etc */
650 		agi_v4.unload_resource (rPICTURE, resnum);
651 
652 		if((palmagi.emulation>>12)==2)
653 		{
654 			data = agi_v4v2_load_vol_res (&game.dir_pic[resnum]);
655     		if (data != NULL) {
656     			pictures[resnum].rdata = data;
657     			game.dir_pic[resnum].flags |= RES_LOADED;
658     		} else {
659     			ec = err_BadResource;
660     		}
661 		}
662 		else
663 		{
664 			data = agi_v4v3_load_vol_res(&game.dir_pic[resnum]);
665 			if (data != NULL) {
666 				data = convert_v3_pic (data,
667 					game.dir_pic[resnum].len);
668 				pictures[resnum].rdata = data;
669 				game.dir_pic[resnum].flags |= RES_LOADED;
670 			} else {
671 				ec=err_BadResource;
672 			}
673 		}
674 
675 		break;
676 	case rSOUND:
677 		_D (_D_WARN "loading sound resource %d", resnum);
678 		if (game.dir_sound[resnum].flags & RES_LOADED)
679 			break;
680 
681 		if((palmagi.emulation>>12)==2)
682 			data = agi_v4v2_load_vol_res (&game.dir_sound[resnum]);
683 		else
684 			data = agi_v4v3_load_vol_res(&game.dir_sound[resnum]);
685 
686 		if (data != NULL) {
687 			sounds[resnum].rdata = data;
688 			game.dir_sound[resnum].flags |= RES_LOADED;
689 			decode_sound (resnum);
690 		} else {
691 			ec = err_BadResource;
692 		}
693 		break;
694 	case rVIEW:
695 		/* Load a VIEW resource into memory...
696 		 * Since VIEWS alter the view table ALL the time
697 		 * can we cache the view? or must we reload it all
698 		 * the time?
699 		 */
700 		if (game.dir_view[resnum].flags & RES_LOADED)
701 			break;
702 
703 		_D (_D_WARN "loading view resource %d", resnum);
704     		agi_v4.unload_resource (rVIEW, resnum);
705 
706     		if((palmagi.emulation>>12)==2)
707     		{
708     			if ((data = agi_v4v2_load_vol_res (&game.dir_view[resnum]))) {
709 	    			views[resnum].rdata = data;
710     				game.dir_view[resnum].flags |= RES_LOADED;
711     				ec = decode_view (resnum);
712     			} else {
713 	    			ec=err_BadResource;
714 				}
715 	    	}
716 	    	else
717 	    	{
718 	    		if ((data = agi_v4v3_load_vol_res (&game.dir_view[resnum]))) {
719     				views[resnum].rdata = data;
720     				game.dir_view[resnum].flags |= RES_LOADED;
721     				ec = decode_view (resnum);
722     			} else {
723 	    			ec=err_BadResource;
724 				}
725 	    	}
726 		break;
727 	default:
728 		ec = err_BadResource;
729 		break;
730 	}
731 
732 	return ec;
733 }
734 
735 
pdb_read_word(UINT8 * mem)736 UINT16 pdb_read_word(UINT8 *mem)
737 {
738 	UINT16	w;
739 
740 	w = (UINT16)mem[1];
741 	w += (UINT16)mem[0]<<8;
742 
743 	return w;
744 }
745 
pdb_read_dword(UINT8 * mem)746 UINT32 pdb_read_dword(UINT8 *mem)
747 {
748 	UINT32 w;
749 
750 	w = (UINT32)mem[3];
751 	w += (UINT32)mem[2]<<8;
752 	w += (UINT32)mem[1]<<16;
753 	w += (UINT32)mem[0]<<24;
754 
755 	return w;
756 }
757 
agi_v4_load_objects(char * fname)758 static int agi_v4_load_objects(char *fname)
759 {
760 	int ec=err_OK;
761 #ifndef PALMOS
762 	FILE *fp;
763 	UINT8	*mem;
764 	UINT32	len;
765 	UINT32	offs;
766 
767 	game.num_objects=0;
768 	fp=fopen(pdb_file, "rb");
769 	if(fp!=NULL)
770 	{
771 		if((palmagi.emulation>>12)==2)
772 		{
773 			offs=palmagi.v4.v2.object[0];
774 			len=palmagi.v4.v2.object[1];
775 		}
776 		else
777 		{
778 			offs=palmagi.v4.v3.object[0];
779 			len=palmagi.v4.v3.object[1];
780 		}
781 
782 		fseek(fp, pdb_start + offs, SEEK_SET);
783 		mem=(UINT8*)malloc(32+len);
784 		fread(mem, 1, len, fp);
785 		ec=decode_objects(mem, len);
786 
787 		free(mem);
788 		fclose(fp);
789 	}
790 #endif
791 	return ec;
792 }
793 
agi_v4_load_words(char * fname)794 static int agi_v4_load_words(char *fname)
795 {
796 	int ec=err_OK;
797 #ifndef PALMOS
798 	FILE *fp;
799 	UINT8	*mem;
800 	UINT32	len;
801 	UINT32	offs;
802 
803 	fp=fopen(pdb_file, "rb");
804 	if(fp!=NULL)
805 	{
806 		if((palmagi.emulation>>12)==2)
807 		{
808 			offs=palmagi.v4.v2.words[0];
809 			len=palmagi.v4.v2.words[1];
810 		}
811 		else
812 		{
813 			offs=palmagi.v4.v3.words[0];
814 			len=palmagi.v4.v3.words[1];
815 		}
816 
817 		fseek(fp, pdb_start + offs, SEEK_SET);
818 		mem=(UINT8*)malloc(32+len);
819 		fread(mem, 1, len, fp);
820 		ec=decode_words(mem, len);
821 		free(mem);
822 		fclose(fp);
823 	}
824 #endif
825 	return ec;
826 }
827 
828 #endif /* PALMOS */
829