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