1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * routines to handle compressed file automatically
5 *
6 * (c) 1996 Samuel Devulder, Tim Gunn
7 * 2002-2007 Toni Wilen
8 */
9
10 #define RECURSIVE_ARCHIVES 1
11 //#define ZFILE_DEBUG
12
13 #include "sysconfig.h"
14 #include "sysdeps.h"
15
16 #include "options.h"
17 #include "zfile.h"
18 #include "disk.h"
19 #include "gui.h"
20 #include "crc32.h"
21 #include "fsdb.h"
22 #include "fsusage.h"
23 #include "zarchive.h"
24 #include "diskutil.h"
25 #include "fdi2raw.h"
26
27 #include "archivers/zip/unzip.h"
28 #include "archivers/dms/cdata.h"
29 #include "archivers/dms/pfile.h"
30 #include "archivers/wrp/warp.h"
31 #include <zlib.h>
32 #include <stdarg.h>
33 #include "misc.h"
34
35 static struct zfile *zlist = 0;
36
37 const TCHAR *uae_archive_extensions[] = { _T("zip"), _T("rar"), _T("7z"), _T("lha"), _T("lzh"), _T("lzx"), _T("tar"), NULL };
38
39 #define MAX_CACHE_ENTRIES 10
40
41 struct zdisktrack
42 {
43 void *data;
44 int len;
45 };
46 struct zdiskimage
47 {
48 int tracks;
49 struct zdisktrack zdisktracks[2 * 84];
50 };
51 struct zcache
52 {
53 TCHAR *name;
54 struct zdiskimage *zd;
55 void *data;
56 int size;
57 struct zcache *next;
58 time_t tm;
59 };
60 static struct zcache *zcachedata;
61
cache_get(const TCHAR * name)62 static struct zcache *cache_get (const TCHAR *name)
63 {
64 struct zcache *zc = zcachedata;
65 while (zc) {
66 if (!_tcscmp (name, zc->name)) {
67 zc->tm = time (NULL);
68 return zc;
69 }
70 zc = zc->next;
71 }
72 return NULL;
73 }
74
75 /* internal prototypes */
76 struct zvolume *zvolume_alloc_nofile (const TCHAR *name, unsigned int id, void *handle, const TCHAR *volumename);
77 struct zvolume *zfile_fopen_directory (const TCHAR *dirname);
78 struct zvolume *zfile_fopen_archive_flags (const TCHAR *filename, int flags);
79 struct zdirectory *zfile_opendir_archive_flags (const TCHAR *path, int flags);
80 int zfile_readdir_archive_fullpath (struct zdirectory *zd, TCHAR *out, bool fullpath);
81 int zfile_fs_usage_archive (const TCHAR *path, const TCHAR *disk, struct fs_usage *fsp);
82
83
zcache_flush(void)84 static void zcache_flush (void)
85 {
86 }
87
zcache_free_data(struct zcache * zc)88 static void zcache_free_data (struct zcache *zc)
89 {
90 int i;
91 if (zc->zd) {
92 for (i = 0; i < zc->zd->tracks; i++) {
93 xfree (zc->zd->zdisktracks[i].data);
94 }
95 xfree (zc->zd);
96 }
97 xfree (zc->data);
98 xfree (zc->name);
99 }
100
zcache_free(struct zcache * zc)101 static void zcache_free (struct zcache *zc)
102 {
103 struct zcache *pl = NULL;
104 struct zcache *l = zcachedata;
105 struct zcache *nxt;
106
107 while (l != zc) {
108 if (l == 0)
109 return;
110 pl = l;
111 l = l->next;
112 }
113 if (l)
114 nxt = l->next;
115 zcache_free_data (zc);
116 if (l == 0)
117 return;
118 if(!pl)
119 zcachedata = nxt;
120 else
121 pl->next = nxt;
122 }
123
zcache_close(void)124 static void zcache_close (void)
125 {
126 struct zcache *zc = zcachedata;
127 while (zc) {
128 struct zcache *n = zc->next;
129 zcache_free_data (zc);
130 xfree (n);
131 zc = n;
132 }
133 }
134
zcache_check(void)135 static void zcache_check (void)
136 {
137 int cnt = 0;
138 struct zcache *zc = zcachedata, *last = NULL;
139 while (zc) {
140 last = zc;
141 zc = zc->next;
142 cnt++;
143 }
144 write_log (_T("CACHE: %d\n"), cnt);
145 if (cnt >= MAX_CACHE_ENTRIES && last)
146 zcache_free (last);
147 }
148
zcache_put(const TCHAR * name,struct zdiskimage * data)149 static struct zcache *zcache_put (const TCHAR *name, struct zdiskimage *data)
150 {
151 struct zcache *zc;
152
153 zcache_check ();
154 zc = xcalloc (struct zcache, 1);
155 zc->next = zcachedata;
156 zcachedata = zc;
157 zc->zd = data;
158 zc->name = my_strdup (name);
159 zc->tm = time (NULL);
160 return zc;
161 }
162
checkarchiveparent(struct zfile * z)163 static void checkarchiveparent (struct zfile *z)
164 {
165 // unpack completely if opened in PEEK mode
166 if (z->archiveparent)
167 archive_unpackzfile (z);
168 }
169
zfile_create(struct zfile * prev)170 static struct zfile *zfile_create (struct zfile *prev)
171 {
172 struct zfile *z;
173
174 z = xmalloc (struct zfile, 1);
175 if (!z)
176 return 0;
177 memset (z, 0, sizeof *z);
178 z->next = zlist;
179 zlist = z;
180 z->opencnt = 1;
181 if (prev) {
182 z->zfdmask = prev->zfdmask;
183 }
184 return z;
185 }
186
zfile_free(struct zfile * f)187 static void zfile_free (struct zfile *f)
188 {
189 if (!f)
190 return;
191 if (f->f)
192 fclose (f->f);
193 if (f->deleteafterclose) {
194 _wunlink (f->name);
195 write_log (_T("deleted temporary file '%s'\n"), f->name);
196 }
197 xfree (f->name);
198 xfree (f->data);
199 xfree (f->mode);
200 xfree (f->userdata);
201 xfree (f);
202 }
203
zfile_exit(void)204 void zfile_exit (void)
205 {
206 struct zfile *l;
207 while ((l = zlist)) {
208 zlist = l->next;
209 zfile_free (l);
210 }
211 }
212
zfile_fclose(struct zfile * f)213 void zfile_fclose (struct zfile *f)
214 {
215 //write_log (_T("%p\n"), f);
216 if (!f)
217 return;
218 if (f->opencnt < 0) {
219 write_log (_T("zfile: tried to free already closed filehandle!\n"));
220 return;
221 }
222 f->opencnt--;
223 if (f->opencnt > 0)
224 return;
225 f->opencnt = -100;
226 if (f->parent) {
227 f->parent->opencnt--;
228 if (f->parent->opencnt <= 0)
229 zfile_fclose (f->parent);
230 }
231 if (f->archiveparent) {
232 zfile_fclose (f->archiveparent);
233 f->archiveparent = NULL;
234 }
235 struct zfile *pl = NULL;
236 struct zfile *nxt;
237 struct zfile *l = zlist;
238 while (l != f) {
239 if (l == 0) {
240 write_log (_T("zfile: tried to free already freed or nonexisting filehandle!\n"));
241 return;
242 }
243 pl = l;
244 l = l->next;
245 }
246 if (l)
247 nxt = l->next;
248 zfile_free (f);
249 if (l == 0)
250 return;
251 if(!pl)
252 zlist = nxt;
253 else
254 pl->next = nxt;
255 }
256
removeext(TCHAR * s,TCHAR * ext)257 static void removeext (TCHAR *s, TCHAR *ext)
258 {
259 if (_tcslen (s) < _tcslen (ext))
260 return;
261 if (_tcsicmp (s + _tcslen (s) - _tcslen (ext), ext) == 0)
262 s[_tcslen (s) - _tcslen (ext)] = 0;
263 }
264
checkwrite(struct zfile * zf,int * retcode)265 static bool checkwrite (struct zfile *zf, int *retcode)
266 {
267 if (zfile_needwrite (zf)) {
268 if (retcode)
269 *retcode = -1;
270 return true;
271 }
272 return false;
273 }
274
275
276 static uae_u8 exeheader[]={ 0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00 };
277 static TCHAR *diskimages[] = { _T("adf"), _T("adz"), _T("ipf"), _T("fdi"), _T("dms"), _T("wrp"), _T("dsq"), 0 };
278
zfile_gettype(struct zfile * z)279 int zfile_gettype (struct zfile *z)
280 {
281 uae_u8 buf[8];
282 TCHAR *ext;
283
284 if (!z || !z->name)
285 return ZFILE_UNKNOWN;
286 ext = _tcsrchr (z->name, '.');
287 if (ext != NULL) {
288 int i;
289 ext++;
290 for (i = 0; diskimages[i]; i++) {
291 if (strcasecmp (ext, diskimages[i]) == 0)
292 return ZFILE_DISKIMAGE;
293 }
294 if (strcasecmp (ext, _T("roz")) == 0)
295 return ZFILE_ROM;
296 if (strcasecmp (ext, _T("uss")) == 0)
297 return ZFILE_STATEFILE;
298 if (strcasecmp (ext, _T("rom")) == 0)
299 return ZFILE_ROM;
300 if (strcasecmp (ext, _T("key")) == 0)
301 return ZFILE_KEY;
302 if (strcasecmp (ext, _T("nvr")) == 0)
303 return ZFILE_NVR;
304 if (strcasecmp (ext, _T("uae")) == 0)
305 return ZFILE_CONFIGURATION;
306 if (strcasecmp (ext, _T("cue")) == 0 || strcasecmp (ext, _T("iso")) == 0 || strcasecmp (ext, _T("ccd")) == 0 || strcasecmp (ext, _T("mds")) == 0 || strcasecmp (ext, _T("chd")) == 0)
307 return ZFILE_CDIMAGE;
308 }
309 memset (buf, 0, sizeof (buf));
310 zfile_fread (buf, 8, 1, z);
311 zfile_fseek (z, -8, SEEK_CUR);
312 if (!memcmp (buf, exeheader, sizeof (buf)))
313 return ZFILE_DISKIMAGE;
314 if (!memcmp (buf, "RDSK", 4))
315 return ZFILE_HDFRDB;
316 if (!memcmp (buf, "DOS", 3)) {
317 if (z->size < 4 * 1024 * 1024)
318 return ZFILE_DISKIMAGE;
319 else
320 return ZFILE_HDF;
321 }
322 if (ext != NULL) {
323 if (strcasecmp (ext, _T("hdf")) == 0)
324 return ZFILE_HDF;
325 if (strcasecmp (ext, _T("hdz")) == 0)
326 return ZFILE_HDF;
327 }
328 return ZFILE_UNKNOWN;
329 }
330
331 #define VHD_DYNAMIC 3
332 #define VHD_FIXED 2
333
gl(uae_u8 * p)334 STATIC_INLINE uae_u32 gl (uae_u8 *p)
335 {
336 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
337 }
338
vhd_checksum(uae_u8 * p,int offset)339 static uae_u32 vhd_checksum (uae_u8 *p, int offset)
340 {
341 int i;
342 uae_u32 sum;
343
344 sum = 0;
345 for (i = 0; i < 512; i++) {
346 if (offset >= 0 && i >= offset && i < offset + 4)
347 continue;
348 sum += p[i];
349 }
350 return ~sum;
351 }
352
353 struct zfile_vhd
354 {
355 int vhd_type;
356 uae_u64 virtsize;
357 uae_u32 vhd_bamoffset;
358 uae_u32 vhd_blocksize;
359 uae_u8 *vhd_header, *vhd_sectormap;
360 uae_u64 vhd_footerblock;
361 uae_u32 vhd_bamsize;
362 uae_u64 vhd_sectormapblock;
363 uae_u32 vhd_bitmapsize;
364 };
365
366
vhd_fread2(struct zfile * zf,void * dataptrv,uae_u64 offset,uae_u64 len)367 static uae_u64 vhd_fread2 (struct zfile *zf, void *dataptrv, uae_u64 offset, uae_u64 len)
368 {
369 uae_u32 bamoffset;
370 uae_u32 sectoroffset;
371 uae_u64 read;
372 struct zfile *zp = zf->parent;
373 struct zfile_vhd *zvhd = (struct zfile_vhd*)zf->userdata;
374 uae_u8 *dataptr = (uae_u8*)dataptrv;
375
376 //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len);
377 read = 0;
378 if (offset & 511)
379 return read;
380 if (len & 511)
381 return read;
382 while (len > 0) {
383 bamoffset = (offset / zvhd->vhd_blocksize) * 4 + zvhd->vhd_bamoffset;
384 sectoroffset = gl (zvhd->vhd_header + bamoffset);
385 if (sectoroffset == 0xffffffff) {
386 memset (dataptr, 0, 512);
387 read += 512;
388 } else {
389 int bitmapoffsetbits;
390 int bitmapoffsetbytes;
391 uae_u64 sectormapblock;
392
393 bitmapoffsetbits = (offset / 512) % (zvhd->vhd_blocksize / 512);
394 bitmapoffsetbytes = bitmapoffsetbits / 8;
395 sectormapblock = sectoroffset * 512 + (bitmapoffsetbytes & ~511);
396 if (zvhd->vhd_sectormapblock != sectormapblock) {
397 // read sector bitmap
398 //write_log (_T("BM %08x\n"), sectormapblock);
399 zfile_fseek (zp, sectormapblock, SEEK_SET);
400 if (zfile_fread (zvhd->vhd_sectormap, 1, 512, zp) != 512)
401 return read;
402 zvhd->vhd_sectormapblock = sectormapblock;
403 }
404 // block allocated in bitmap?
405 if (zvhd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) {
406 // read data block
407 int block = sectoroffset * 512 + zvhd->vhd_bitmapsize + bitmapoffsetbits * 512;
408 //write_log (_T("DB %08x\n"), block);
409 zfile_fseek (zp, block, SEEK_SET);
410 if (zfile_fread (dataptr, 1, 512, zp) != 512)
411 return read;
412 } else {
413 memset (dataptr, 0, 512);
414 }
415 read += 512;
416 }
417 len -= 512;
418 dataptr += 512;
419 offset += 512;
420 }
421 return read;
422 }
vhd_fread(void * data,uae_u64 l1,uae_u64 l2,struct zfile * zf)423 static uae_s64 vhd_fread (void *data, uae_u64 l1, uae_u64 l2, struct zfile *zf)
424 {
425 uae_u64 size = l1 * l2;
426 uae_u64 out = 0;
427 int len = 0;
428
429 if (!l1 || !l2)
430 return 0;
431 if ((zf->seek & 511) || (size & 511)) {
432 uae_u8 tmp[512];
433
434 if (zf->seek & 511) {
435 int s;
436 s = 512 - (zf->seek & 511);
437 vhd_fread2 (zf, tmp, zf->seek & ~511, 512);
438 memcpy ((uae_u8*)data + len, tmp + 512 - s, s);
439 len += s;
440 out += s;
441 zf->seek += s;
442 }
443 while (size > 0) {
444 int s = size > 512 ? 512 : size;
445 vhd_fread2 (zf, tmp, zf->seek, 512);
446 memcpy ((uae_u8*)data + len, tmp, s);
447 zf->seek += s;
448 size -= s;
449 out += s;
450 }
451 } else {
452 out = vhd_fread2 (zf, data, zf->seek, size);
453 zf->seek += out;
454 out /= l1;
455 }
456 return out;
457 }
458
vhd(struct zfile * z)459 static struct zfile *vhd (struct zfile *z)
460 {
461 uae_u8 tmp[512], tmp2[512];
462 uae_u32 v;
463 struct zfile_vhd *zvhd;
464 uae_u64 fsize;
465
466 zvhd = xcalloc (struct zfile_vhd, 1);
467 zfile_fseek (z, 0, SEEK_END);
468 fsize = zfile_ftell (z);
469 zfile_fseek (z, 0, SEEK_SET);
470 if (zfile_fread (tmp, 1, 512, z) != 512)
471 goto nonvhd;
472 v = gl (tmp + 8); // features
473 if ((v & 3) != 2)
474 goto nonvhd;
475 v = gl (tmp + 8 + 4); // version
476 if ((v >> 16) != 1)
477 goto nonvhd;
478 zvhd->vhd_type = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4);
479 if (zvhd->vhd_type != VHD_FIXED && zvhd->vhd_type != VHD_DYNAMIC)
480 goto nonvhd;
481 v = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4);
482 if (v == 0)
483 goto nonvhd;
484 if (vhd_checksum (tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4) != v)
485 goto nonvhd;
486 zfile_fseek (z, fsize - sizeof tmp2, SEEK_SET);
487 if (zfile_fread (tmp2, 1, 512, z) != 512)
488 goto end;
489 if (memcmp (tmp, tmp2, sizeof tmp))
490 goto nonvhd;
491 zvhd->vhd_footerblock = fsize - 512;
492 zvhd->virtsize = (uae_u64)(gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8)) << 32;
493 zvhd->virtsize |= gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8 + 4);
494 if (zvhd->vhd_type == VHD_DYNAMIC) {
495 uae_u32 size;
496 zvhd->vhd_bamoffset = gl (tmp + 8 + 4 + 4 + 4);
497 if (zvhd->vhd_bamoffset == 0 || zvhd->vhd_bamoffset >= fsize)
498 goto end;
499 zfile_fseek (z, zvhd->vhd_bamoffset, SEEK_SET);
500 if (zfile_fread (tmp, 1, 512, z) != 512)
501 goto end;
502 v = gl (tmp + 8 + 8 + 8 + 4 + 4 + 4);
503 if (vhd_checksum (tmp, 8 + 8 + 8 + 4 + 4 + 4) != v)
504 goto end;
505 v = gl (tmp + 8 + 8 + 8);
506 if ((v >> 16) != 1)
507 goto end;
508 zvhd->vhd_blocksize = gl (tmp + 8 + 8 + 8 + 4 + 4);
509 zvhd->vhd_bamoffset = gl (tmp + 8 + 8 + 4);
510 zvhd->vhd_bamsize = (((zvhd->virtsize + zvhd->vhd_blocksize - 1) / zvhd->vhd_blocksize) * 4 + 511) & ~511;
511 size = zvhd->vhd_bamoffset + zvhd->vhd_bamsize;
512 zvhd->vhd_header = xmalloc (uae_u8, size);
513 zfile_fseek (z, 0, SEEK_SET);
514 if (zfile_fread (zvhd->vhd_header, 1, size, z) != size)
515 goto end;
516 zvhd->vhd_sectormap = xmalloc (uae_u8, 512);
517 zvhd->vhd_sectormapblock = -1;
518 zvhd->vhd_bitmapsize = ((zvhd->vhd_blocksize / (8 * 512)) + 511) & ~511;
519 }
520 z = zfile_fopen_parent (z, NULL, 0, zvhd->virtsize);
521 z->useparent = 0;
522 z->dataseek = 1;
523 z->userdata = zvhd;
524 z->zfileread = vhd_fread;
525 write_log (_T("%s is VHD %s image, virtual size=%lldK\n"),
526 zfile_getname (z),
527 zvhd->vhd_type == 2 ? _T("fixed") : _T("dynamic"),
528 zvhd->virtsize / 1024);
529 return z;
530 nonvhd:
531 end:
532 return z;
533 }
534
zfile_gunzip(struct zfile * z,int * retcode)535 struct zfile *zfile_gunzip (struct zfile *z, int *retcode)
536 {
537 uae_u8 header[2 + 1 + 1 + 4 + 1 + 1];
538 z_stream zs;
539 int i, size, ret, first;
540 uae_u8 flags;
541 uae_s64 offset;
542 TCHAR name[MAX_DPATH];
543 uae_u8 buffer[8192];
544 struct zfile *z2;
545 uae_u8 b;
546
547 if (checkwrite (z, retcode))
548 return NULL;
549 _tcscpy (name, z->name);
550 memset (&zs, 0, sizeof (zs));
551 memset (header, 0, sizeof (header));
552 int read;
553 read = zfile_fread (header, sizeof (header), 1, z);
554 flags = header[3];
555 if (header[0] != 0x1f && header[1] != 0x8b) {
556 write_log("zfile_gunzip: %s failed. not gzipped file.\n", z->name);
557 return NULL;
558 }
559 if (flags & 2) { /* multipart not supported */
560 write_log("zfile_gunzip: %s failed. multipart not supported.\n", z->name);
561 return NULL;
562 }
563 if (flags & 32) { /* encryption not supported */
564 write_log("zfile_gunzip: %s failed. encryption not supported.\n", z->name);
565 return NULL;
566 }
567 if (flags & 4) { /* skip extra field */
568 zfile_fread (&b, 1, 1, z);
569 size = b;
570 zfile_fread (&b, 1, 1, z);
571 size |= b << 8;
572 zfile_fseek (z, size + 2, SEEK_CUR);
573 }
574 if (flags & 8) { /* get original file name */
575 uae_char aname[MAX_DPATH];
576 i = 0;
577 do {
578 zfile_fread (aname + i, 1, 1, z);
579 } while (i < MAX_DPATH - 1 && aname[i++]);
580 aname[i] = 0;
581 au_copy (name, MAX_DPATH, aname);
582 }
583 if (flags & 16) { /* skip comment */
584 i = 0;
585 do {
586 b = 0;
587 zfile_fread (&b, 1, 1, z);
588 } while (b);
589 }
590 removeext (name, _T(".gz"));
591 offset = zfile_ftell (z);
592 zfile_fseek (z, -4, SEEK_END);
593 zfile_fread (&b, 1, 1, z);
594 size = b;
595 zfile_fread (&b, 1, 1, z);
596 size |= b << 8;
597 zfile_fread (&b, 1, 1, z);
598 size |= b << 16;
599 zfile_fread (&b, 1, 1, z);
600 size |= b << 24;
601 if (size < 8 || size > 256 * 1024 * 1024) /* safety check */
602 return NULL;
603 zfile_fseek (z, offset, SEEK_SET);
604 z2 = zfile_fopen_empty (z, name, size);
605 if (!z2)
606 return NULL;
607 zs.next_out = z2->data;
608 zs.avail_out = size;
609 first = 1;
610 do {
611 zs.next_in = buffer;
612 zs.avail_in = zfile_fread (buffer, 1, sizeof (buffer), z);
613 if (first) {
614 if (inflateInit2_ (&zs, -MAX_WBITS, ZLIB_VERSION, sizeof (z_stream)) != Z_OK)
615 break;
616 first = 0;
617 }
618 ret = inflate (&zs, 0);
619 } while (ret == Z_OK);
620 inflateEnd (&zs);
621 if (ret != Z_STREAM_END || first != 0) {
622 zfile_fclose (z2);
623 return NULL;
624 }
625 zfile_fclose (z);
626 return z2;
627 }
628
truncate880k(struct zfile * z)629 static void truncate880k (struct zfile *z)
630 {
631 int i;
632 uae_u8 *b;
633
634 if (z == NULL || z->data == NULL)
635 return;
636 if (z->size < 880 * 512 * 2) {
637 int size = 880 * 512 * 2 - z->size;
638 b = xcalloc (uae_u8, size);
639 zfile_fwrite (b, size, 1, z);
640 xfree (b);
641 return;
642 }
643 for (i = 880 * 512 * 2; i < z->size; i++) {
644 if (z->data[i])
645 return;
646 }
647 z->size = 880 * 512 * 2;
648 }
649
extadf(struct zfile * z,int index,int * retcode)650 static struct zfile *extadf (struct zfile *z, int index, int *retcode)
651 {
652 int i, r;
653 struct zfile *zo;
654 uae_u16 *mfm;
655 uae_u16 *amigamfmbuffer;
656 uae_u8 writebuffer_ok[32], *outbuf;
657 int tracks, len, offs, pos;
658 uae_u8 buffer[2 + 2 + 4 + 4];
659 int outsize;
660 TCHAR newname[MAX_DPATH];
661 TCHAR *ext;
662 int cantrunc = 0;
663 int done = 0;
664
665 if (index > 1)
666 return NULL;
667
668 mfm = xcalloc (uae_u16, 32000 / 2);
669 amigamfmbuffer = xcalloc (uae_u16, 32000 / 2);
670 outbuf = xcalloc (uae_u8, 16384);
671
672 zfile_fread (buffer, 1, 8, z);
673 zfile_fread (buffer, 1, 4, z);
674 tracks = buffer[2] * 256 + buffer[3];
675 offs = 8 + 2 + 2 + tracks * (2 + 2 + 4 + 4);
676
677 _tcscpy (newname, zfile_getname (z));
678 ext = _tcsrchr (newname, '.');
679 if (ext) {
680 _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".std.adf"));
681 } else {
682 _tcscat (newname, _T(".std.adf"));
683 }
684 if (index > 0)
685 _tcscpy (newname + _tcslen (newname) - 4, _T(".ima"));
686
687 zo = zfile_fopen_empty (z, newname, 0);
688 if (!zo)
689 goto end;
690
691 if (retcode)
692 *retcode = 1;
693 pos = 12;
694 outsize = 0;
695 for (i = 0; i < tracks; i++) {
696 int type, bitlen;
697
698 zfile_fseek (z, pos, SEEK_SET);
699 zfile_fread (buffer, 2 + 2 + 4 + 4, 1, z);
700 pos = zfile_ftell (z);
701 type = buffer[2] * 256 + buffer[3];
702 len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7];
703 bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11];
704
705 zfile_fseek (z, offs, SEEK_SET);
706 if (type == 1) {
707 zfile_fread (mfm, len, 1, z);
708 memset (writebuffer_ok, 0, sizeof writebuffer_ok);
709 memset (outbuf, 0, 16384);
710 if (index == 0) {
711 r = isamigatrack (amigamfmbuffer, (uae_u8*)mfm, len, outbuf, writebuffer_ok, i, &outsize);
712 if (r < 0 && i == 0) {
713 zfile_seterror (_T("'%s' is not AmigaDOS formatted"), zo->name);
714 goto end;
715 }
716 if (i == 0)
717 done = 1;
718 } else {
719 r = ispctrack (amigamfmbuffer, (uae_u8*)mfm, len, outbuf, writebuffer_ok, i, &outsize);
720 if (r < 0 && i == 0) {
721 zfile_seterror (_T("'%s' is not PC formatted"), zo->name);
722 goto end;
723 }
724 if (i == 0)
725 done = 1;
726 }
727 } else {
728 outsize = 512 * 11;
729 if (bitlen / 8 > 18000)
730 outsize *= 2;
731 zfile_fread (outbuf, outsize, 1, z);
732 cantrunc = 1;
733 if (index == 0)
734 done = 1;
735 }
736 zfile_fwrite (outbuf, outsize, 1, zo);
737
738 offs += len;
739
740 }
741 if (done == 0)
742 goto end;
743 zfile_fclose (z);
744 xfree (mfm);
745 xfree (amigamfmbuffer);
746 if (cantrunc)
747 truncate880k (zo);
748 return zo;
749 end:
750 zfile_fclose (zo);
751 xfree (mfm);
752 xfree (amigamfmbuffer);
753 return NULL;
754 }
755
756
757 #include "fdi2raw.h"
fdi(struct zfile * z,int index,int * retcode)758 static struct zfile *fdi (struct zfile *z, int index, int *retcode)
759 {
760 int i, j, r;
761 struct zfile *zo;
762 TCHAR *orgname = zfile_getname (z);
763 TCHAR *ext = _tcsrchr (orgname, '.');
764 TCHAR newname[MAX_DPATH];
765 uae_u16 *amigamfmbuffer;
766 uae_u8 writebuffer_ok[32], *outbuf;
767 int tracks, len, outsize;
768 FDI *fdi;
769 int startpos = 0;
770 uae_u8 tmp[12];
771 struct zcache *zc;
772
773 if (checkwrite (z, retcode))
774 return NULL;
775 if (index > 2)
776 return NULL;
777
778 zc = cache_get (z->name);
779 if (!zc) {
780 uae_u16 *mfm;
781 struct zdiskimage *zd;
782 fdi = fdi2raw_header (z);
783 if (!fdi)
784 return NULL;
785 mfm = xcalloc (uae_u16, 32000 / 2);
786 zd = xcalloc (struct zdiskimage, 1);
787 tracks = fdi2raw_get_last_track (fdi);
788 zd->tracks = tracks;
789 for (i = 0; i < tracks; i++) {
790 uae_u8 *buf, *p;
791 fdi2raw_loadtrack (fdi, mfm, NULL, i, &len, NULL, NULL, 1);
792 len /= 8;
793 buf = p = xmalloc (uae_u8, len);
794 for (j = 0; j < len / 2; j++) {
795 uae_u16 v = mfm[j];
796 *p++ = v >> 8;
797 *p++ = v;
798 }
799 zd->zdisktracks[i].data = buf;
800 zd->zdisktracks[i].len = len;
801 }
802 fdi2raw_header_free (fdi);
803 zc = zcache_put (z->name, zd);
804 }
805
806 amigamfmbuffer = xcalloc (uae_u16, 32000 / 2);
807 outbuf = xcalloc (uae_u8, 16384);
808 tracks = zc->zd->tracks;
809 if (ext) {
810 _tcscpy (newname, orgname);
811 _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".adf"));
812 } else {
813 _tcscat (newname, _T(".adf"));
814 }
815 if (index == 1)
816 _tcscpy (newname + _tcslen (newname) - 4, _T(".ima"));
817 if (index == 2)
818 _tcscpy (newname + _tcslen (newname) - 4, _T(".ext.adf"));
819 zo = zfile_fopen_empty (z, newname, 0);
820 if (!zo)
821 goto end;
822 if (retcode)
823 *retcode = 1;
824 if (index > 1) {
825 zfile_fwrite ("UAE-1ADF", 8, 1, zo);
826 tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */
827 tmp[2] = 0; tmp[3] = tracks; /* number of tracks */
828 zfile_fwrite (tmp, 4, 1, zo);
829 memset (tmp, 0, sizeof tmp);
830 tmp[2] = 0; tmp[3] = 1; /* track type */
831 startpos = zfile_ftell (zo);
832 for (i = 0; i < tracks; i++)
833 zfile_fwrite (tmp, sizeof tmp, 1, zo);
834 }
835 outsize = 0;
836 for (i = 0; i < tracks; i++) {
837 uae_u8 *p = (uae_u8*)zc->zd->zdisktracks[i].data;
838 len = zc->zd->zdisktracks[i].len;
839 memset (writebuffer_ok, 0, sizeof writebuffer_ok);
840 memset (outbuf, 0, 16384);
841 if (index == 0) {
842 r = isamigatrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize);
843 if (r < 0 && i == 0) {
844 zfile_seterror (_T("'%s' is not AmigaDOS formatted"), orgname);
845 goto end;
846 }
847 zfile_fwrite (outbuf, outsize, 1, zo);
848 } else if (index == 1) {
849 r = ispctrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize);
850 if (r < 0 && i == 0) {
851 zfile_seterror (_T("'%s' is not PC formatted"), orgname);
852 goto end;
853 }
854 zfile_fwrite (outbuf, outsize, 1, zo);
855 } else {
856 int pos = zfile_ftell (zo);
857 int maxlen = len > 12798 ? len : 12798;
858 int lenb = len * 8;
859
860 if (maxlen & 1)
861 maxlen++;
862 zfile_fseek (zo, startpos + i * 12 + 4, SEEK_SET);
863 tmp[4] = 0; tmp[5] = 0; tmp[6] = maxlen >> 8; tmp[7] = maxlen;
864 tmp[8] = lenb >> 24; tmp[9] = lenb >> 16; tmp[10] = lenb >> 8; tmp[11] = lenb;
865 zfile_fwrite (tmp + 4, 2, 4, zo);
866 zfile_fseek (zo, pos, SEEK_SET);
867 zfile_fwrite (p, 1, len, zo);
868 if (maxlen > len)
869 zfile_fwrite (outbuf, 1, maxlen - len, zo);
870 }
871 }
872 zfile_fclose (z);
873 xfree (amigamfmbuffer);
874 xfree (outbuf);
875 if (index == 0)
876 truncate880k (zo);
877 return zo;
878 end:
879 zfile_fclose (zo);
880 xfree (amigamfmbuffer);
881 xfree (outbuf);
882 return NULL;
883 }
884
885 #ifdef CAPS
886 #include "caps/capsimage.h"
ipf(struct zfile * z,int index,int * retcode)887 static struct zfile *ipf (struct zfile *z, int index, int *retcode)
888 {
889 int i, j, r;
890 struct zfile *zo;
891 TCHAR *orgname = zfile_getname (z);
892 TCHAR *ext = _tcsrchr (orgname, '.');
893 TCHAR newname[MAX_DPATH];
894 uae_u16 *amigamfmbuffer;
895 uae_u8 writebuffer_ok[32];
896 int tracks, len;
897 int outsize;
898 int startpos = 0;
899 uae_u8 *outbuf;
900 uae_u8 tmp[12];
901 struct zcache *zc;
902
903 if (checkwrite (z, retcode))
904 return NULL;
905
906 if (index > 2)
907 return NULL;
908
909 zc = cache_get (z->name);
910 if (!zc) {
911 uae_u16 *mfm;
912 struct zdiskimage *zd;
913 if (!caps_loadimage (z, 0, &tracks))
914 return NULL;
915 mfm = xcalloc (uae_u16, 32000 / 2);
916 zd = xcalloc (struct zdiskimage, 1);
917 zd->tracks = tracks;
918 for (i = 0; i < tracks; i++) {
919 uae_u8 *buf, *p;
920 int mrev, gapo;
921 caps_loadtrack (mfm, NULL, 0, i, &len, &mrev, &gapo);
922 //write_log (_T("%d: %d %d %d\n"), i, mrev, gapo, len);
923 len /= 8;
924 buf = p = xmalloc (uae_u8, len);
925 for (j = 0; j < len / 2; j++) {
926 uae_u16 v = mfm[j];
927 *p++ = v >> 8;
928 *p++ = v;
929 }
930 zd->zdisktracks[i].data = buf;
931 zd->zdisktracks[i].len = len;
932 }
933 caps_unloadimage (0);
934 zc = zcache_put (z->name, zd);
935 }
936
937 outbuf = xcalloc (uae_u8, 16384);
938 amigamfmbuffer = xcalloc (uae_u16, 32000 / 2);
939 if (ext) {
940 _tcscpy (newname, orgname);
941 _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".adf"));
942 } else {
943 _tcscat (newname, _T(".adf"));
944 }
945 if (index == 1)
946 _tcscpy (newname + _tcslen (newname) - 4, _T(".ima"));
947 if (index == 2)
948 _tcscpy (newname + _tcslen (newname) - 4, _T(".ext.adf"));
949
950 zo = zfile_fopen_empty (z, newname, 0);
951 if (!zo)
952 goto end;
953
954 if (retcode)
955 *retcode = 1;
956
957 tracks = zc->zd->tracks;
958
959 if (index > 1) {
960 zfile_fwrite ("UAE-1ADF", 8, 1, zo);
961 tmp[0] = 0; tmp[1] = 0; /* flags (reserved) */
962 tmp[2] = 0; tmp[3] = tracks; /* number of tracks */
963 zfile_fwrite (tmp, 4, 1, zo);
964 memset (tmp, 0, sizeof tmp);
965 tmp[2] = 0; tmp[3] = 1; /* track type */
966 startpos = zfile_ftell (zo);
967 for (i = 0; i < tracks; i++)
968 zfile_fwrite (tmp, sizeof tmp, 1, zo);
969 }
970
971 outsize = 0;
972 for (i = 0; i < tracks; i++) {
973 uae_u8 *p = (uae_u8*)zc->zd->zdisktracks[i].data;
974 len = zc->zd->zdisktracks[i].len;
975 memset (writebuffer_ok, 0, sizeof writebuffer_ok);
976 memset (outbuf, 0, 16384);
977 if (index == 0) {
978 r = isamigatrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize);
979 if (r < 0 && i == 0) {
980 zfile_seterror (_T("'%s' is not AmigaDOS formatted"), orgname);
981 goto end;
982 }
983 zfile_fwrite (outbuf, 1, outsize, zo);
984 } else if (index == 1) {
985 r = ispctrack (amigamfmbuffer, p, len, outbuf, writebuffer_ok, i, &outsize);
986 if (r < 0 && i == 0) {
987 zfile_seterror (_T("'%s' is not PC formatted"), orgname);
988 goto end;
989 }
990 zfile_fwrite (outbuf, outsize, 1, zo);
991 } else {
992 int pos = zfile_ftell (zo);
993 int maxlen = len > 12798 ? len : 12798;
994 int lenb = len * 8;
995
996 if (maxlen & 1)
997 maxlen++;
998 zfile_fseek (zo, startpos + i * 12 + 4, SEEK_SET);
999 tmp[4] = 0; tmp[5] = 0; tmp[6] = maxlen >> 8; tmp[7] = maxlen;
1000 tmp[8] = lenb >> 24; tmp[9] = lenb >> 16; tmp[10] = lenb >> 8; tmp[11] = lenb;
1001 zfile_fwrite (tmp + 4, 2, 4, zo);
1002 zfile_fseek (zo, pos, SEEK_SET);
1003 zfile_fwrite (p, 1, len, zo);
1004 if (maxlen > len)
1005 zfile_fwrite (outbuf, 1, maxlen - len, zo);
1006 }
1007 }
1008 zfile_fclose (z);
1009 xfree (amigamfmbuffer);
1010 xfree (outbuf);
1011 if (index == 0)
1012 truncate880k (zo);
1013 return zo;
1014 end:
1015 zfile_fclose (zo);
1016 xfree (amigamfmbuffer);
1017 xfree (outbuf);
1018 return NULL;
1019 }
1020 #endif
1021
1022 #ifdef A_LZX
dsq(struct zfile * z,int lzx,int * retcode)1023 static struct zfile *dsq (struct zfile *z, int lzx, int *retcode)
1024 {
1025 struct zfile *zi = NULL;
1026 struct zvolume *zv = NULL;
1027
1028 if (checkwrite (z, retcode))
1029 return NULL;
1030 /*
1031 if (lzx) {
1032 zv = archive_directory_lzx (z);
1033 if (zv) {
1034 if (zv->root.child)
1035 zi = archive_access_lzx (zv->root.child);
1036 }
1037 } else {
1038 zi = z;
1039 }
1040 */
1041 zi = z;
1042 if (zi) {
1043 uae_u8 *buf = zfile_getdata (zi, 0, -1);
1044 if (!memcmp (buf, "PKD\x13", 4) || !memcmp (buf, "PKD\x11", 4)) {
1045 TCHAR *fn;
1046 int sectors = buf[18];
1047 int heads = buf[15];
1048 int blocks = (buf[6] << 8) | buf[7];
1049 int blocksize = (buf[10] << 8) | buf[11];
1050 struct zfile *zo;
1051 int size = blocks * blocksize;
1052 int off;
1053 int i;
1054 uae_u8 *bitmap = NULL;
1055 uae_u8 *nullsector;
1056
1057 nullsector = xcalloc (uae_u8, blocksize);
1058 sectors /= heads;
1059 if (buf[3] == 0x13) {
1060 off = 52;
1061 if (buf[off - 1] == 1) {
1062 bitmap = &buf[off];
1063 off += (blocks + 7) / 8;
1064 } else if (buf[off - 1] > 1) {
1065 write_log (_T("unknown DSQ extra header type %d\n"), buf[off - 1]);
1066 }
1067 } else {
1068 off = 32;
1069 }
1070
1071 if (size < 1760 * 512)
1072 size = 1760 * 512;
1073
1074 if (zfile_getfilename (zi) && _tcslen (zfile_getfilename (zi))) {
1075 fn = xmalloc (TCHAR, (_tcslen (zfile_getfilename (zi)) + 5));
1076 _tcscpy (fn, zfile_getfilename (zi));
1077 _tcscat (fn, _T(".adf"));
1078 } else {
1079 fn = my_strdup (_T("dsq.adf"));
1080 }
1081 zo = zfile_fopen_empty (z, fn, size);
1082 xfree (fn);
1083 int seccnt = 0;
1084 for (i = 0; i < blocks; i++) {
1085 int bmoff = i - 2;
1086 int boff = -1;
1087 uae_u32 mask = 0;
1088 if (bitmap) {
1089 boff = (bmoff / 32) * 4;
1090 mask = (bitmap[boff] << 24) | (bitmap[boff + 1] << 16) | (bitmap[boff + 2] << 8) | (bitmap[boff + 3]);
1091 }
1092 if (bmoff >= 0 && boff >= 0 && (mask & (1 << (bmoff & 31)))) {
1093 zfile_fwrite (nullsector, blocksize, 1, zo);
1094 } else {
1095 zfile_fwrite (buf + off, blocksize, 1, zo);
1096 off += blocksize;
1097 seccnt++;
1098 }
1099 if ((i % sectors) == sectors - 1) {
1100 off += seccnt * 16;
1101 seccnt = 0;
1102 }
1103 }
1104 //FIXME: zfile_fclose_archive (zv);
1105 zfile_fclose (z);
1106 xfree (buf);
1107 xfree (nullsector);
1108 return zo;
1109 }
1110 xfree (buf);
1111 }
1112 if (lzx)
1113 zfile_fclose (zi);
1114 return z;
1115 }
1116 #endif
1117
1118 #ifdef A_WRP
wrp(struct zfile * z,int * retcode)1119 static struct zfile *wrp (struct zfile *z, int *retcode)
1120 {
1121 //return unwarp (z);
1122 return z;
1123 }
1124 #endif
1125
bunzip(const char * decompress,struct zfile * z)1126 static struct zfile *bunzip (const char *decompress, struct zfile *z)
1127 {
1128 return z;
1129 }
1130
lha(struct zfile * z)1131 static struct zfile *lha (struct zfile *z)
1132 {
1133 return z;
1134 }
1135
1136 #ifdef A_DMS
dms(struct zfile * z,int index,int * retcode)1137 static struct zfile *dms (struct zfile *z, int index, int *retcode)
1138 {
1139 int ret;
1140 struct zfile *zo;
1141 TCHAR *orgname = zfile_getname (z);
1142 TCHAR *ext = _tcsrchr (orgname, '.');
1143 TCHAR newname[MAX_DPATH];
1144 static int recursive;
1145 int i;
1146 struct zfile *zextra[DMS_EXTRA_SIZE] = { 0 };
1147
1148 if (checkwrite (z, retcode))
1149 return NULL;
1150 if (recursive)
1151 return NULL;
1152 if (ext) {
1153 _tcscpy (newname, orgname);
1154 _tcscpy (newname + _tcslen (newname) - _tcslen (ext), _T(".adf"));
1155 } else {
1156 _tcscat (newname, _T(".adf"));
1157 }
1158
1159 zo = zfile_fopen_empty (z, newname, 1760 * 512);
1160 if (!zo)
1161 return NULL;
1162 ret = DMS_Process_File (z, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0, 0, zextra);
1163 if (ret == NO_PROBLEM || ret == DMS_FILE_END) {
1164 int off = zfile_ftell (zo);
1165 if (off >= 1760 * 512 / 3 && off <= 1760 * 512 * 3 / 4) { // possible split dms?
1166 if (_tcslen (orgname) > 5) {
1167 TCHAR *s = orgname + _tcslen (orgname) - 5;
1168 if (!_tcsicmp (s, _T("a.dms"))) {
1169 TCHAR *fn2 = my_strdup (orgname);
1170 struct zfile *z2;
1171 fn2[_tcslen (fn2) - 5]++;
1172 recursive++;
1173 z2 = zfile_fopen (fn2, _T("rb"), z->zfdmask);
1174 recursive--;
1175 if (z2) {
1176 ret = DMS_Process_File (z2, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0, 1, NULL);
1177 zfile_fclose (z2);
1178 }
1179 xfree (fn2);
1180 }
1181 }
1182 }
1183 zfile_fseek (zo, 0, SEEK_SET);
1184 if (index > 0) {
1185 zfile_fclose (zo);
1186 zo = NULL;
1187 for (i = 0; i < DMS_EXTRA_SIZE && zextra[i]; i++);
1188 if (index > i)
1189 goto end;
1190 zo = zextra[index - 1];
1191 zextra[index - 1] = NULL;
1192 }
1193 if (retcode)
1194 *retcode = 1;
1195 zfile_fclose (z);
1196 z = NULL;
1197
1198 } else {
1199 zfile_fclose (zo);
1200 zo = NULL;
1201 }
1202 end:
1203 for (i = 0; i < DMS_EXTRA_SIZE; i++)
1204 zfile_fclose (zextra[i]);
1205 return zo;
1206 }
1207 #endif
1208
1209 const TCHAR *uae_ignoreextensions[] =
1210 { _T(".gif"), _T(".jpg"), _T(".png"), _T(".xml"), _T(".pdf"), _T(".txt"), 0 };
1211 const TCHAR *uae_diskimageextensions[] =
1212 { _T(".adf"), _T(".adz"), _T(".ipf"), _T(".fdi"), _T(".exe"), _T(".dms"), _T(".wrp"), _T(".dsq"), 0 };
1213
zfile_is_ignore_ext(const TCHAR * name)1214 int zfile_is_ignore_ext (const TCHAR *name)
1215 {
1216 int i;
1217 const TCHAR *ext;
1218
1219 ext = _tcsrchr (name, '.');
1220 if (!ext)
1221 return 0;
1222 for (i = 0; uae_ignoreextensions[i]; i++) {
1223 if (!strcasecmp (uae_ignoreextensions[i], ext))
1224 return 1;
1225 }
1226 return 0;
1227 }
1228
zfile_is_diskimage(const TCHAR * name)1229 int zfile_is_diskimage (const TCHAR *name)
1230 {
1231 int i;
1232
1233 const TCHAR *ext = _tcsrchr (name, '.');
1234 if (!ext)
1235 return 0;
1236 i = 0;
1237 while (uae_diskimageextensions[i]) {
1238 if (!strcasecmp (ext, uae_diskimageextensions[i]))
1239 return HISTORY_FLOPPY;
1240 i++;
1241 }
1242 if (!_tcsicmp (ext, _T(".cue")))
1243 return HISTORY_CD;
1244 return -1;
1245 }
1246
1247
1248 static const TCHAR *archive_extensions[] = {
1249 _T("7z"), _T("rar"), _T("zip"), _T("lha"), _T("lzh"), _T("lzx"),
1250 _T("adf"), _T("adz"), _T("dsq"), _T("dms"), _T("ipf"), _T("fdi"), _T("wrp"), _T("ima"),
1251 _T("hdf"), _T("tar"),
1252 NULL
1253 };
1254 static const TCHAR *plugins_7z[] = { _T("7z"), _T("rar"), _T("zip"), _T("lha"), _T("lzh"), _T("lzx"), _T("adf"), _T("dsq"), _T("hdf"), _T("tar"), NULL };
1255 static const uae_char *plugins_7z_x[] = { "7z", "Rar!", "MK", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1256 static const int plugins_7z_t[] = {
1257 ArchiveFormat7Zip, ArchiveFormatRAR, ArchiveFormatZIP, ArchiveFormatLHA, ArchiveFormatLHA, ArchiveFormatLZX,
1258 ArchiveFormatADF, ArchiveFormatADF, ArchiveFormatADF, ArchiveFormatTAR
1259 };
1260 static const int plugins_7z_m[] = {
1261 ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE, ZFD_ARCHIVE,
1262 ZFD_ADF, ZFD_ADF, ZFD_ADF, ZFD_ARCHIVE
1263 };
1264
iszip(struct zfile * z)1265 int iszip (struct zfile *z)
1266 {
1267 TCHAR *name = z->name;
1268 TCHAR *ext = _tcsrchr (name, '.');
1269 uae_u8 header[32];
1270 int i;
1271 int mask = ZFD_NORMAL;
1272
1273 if (!ext)
1274 return 0;
1275 memset (header, 0, sizeof (header));
1276 zfile_fseek (z, 0, SEEK_SET);
1277 zfile_fread (header, sizeof (header), 1, z);
1278 zfile_fseek (z, 0, SEEK_SET);
1279
1280 if (mask & ZFD_ARCHIVE) {
1281 if (!strcasecmp (ext, _T(".zip")) || !strcasecmp (ext, _T(".rp9"))) {
1282 if (header[0] == 'P' && header[1] == 'K')
1283 return ArchiveFormatZIP;
1284 return 0;
1285 }
1286 }
1287 if (mask & ZFD_ARCHIVE) {
1288 if (!strcasecmp (ext, _T(".7z"))) {
1289 if (header[0] == '7' && header[1] == 'z')
1290 return ArchiveFormat7Zip;
1291 return 0;
1292 }
1293 if (!strcasecmp (ext, _T(".rar"))) {
1294 if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!')
1295 return ArchiveFormatRAR;
1296 return 0;
1297 }
1298 if (!strcasecmp (ext, _T(".lha")) || !strcasecmp (ext, _T(".lzh"))) {
1299 if (header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-')
1300 return ArchiveFormatLHA;
1301 return 0;
1302 }
1303 if (!strcasecmp (ext, _T(".lzx"))) {
1304 if (header[0] == 'L' && header[1] == 'Z' && header[2] == 'X')
1305 return ArchiveFormatLZX;
1306 return 0;
1307 }
1308 }
1309 if (mask & ZFD_ADF) {
1310 if (!strcasecmp (ext, _T(".adf"))) {
1311 // Note: With uae_u8 "header[3] >= 0" is always true, and thus removed.
1312 if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && header[3] <= 7)
1313 return ArchiveFormatADF;
1314 if (isfat (header))
1315 return ArchiveFormatFAT;
1316 return 0;
1317 }
1318 if (!strcasecmp (ext, _T(".ima"))) {
1319 if (isfat (header))
1320 return ArchiveFormatFAT;
1321 }
1322 }
1323 if (mask & ZFD_HD) {
1324 if (!strcasecmp (ext, _T(".hdf"))) {
1325 // Note: With uae_u8 "header[3] >= 0" is always true, and thus removed.
1326 if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && header[3] <= 7)
1327 return ArchiveFormatADF;
1328 if (header[0] == 'S' && header[1] == 'F' && header[2] == 'S')
1329 return ArchiveFormatADF;
1330 if (header[0] == 'R' && header[1] == 'D' && header[2] == 'S' && header[3] == 'K')
1331 return ArchiveFormatRDB;
1332 if (isfat (header))
1333 return ArchiveFormatFAT;
1334 return 0;
1335 }
1336 }
1337 #if defined(ARCHIVEACCESS)
1338 for (i = 0; plugins_7z_x[i]; i++) {
1339 if ((plugins_7z_m[i] & mask) && plugins_7z_x[i] && !strcasecmp (ext + 1, plugins_7z[i]) &&
1340 !memcmp (header, plugins_7z_x[i], strlen (plugins_7z_x[i])))
1341 return plugins_7z_t[i];
1342 }
1343 #endif
1344 return 0;
1345 }
1346
zuncompress(struct znode * parent,struct zfile * z,int dodefault,int mask,int * retcode,int index)1347 struct zfile *zuncompress (struct znode *parent, struct zfile *z, int dodefault, int mask, int *retcode, int index)
1348 {
1349 TCHAR *name = z->name;
1350 TCHAR *ext = NULL;
1351 uae_u8 header[32];
1352 int i;
1353
1354 if (retcode)
1355 *retcode = 0;
1356 if (!mask)
1357 return NULL;
1358 if (name) {
1359 ext = _tcsrchr (name, '.');
1360 if (ext)
1361 ext++;
1362 }
1363
1364 if (ext != NULL) {
1365 /* if (mask & ZFD_ARCHIVE) {
1366 if (strcasecmp (ext, _T("7z")) == 0)
1367 return archive_access_select (parent, z, ArchiveFormat7Zip, dodefault, retcode, index);
1368 if (strcasecmp (ext, _T("zip")) == 0)
1369 return archive_access_select (parent, z, ArchiveFormatZIP, dodefault, retcode, index);
1370 if (strcasecmp (ext, _T("lha")) == 0 || strcasecmp (ext, _T("lzh")) == 0)
1371 return archive_access_select (parent, z, ArchiveFormatLHA, dodefault, retcode, index);
1372 if (strcasecmp (ext, _T("lzx")) == 0)
1373 return archive_access_select (parent, z, ArchiveFormatLZX, dodefault, retcode, index);
1374 if (strcasecmp (ext, _T("rar")) == 0)
1375 return archive_access_select (parent, z, ArchiveFormatRAR, dodefault, retcode, index);
1376 if (strcasecmp (ext, _T("tar")) == 0)
1377 return archive_access_select (parent, z, ArchiveFormatTAR, dodefault, retcode, index);
1378 }*/
1379 if (mask & ZFD_UNPACK) {
1380 if (index == 0) {
1381 if (strcasecmp (ext, _T("gz")) == 0)
1382 return zfile_gunzip (z, retcode);
1383 if (strcasecmp (ext, _T("adz")) == 0)
1384 return zfile_gunzip (z, retcode);
1385 if (strcasecmp (ext, _T("roz")) == 0)
1386 return zfile_gunzip (z, retcode);
1387 if (strcasecmp (ext, _T("hdz")) == 0)
1388 return zfile_gunzip (z, retcode);
1389 #ifdef A_WRP
1390 if (strcasecmp (ext, _T("wrp")) == 0)
1391 return wrp (z, retcode);
1392 #endif
1393 #ifdef A_7Z
1394 // if (strcasecmp (ext, _T("xz")) == 0)
1395 // return xz (z, retcode);
1396 #endif
1397 }
1398 #ifdef A_DMS
1399 if (strcasecmp (ext, _T("dms")) == 0)
1400 return dms (z, index, retcode);
1401 #endif
1402 }
1403 if (mask & ZFD_RAWDISK) {
1404 #ifdef CAPS
1405 if (strcasecmp (ext, _T("ipf")) == 0)
1406 return ipf (z, index, retcode);
1407 #endif
1408 if (strcasecmp (ext, _T("fdi")) == 0)
1409 return fdi (z, index, retcode);
1410 if (mask & (ZFD_RAWDISK_PC | ZFD_RAWDISK_AMIGA))
1411 return NULL;
1412 }
1413 #if defined(ARCHIVEACCESS)
1414 if (index == 0) {
1415 for (i = 0; plugins_7z_x[i]; i++) {
1416 if ((plugins_7z_t[i] & mask) && strcasecmp (ext, plugins_7z[i]) == 0)
1417 return archive_access_arcacc_select (z, plugins_7z_t[i], retcode);
1418 }
1419 }
1420 #endif
1421 }
1422 memset (header, 0, sizeof (header));
1423 zfile_fseek (z, 0, SEEK_SET);
1424 zfile_fread (header, sizeof (header), 1, z);
1425 zfile_fseek (z, 0, SEEK_SET);
1426 if (!memcmp (header, "conectix", 8)) {
1427 if (index > 0)
1428 return NULL;
1429 return vhd (z);
1430 }
1431 if (mask & ZFD_UNPACK) {
1432 if (index == 0) {
1433 if (header[0] == 0x1f && header[1] == 0x8b)
1434 return zfile_gunzip (z, retcode);
1435 #ifdef A_LZX
1436 if (header[0] == 'P' && header[1] == 'K' && header[2] == 'D')
1437 return dsq (z, 0, retcode);
1438 #endif
1439 #ifdef A_7Z
1440 // if (header[0] == 0xfd && header[1] == 0x37 && header[2] == 0x7a && header[3] == 0x58 && header[4] == 0x5a && header[5] == 0)
1441 // return xz (z, retcode);
1442 #endif
1443 }
1444 #ifdef A_DMS
1445 if (header[0] == 'D' && header[1] == 'M' && header[2] == 'S' && header[3] == '!')
1446 return dms (z, index, retcode);
1447 #endif
1448 }
1449 if (mask & ZFD_RAWDISK) {
1450 #ifdef CAPS
1451 if (header[0] == 'C' && header[1] == 'A' && header[2] == 'P' && header[3] == 'S')
1452 return ipf (z, index, retcode);
1453 #endif
1454 if (!memcmp (header, "Formatte", 8))
1455 return fdi (z, index, retcode);
1456 if (!memcmp (header, "UAE-1ADF", 8))
1457 return extadf (z, index, retcode);
1458 }
1459 if (index > 0)
1460 return NULL;
1461 /* if (mask & ZFD_ARCHIVE) {
1462 if (header[0] == 'P' && header[1] == 'K')
1463 return archive_access_select (parent, z, ArchiveFormatZIP, dodefault, retcode, index);
1464 if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!')
1465 return archive_access_select (parent, z, ArchiveFormatRAR, dodefault, retcode, index);
1466 if (header[0] == 'L' && header[1] == 'Z' && header[2] == 'X')
1467 return archive_access_select (parent, z, ArchiveFormatLZX, dodefault, retcode, index);
1468 if (header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-')
1469 return archive_access_select (parent, z, ArchiveFormatLHA, dodefault, retcode, index);
1470 }
1471 if (mask & ZFD_ADF) {
1472 if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && (header[3] >= 0 && header[3] <= 7))
1473 return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index);
1474 if (header[0] == 'S' && header[1] == 'F' && header[2] == 'S')
1475 return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index);
1476 if (isfat (header))
1477 return archive_access_select (parent, z, ArchiveFormatFAT, dodefault, retcode, index);
1478 }*/
1479
1480 /* if (ext) {
1481 if (mask & ZFD_UNPACK) {
1482 #ifdef A_LZX
1483 if (strcasecmp (ext, _T("dsq")) == 0)
1484 return dsq (z, 1, retcode);
1485 #endif
1486 }
1487 if (mask & ZFD_ADF) {
1488 if (strcasecmp (ext, _T("adf")) == 0 && !memcmp (header, "DOS", 3))
1489 return archive_access_select (parent, z, ArchiveFormatADF, dodefault, retcode, index);
1490 }
1491 }*/
1492 return NULL;
1493 }
1494
1495
1496 #ifdef SINGLEFILE
1497 extern uae_u8 singlefile_data[];
1498
zfile_opensinglefile(struct zfile * l)1499 static struct zfile *zfile_opensinglefile(struct zfile *l)
1500 {
1501 uae_u8 *p = singlefile_data;
1502 int size, offset;
1503 TCHAR tmp[256], *s;
1504
1505 _tcscpy (tmp, l->name);
1506 s = tmp + _tcslen (tmp) - 1;
1507 while (*s != 0 && *s != '/' && *s != '\\')
1508 s--;
1509 if (s > tmp)
1510 s++;
1511 write_log (_T("loading from singlefile: '%s'\n"), tmp);
1512 while (*p++);
1513 offset = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0);
1514 p += 4;
1515 for (;;) {
1516 size = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0);
1517 if (!size)
1518 break;
1519 if (!strcmpi (tmp, p + 4)) {
1520 l->data = singlefile_data + offset;
1521 l->size = size;
1522 write_log (_T("found, size %d\n"), size);
1523 return l;
1524 }
1525 offset += size;
1526 p += 4;
1527 p += _tcslen (p) + 1;
1528 }
1529 write_log (_T("not found\n"));
1530 return 0;
1531 }
1532 #endif
1533
zfile_fopen_nozip(const TCHAR * name,const TCHAR * mode)1534 static struct zfile *zfile_fopen_nozip (const TCHAR *name, const TCHAR *mode)
1535 {
1536 struct zfile *l;
1537 FILE *f;
1538
1539 if(*name == '\0')
1540 return NULL;
1541 l = zfile_create (NULL);
1542 l->name = my_strdup (name);
1543 l->mode = my_strdup (mode);
1544 f = _tfopen (name, mode);
1545 if (!f) {
1546 zfile_fclose (l);
1547 return 0;
1548 }
1549 l->f = f;
1550 return l;
1551 }
1552
openzip(const TCHAR * pname)1553 static struct zfile *openzip (const TCHAR *pname)
1554 {
1555 int i = 0, j = 0;
1556 TCHAR v = 0;
1557 TCHAR name[MAX_DPATH];
1558 TCHAR zippath[MAX_DPATH];
1559
1560 if (!pname)
1561 return NULL;
1562
1563 memset(name, 0, sizeof(TCHAR) * MAX_DPATH);
1564 memset(zippath, 0, sizeof(TCHAR) * MAX_DPATH);
1565
1566 _tcscpy (name, pname);
1567 i = _tcslen (name) - 2;
1568 while (i > 0) {
1569 if (name[i] == '/' || (name[i] == '\\' && i > 4) ) {
1570 v = name[i];
1571 name[i] = 0;
1572 for (j = 0; plugins_7z[j]; j++) {
1573 int len = _tcslen (plugins_7z[j]);
1574 if ((i > len) // otherwise the next check is done on a negative index! - Sven
1575 && (name[i - len - 1] == '.') // and the next check on a negative address.
1576 && !strcasecmp (name + i - len, plugins_7z[j])) {
1577 struct zfile *f = zfile_fopen_nozip (name, _T("rb"));
1578 if (f) {
1579 f->zipname = my_strdup (name + i + 1);
1580 return f;
1581 }
1582 break;
1583 }
1584 }
1585 name[i] = v;
1586 }
1587 i--;
1588 }
1589 return NULL;
1590 }
1591
writeneeded(const TCHAR * mode)1592 static bool writeneeded (const TCHAR *mode)
1593 {
1594 return _tcschr (mode, 'w') || _tcschr (mode, 'a') || _tcschr (mode, '+') || _tcschr (mode, 't');
1595 }
1596
zfile_needwrite(struct zfile * zf)1597 bool zfile_needwrite (struct zfile *zf)
1598 {
1599 if (!zf->mode)
1600 return false;
1601 return writeneeded (zf->mode);
1602 }
1603
zfile_fopen_2(const TCHAR * name,const TCHAR * mode,int mask)1604 static struct zfile *zfile_fopen_2 (const TCHAR *name, const TCHAR *mode, int mask)
1605 {
1606 struct zfile *l;
1607 FILE *f;
1608
1609 if(*name == '\0')
1610 return NULL;
1611 #ifdef SINGLEFILE
1612 if (zfile_opensinglefile (l))
1613 return l;
1614 #endif
1615 l = openzip (name);
1616 if (l) {
1617 if (writeneeded (mode)) {
1618 zfile_fclose (l);
1619 return 0;
1620 }
1621 l->zfdmask = mask;
1622 } else {
1623 struct mystat st;
1624 l = zfile_create (NULL);
1625 l->mode = my_strdup (mode);
1626 l->name = my_strdup (name);
1627 l->zfdmask = mask;
1628 if (!_tcsicmp (mode, _T("r"))) {
1629 f = my_opentext (l->name);
1630 l->textmode = 1;
1631 } else {
1632 f = _tfopen (l->name, mode);
1633 }
1634 if (!f) {
1635 zfile_fclose (l);
1636 return 0;
1637 }
1638 if (my_stat (l->name, &st))
1639 l->size = st.size;
1640 l->f = f;
1641 }
1642 return l;
1643 }
1644
manglefilename(TCHAR * out,const TCHAR * in)1645 static void manglefilename(TCHAR *out, const TCHAR *in)
1646 {
1647 _tcscpy (out, in);
1648 }
1649
zfile_zopen(const TCHAR * name,zfile_callback zc,void * user)1650 int zfile_zopen (const TCHAR *name, zfile_callback zc, void *user)
1651 {
1652 struct zfile *l;
1653 int ztype;
1654 TCHAR path[MAX_DPATH];
1655
1656 manglefilename (path, name);
1657 l = zfile_fopen_2 (path, _T("rb"), ZFD_NORMAL);
1658 if (!l)
1659 return 0;
1660 ztype = iszip (l);
1661 if (ztype == 0)
1662 zc (l, user);
1663 /* else
1664 archive_access_scan (l, zc, user, ztype);*/
1665 zfile_fclose (l);
1666 return 1;
1667 }
1668
1669 /*
1670 * fopen() for a compressed file
1671 */
zfile_fopen_x(const TCHAR * name,const TCHAR * mode,int mask,int index)1672 static struct zfile *zfile_fopen_x (const TCHAR *name, const TCHAR *mode, int mask, int index)
1673 {
1674 int cnt = 10;
1675 struct zfile *l, *l2;
1676 TCHAR path[MAX_DPATH];
1677
1678 if (_tcslen (name) == 0)
1679 return NULL;
1680 manglefilename (path, name);
1681 l = zfile_fopen_2 (path, mode, mask);
1682 if (!l)
1683 return 0;
1684 l2 = NULL;
1685 while (cnt-- > 0) {
1686 int rc;
1687 zfile_fseek (l, 0, SEEK_SET);
1688 l2 = zuncompress (NULL, l, 0, mask, &rc, index);
1689 if (!l2) {
1690 if (rc < 0) {
1691 zfile_fclose (l);
1692 return NULL;
1693 }
1694 zfile_fseek (l, 0, SEEK_SET);
1695 break;
1696 } else {
1697 if (l2->parent == l)
1698 l->opencnt--;
1699 }
1700 l = l2;
1701 }
1702 return l;
1703 }
1704
zfile_fopenx2(const TCHAR * name,const TCHAR * mode,int mask,int index)1705 static struct zfile *zfile_fopenx2 (const TCHAR *name, const TCHAR *mode, int mask, int index)
1706 {
1707 struct zfile *f;
1708 TCHAR tmp[MAX_DPATH];
1709
1710 f = zfile_fopen_x (name, mode, mask, index);
1711 if (f)
1712 return f;
1713 if (_tcslen (name) <= 2)
1714 return NULL;
1715 if (name[1] != ':') {
1716 // _tcscpy (tmp, start_path_data);
1717 _tcscpy (tmp, "./");
1718 _tcscat (tmp, name);
1719 f = zfile_fopen_x (tmp, mode, mask, index);
1720 if (f)
1721 return f;
1722 }
1723 #if 0
1724 name += 2;
1725 if (name[0] == '/' || name[0] == '\\')
1726 name++;
1727 for (;;) {
1728 _tcscpy (tmp, start_path_data);
1729 _tcscpy (tmp, name);
1730 f = zfile_fopen_x (tmp, mode, mask);
1731 if (f)
1732 return f;
1733 while (name[0]) {
1734 name++;
1735 if (name[-1] == '/' || name[-1] == '\\')
1736 break;
1737 }
1738 if (name[0] == 0)
1739 break;
1740 }
1741 #endif
1742 return NULL;
1743 }
1744
zfile_fopenx(const TCHAR * name,const TCHAR * mode,int mask,int index)1745 static struct zfile *zfile_fopenx (const TCHAR *name, const TCHAR *mode, int mask, int index)
1746 {
1747 struct zfile *zf;
1748 //write_log (_T("zfile_fopen('%s','%s',%08x,%d)\n"), name, mode, mask, index);
1749 zf = zfile_fopenx2 (name, mode, mask, index);
1750 //write_log (_T("=%p\n"), zf);
1751 return zf;
1752 }
1753
zfile_fopen(const TCHAR * name,const TCHAR * mode,int mask)1754 struct zfile *zfile_fopen (const TCHAR *name, const TCHAR *mode, int mask)
1755 {
1756 return zfile_fopenx (name, mode, mask, 0);
1757 }
zfile_fopen2(const TCHAR * name,const TCHAR * mode)1758 struct zfile *zfile_fopen2 (const TCHAR *name, const TCHAR *mode)
1759 {
1760 return zfile_fopenx (name, mode, 0, 0);
1761 }
1762
zfile_fopen4(const TCHAR * name,const TCHAR * mode,int mask,int index)1763 struct zfile *zfile_fopen4 (const TCHAR *name, const TCHAR *mode, int mask, int index)
1764 {
1765 return zfile_fopenx (name, mode, mask, index);
1766 }
1767
zfile_dup(struct zfile * zf)1768 struct zfile *zfile_dup (struct zfile *zf)
1769 {
1770 struct zfile *nzf;
1771 if (!zf)
1772 return NULL;
1773 if (zf->archiveparent)
1774 checkarchiveparent (zf);
1775 if (zf->userdata)
1776 return NULL;
1777 if (!zf->data && zf->dataseek) {
1778 nzf = zfile_create (zf);
1779 } else if (zf->data) {
1780 nzf = zfile_create (zf);
1781 nzf->data = xmalloc (uae_u8, zf->size);
1782 memcpy (nzf->data, zf->data, zf->size);
1783 nzf->size = zf->size;
1784 nzf->datasize = zf->datasize;
1785 } else {
1786 if (zf->zipname) {
1787 nzf = openzip (zf->name);
1788 if (nzf)
1789 return nzf;
1790 }
1791 FILE *ff = _tfopen (zf->name, zf->mode);
1792 if (!ff)
1793 return NULL;
1794 nzf = zfile_create (zf);
1795 nzf->f = ff;
1796 }
1797 zfile_fseek (nzf, zf->seek, SEEK_SET);
1798 if (zf->name)
1799 nzf->name = my_strdup (zf->name);
1800 if (nzf->zipname)
1801 nzf->zipname = my_strdup (zf->zipname);
1802 nzf->zfdmask = zf->zfdmask;
1803 nzf->mode = my_strdup (zf->mode);
1804 nzf->size = zf->size;
1805 return nzf;
1806 }
1807
zfile_exists(const TCHAR * name)1808 int zfile_exists (const TCHAR *name)
1809 {
1810 struct zfile *z;
1811
1812 if (my_existsfile (name))
1813 return 1;
1814 z = zfile_fopen (name, _T("rb"), ZFD_NORMAL | ZFD_CHECKONLY);
1815 if (!z)
1816 return 0;
1817 zfile_fclose (z);
1818 return 1;
1819 }
1820
zfile_iscompressed(struct zfile * z)1821 int zfile_iscompressed (struct zfile *z)
1822 {
1823 return z->data ? 1 : 0;
1824 }
1825
zfile_fopen_empty(struct zfile * prev,const TCHAR * name,uae_u64 size)1826 struct zfile *zfile_fopen_empty (struct zfile *prev, const TCHAR *name, uae_u64 size)
1827 {
1828 struct zfile *l;
1829 l = zfile_create (prev);
1830 l->name = my_strdup (name ? name : _T(""));
1831 if (size) {
1832 l->data = xcalloc (uae_u8, size);
1833 if (!l->data) {
1834 xfree (l);
1835 return NULL;
1836 }
1837 l->size = size;
1838 l->datasize = size;
1839 l->allocsize = size;
1840 } else {
1841 l->data = xcalloc (uae_u8, 1000);
1842 l->size = 0;
1843 l->allocsize = 1000;
1844 }
1845 return l;
1846 }
1847
1848 /*struct zfile *zfile_fopen_empty (struct zfile *prev, const TCHAR *name)
1849 {
1850 return zfile_fopen_empty (prev, name, 0);
1851 }*/
1852
zfile_fopen_parent(struct zfile * z,const TCHAR * name,uae_u64 offset,uae_u64 size)1853 struct zfile *zfile_fopen_parent (struct zfile *z, const TCHAR *name, uae_u64 offset, uae_u64 size)
1854 {
1855 struct zfile *l;
1856
1857 if (z == NULL)
1858 return NULL;
1859 l = zfile_create (z);
1860 if (name)
1861 l->name = my_strdup (name);
1862 else if (z->name)
1863 l->name = my_strdup (z->name);
1864 l->size = size;
1865 l->datasize = size;
1866 l->offset = offset;
1867 for (;;) {
1868 l->parent = z;
1869 l->useparent = 1;
1870 if (!z->parent)
1871 break;
1872 l->offset += z->offset;
1873 z = z->parent;
1874 }
1875 z->opencnt++;
1876 return l;
1877 }
1878
zfile_fopen_load_zfile(struct zfile * f)1879 struct zfile *zfile_fopen_load_zfile (struct zfile *f)
1880 {
1881 struct zfile *l = zfile_fopen_empty (f, f->name, f->size);
1882 if (!l)
1883 return NULL;
1884 zfile_fseek (f, 0, SEEK_SET);
1885 zfile_fread (l->data, f->size, 1, f);
1886 return l;
1887 }
1888
zfile_fopen_data(const TCHAR * name,uae_u64 size,const uae_u8 * data)1889 struct zfile *zfile_fopen_data (const TCHAR *name, uae_u64 size, const uae_u8 *data)
1890 {
1891 struct zfile *l;
1892
1893 l = zfile_create (NULL);
1894 l->name = name ? my_strdup (name) : _T("");
1895 l->data = xmalloc (uae_u8, size);
1896 l->size = size;
1897 l->datasize = size;
1898 memcpy (l->data, data, size);
1899 return l;
1900 }
1901
zfile_load_data(const TCHAR * name,const uae_u8 * data,int datalen,int * outlen)1902 uae_u8 *zfile_load_data (const TCHAR *name, const uae_u8 *data,int datalen, int *outlen)
1903 {
1904 struct zfile *zf, *f;
1905 int size;
1906 uae_u8 *out;
1907
1908 zf = zfile_fopen_data (name, datalen, data);
1909 f = zfile_gunzip (zf, NULL);
1910 size = f->datasize;
1911 zfile_fseek (f, 0, SEEK_SET);
1912 out = xmalloc (uae_u8, size);
1913 zfile_fread (out, 1, size, f);
1914 zfile_fclose (f);
1915 *outlen = size;
1916 return out;
1917 }
1918
1919
zfile_truncate(struct zfile * z,uae_s64 size)1920 int zfile_truncate (struct zfile *z, uae_s64 size)
1921 {
1922 if (z->data) {
1923 if (z->size > size) {
1924 z->size = size;
1925 if (z->datasize > z->size)
1926 z->datasize = z->size;
1927 if (z->seek > z->size)
1928 z->seek = z->size;
1929 return 1;
1930 }
1931 return 0;
1932 } else {
1933 /* !!! */
1934 return 0;
1935 }
1936 }
1937
zfile_size(struct zfile * z)1938 uae_s64 zfile_size (struct zfile *z)
1939 {
1940 return z->size;
1941 }
1942
zfile_ftell(struct zfile * z)1943 uae_s64 zfile_ftell (struct zfile *z)
1944 {
1945 if (z->data || z->dataseek || z->parent)
1946 return z->seek;
1947 return ftell (z->f);
1948
1949 }
1950
zfile_fseek(struct zfile * z,uae_s64 offset,int mode)1951 uae_s64 zfile_fseek (struct zfile *z, uae_s64 offset, int mode)
1952 {
1953 if (z->zfileseek)
1954 return z->zfileseek (z, offset, mode);
1955 if (z->data || z->dataseek || (z->parent && z->useparent)) {
1956 int ret = 0;
1957 switch (mode)
1958 {
1959 case SEEK_SET:
1960 z->seek = offset;
1961 break;
1962 case SEEK_CUR:
1963 z->seek += offset;
1964 break;
1965 case SEEK_END:
1966 z->seek = z->size + offset;
1967 break;
1968 }
1969 if (z->seek < 0) {
1970 z->seek = 0;
1971 ret = 1;
1972 }
1973 if (z->seek > z->size) {
1974 z->seek = z->size;
1975 ret = 1;
1976 }
1977 return ret;
1978 } else {
1979 return fseek (z->f, offset, mode);
1980 }
1981 return 1;
1982 }
1983
zfile_fread(void * b,size_t l1,size_t l2,struct zfile * z)1984 size_t zfile_fread (void *b, size_t l1, size_t l2, struct zfile *z)
1985 {
1986 if (z->zfileread)
1987 return z->zfileread (b, l1, l2, z);
1988 if (z->data) {
1989 uae_s64 end_pos = z->seek + (uae_s64)(l1 * l2);
1990 if ( (z->datasize < z->size) && ( end_pos > z->datasize) ) {
1991 if (z->archiveparent) {
1992 archive_unpackzfile (z);
1993 return zfile_fread (b, l1, l2, z);
1994 }
1995 write_log (_T("zfile_fread(%s) attempted to read past PEEK_BYTES\n"), z->name);
1996 return 0;
1997 }
1998 if ( end_pos > z->size) {
1999 if (l1)
2000 l2 = (size_t)((z->size - z->seek) / (uae_s64)(l1));
2001 else
2002 l2 = 0;
2003 /* l2 is size_t, and size_t is (really everywhere!) unsigned
2004 if (l2 < 0)
2005 l2 = 0;
2006 */
2007 }
2008 memcpy (b, z->data + z->offset + z->seek, l1 * l2);
2009 z->seek += l1 * l2;
2010 return l2;
2011 }
2012 if (z->parent && z->useparent) {
2013 size_t ret;
2014 uae_s64 end_pos = z->seek + (uae_s64)(l1 * l2);
2015 if (end_pos > z->size) {
2016 if (l1)
2017 l2 = (size_t)( (z->size - z->seek) / (uae_s64)(l1) );
2018 else
2019 l2 = 0;
2020 /* l2 is size_t, and size_t is (really everywhere!) unsigned
2021 if (l2 < 0)
2022 l2 = 0;
2023 */
2024 }
2025 zfile_fseek (z->parent, z->seek + z->offset, SEEK_SET);
2026 ret = zfile_fread (b, l1, l2, z->parent);
2027 z->seek += l1 * ret;
2028 return ret;
2029 }
2030 return fread (b, l1, l2, z->f);
2031 }
2032
zfile_fwrite(const void * b,size_t l1,size_t l2,struct zfile * z)2033 size_t zfile_fwrite (const void *b, size_t l1, size_t l2, struct zfile *z)
2034 {
2035 if (z->archiveparent)
2036 return 0;
2037 if (z->zfilewrite)
2038 return z->zfilewrite (b, l1, l2, z);
2039 if (z->parent && z->useparent)
2040 return 0;
2041 if (z->data) {
2042 uae_s64 off = z->seek + l1 * l2;
2043 if (z->allocsize == 0) {
2044 write_log (_T("zfile_fwrite(data,%s) but allocsize=0!\n"), z->name);
2045 return 0;
2046 }
2047 if (off > z->allocsize) {
2048 if (z->allocsize < off)
2049 z->allocsize = off;
2050 z->allocsize += z->size / 2;
2051 if (z->allocsize < 10000)
2052 z->allocsize = 10000;
2053 z->data = xrealloc (uae_u8, z->data, z->allocsize);
2054 z->datasize = z->size = off;
2055 }
2056 memcpy (z->data + z->seek, b, l1 * l2);
2057 z->seek += l1 * l2;
2058 if (z->seek > z->size)
2059 z->size = z->seek;
2060 if (z->size > z->datasize)
2061 z->datasize = z->size;
2062 return l2;
2063 }
2064 return fwrite (b, l1, l2, z->f);
2065 }
2066
zfile_fputs(struct zfile * z,const TCHAR * s)2067 size_t zfile_fputs (struct zfile *z, const TCHAR *s)
2068 {
2069 char *s2 = ua (s);
2070 size_t t;
2071 t = zfile_fwrite (s2, strlen (s2), 1, z);
2072 xfree (s2);
2073 return t;
2074 }
2075
zfile_fgetsa(char * s,int size,struct zfile * z)2076 char *zfile_fgetsa (char *s, int size, struct zfile *z)
2077 {
2078 checkarchiveparent (z);
2079 if (z->data) {
2080 char *os = s;
2081 int i;
2082 for (i = 0; i < size - 1; i++) {
2083 if (z->seek == z->size) {
2084 if (i == 0)
2085 return NULL;
2086 break;
2087 }
2088 *s = z->data[z->seek++];
2089 if (*s == '\n') {
2090 s++;
2091 break;
2092 }
2093 s++;
2094 }
2095 *s = 0;
2096 return os;
2097 } else {
2098 return fgets (s, size, z->f);
2099 }
2100 }
2101
zfile_fgets(TCHAR * s,int size,struct zfile * z)2102 TCHAR *zfile_fgets (TCHAR *s, int size, struct zfile *z)
2103 {
2104 checkarchiveparent (z);
2105 if (z->data) {
2106 char s2[MAX_DPATH];
2107 char *p = s2;
2108 int i;
2109 for (i = 0; i < size - 1; i++) {
2110 if (z->seek == z->size) {
2111 if (i == 0)
2112 return NULL;
2113 break;
2114 }
2115 *p = z->data[z->seek++];
2116 if (*p == 0 && i == 0)
2117 return NULL;
2118 if (*p == '\n' || *p == 0) {
2119 p++;
2120 break;
2121 }
2122 p++;
2123 }
2124 *p = 0;
2125 if (size > (int)(strlen (s2) + 1) )
2126 size = (int)(strlen (s2) + 1);
2127 au_copy (s, size, s2);
2128 return s + size;
2129 } else {
2130 char s2[MAX_DPATH];
2131 char *s1;
2132 s1 = fgets (s2, size, z->f);
2133 if (!s1)
2134 return NULL;
2135 if (size > (int)(strlen (s2) + 1) )
2136 size = (int)(strlen (s2) + 1);
2137 au_copy (s, size, s2);
2138 return s + size;
2139 }
2140 }
2141
zfile_putc(int c,struct zfile * z)2142 int zfile_putc (int c, struct zfile *z)
2143 {
2144 uae_u8 b = (uae_u8)c;
2145 return zfile_fwrite (&b, 1, 1, z) ? 1 : -1;
2146 }
2147
zfile_getc(struct zfile * z)2148 int zfile_getc (struct zfile *z)
2149 {
2150 checkarchiveparent (z);
2151 int out = -1;
2152 if (z->data) {
2153 if (z->seek < z->size) {
2154 out = z->data[z->seek++];
2155 }
2156 } else {
2157 out = fgetc (z->f);
2158 }
2159 return out;
2160 }
2161
zfile_ferror(struct zfile * z)2162 int zfile_ferror (struct zfile *z)
2163 {
2164 return 0;
2165 }
2166
zfile_getdata(struct zfile * z,uae_s64 offset,int len)2167 uae_u8 *zfile_getdata (struct zfile *z, uae_s64 offset, int len)
2168 {
2169 uae_s64 pos = zfile_ftell (z);
2170 uae_u8 *b;
2171 if (len < 0) {
2172 zfile_fseek (z, 0, SEEK_END);
2173 len = zfile_ftell (z);
2174 zfile_fseek (z, 0, SEEK_SET);
2175 }
2176 b = xmalloc (uae_u8, len);
2177 zfile_fseek (z, offset, SEEK_SET);
2178 zfile_fread (b, len, 1, z);
2179 zfile_fseek (z, pos, SEEK_SET);
2180 return b;
2181 }
2182
zfile_zuncompress(void * dst,int dstsize,struct zfile * src,int srcsize)2183 int zfile_zuncompress (void *dst, int dstsize, struct zfile *src, int srcsize)
2184 {
2185 z_stream zs;
2186 int v;
2187 uae_u8 inbuf[4096];
2188 int incnt;
2189 size_t left = 1;
2190
2191 memset (&zs, 0, sizeof (zs));
2192 if (inflateInit_ (&zs, ZLIB_VERSION, sizeof (z_stream)) != Z_OK)
2193 return 0;
2194 zs.next_out = (Bytef*)dst;
2195 zs.avail_out = dstsize;
2196 incnt = 0;
2197 v = Z_OK;
2198 while (left && (v == Z_OK) && (zs.avail_out > 0) ) {
2199 if (zs.avail_in == 0) {
2200 left = (srcsize > incnt) ? srcsize - incnt : 0;
2201 if (left > 0) {
2202 if (left > sizeof (inbuf))
2203 left = sizeof (inbuf);
2204 zs.next_in = inbuf;
2205 zs.avail_in = zfile_fread (inbuf, 1, left, src);
2206 incnt += left;
2207 }
2208 }
2209 v = inflate (&zs, 0);
2210 }
2211 inflateEnd (&zs);
2212 return 0;
2213 }
2214
zfile_zcompress(struct zfile * f,void * src,int size)2215 int zfile_zcompress (struct zfile *f, void *src, int size)
2216 {
2217 int v;
2218 z_stream zs;
2219 uae_u8 outbuf[4096];
2220
2221 memset (&zs, 0, sizeof (zs));
2222 if (deflateInit_ (&zs, Z_DEFAULT_COMPRESSION, ZLIB_VERSION, sizeof (z_stream)) != Z_OK)
2223 return 0;
2224 zs.next_in = (Bytef*)src;
2225 zs.avail_in = size;
2226 v = Z_OK;
2227 while (v == Z_OK) {
2228 zs.next_out = outbuf;
2229 zs.avail_out = sizeof (outbuf);
2230 v = deflate (&zs, Z_NO_FLUSH | Z_FINISH);
2231 if (sizeof (outbuf) - zs.avail_out > 0)
2232 zfile_fwrite (outbuf, 1, sizeof (outbuf) - zs.avail_out, f);
2233 }
2234 deflateEnd (&zs);
2235 return zs.total_out;
2236 }
2237
zfile_getname(struct zfile * f)2238 TCHAR *zfile_getname (struct zfile *f)
2239 {
2240 return f ? f->name : NULL;
2241 }
2242
zfile_getfilename(struct zfile * f)2243 TCHAR *zfile_getfilename (struct zfile *f)
2244 {
2245 int i;
2246 if (f->name == NULL)
2247 return NULL;
2248 for (i = _tcslen (f->name) - 1; i >= 0; i--) {
2249 if (f->name[i] == '\\' || f->name[i] == '/' || f->name[i] == ':') {
2250 i++;
2251 return &f->name[i];
2252 }
2253 }
2254 return f->name;
2255 }
2256
zfile_crc32(struct zfile * f)2257 uae_u32 zfile_crc32 (struct zfile *f)
2258 {
2259 uae_u8 *p;
2260 int pos, size;
2261 uae_u32 crc;
2262
2263 if (!f)
2264 return 0;
2265 if (f->data)
2266 return get_crc32 (f->data, f->size);
2267 pos = zfile_ftell (f);
2268 zfile_fseek (f, 0, SEEK_END);
2269 size = zfile_ftell (f);
2270 p = xmalloc (uae_u8, size);
2271 if (!p)
2272 return 0;
2273 memset (p, 0, size);
2274 zfile_fseek (f, 0, SEEK_SET);
2275 zfile_fread (p, 1, size, f);
2276 zfile_fseek (f, pos, SEEK_SET);
2277 crc = get_crc32 (p, size);
2278 xfree (p);
2279 return crc;
2280 }
2281
2282 static struct zvolume *zvolume_list;
2283
recurparent(TCHAR * newpath,struct znode * zn,int recurse)2284 static void recurparent (TCHAR *newpath, struct znode *zn, int recurse)
2285 {
2286 if (zn->parent && (&zn->volume->root != zn->parent || zn->volume->parentz == NULL)) {
2287 if (&zn->volume->root == zn->parent && zn->volume->parentz == NULL && !_tcscmp (zn->name, zn->parent->name))
2288 goto end;
2289 recurparent (newpath, zn->parent, recurse);
2290 } else {
2291 struct zvolume *zv = zn->volume;
2292 if (zv->parentz && recurse)
2293 recurparent (newpath, zv->parentz, recurse);
2294 }
2295 end:
2296 if (newpath[0])
2297 _tcscat (newpath, FSDB_DIR_SEPARATOR_S);
2298 _tcscat (newpath, zn->name);
2299 }
2300
znode_alloc(struct znode * parent,const TCHAR * name)2301 static struct znode *znode_alloc (struct znode *parent, const TCHAR *name)
2302 {
2303 TCHAR fullpath[MAX_DPATH];
2304 TCHAR tmpname[MAX_DPATH];
2305 struct znode *zn = xcalloc (struct znode, 1);
2306 struct znode *zn2;
2307
2308 _tcscpy (tmpname, name);
2309 zn2 = parent->child;
2310 while (zn2) {
2311 if (!_tcscmp (zn2->name, tmpname)) {
2312 TCHAR *ext = _tcsrchr (tmpname, '.');
2313 if (ext && ext > tmpname + 2 && ext[-2] == '.') {
2314 ext[-1]++;
2315 } else if (ext) {
2316 memmove (ext + 2, ext, (_tcslen (ext) + 1) * sizeof (TCHAR));
2317 ext[0] = '.';
2318 ext[1] = '1';
2319 } else {
2320 int len = _tcslen (tmpname);
2321 tmpname[len] = '.';
2322 tmpname[len + 1] = '1';
2323 tmpname[len + 2] = 0;
2324 }
2325 zn2 = parent->child;
2326 continue;
2327 }
2328 zn2 = zn2->sibling;
2329 }
2330
2331 fullpath[0] = 0;
2332 recurparent (fullpath, parent, false);
2333 _tcscat (fullpath, FSDB_DIR_SEPARATOR_S);
2334 _tcscat (fullpath, tmpname);
2335 #ifdef ZFILE_DEBUG
2336 write_log (_T("znode_alloc vol='%s' parent='%s' name='%s'\n"), parent->volume->root.name, parent->name, name);
2337 #endif
2338 zn->fullname = my_strdup (fullpath);
2339 zn->name = my_strdup (tmpname);
2340 zn->volume = parent->volume;
2341 zn->volume->last->next = zn;
2342 zn->prev = zn->volume->last;
2343 zn->volume->last = zn;
2344 return zn;
2345 }
2346
znode_alloc_child(struct znode * parent,const TCHAR * name)2347 static struct znode *znode_alloc_child (struct znode *parent, const TCHAR *name)
2348 {
2349 struct znode *zn = znode_alloc (parent, name);
2350
2351 if (!parent->child) {
2352 parent->child = zn;
2353 } else {
2354 struct znode *pn = parent->child;
2355 while (pn->sibling)
2356 pn = pn->sibling;
2357 pn->sibling = zn;
2358 }
2359 zn->parent = parent;
2360 return zn;
2361 }
znode_alloc_sibling(struct znode * sibling,const TCHAR * name)2362 static struct znode *znode_alloc_sibling (struct znode *sibling, const TCHAR *name)
2363 {
2364 struct znode *zn = znode_alloc (sibling->parent, name);
2365
2366 if (!sibling->sibling) {
2367 sibling->sibling = zn;
2368 } else {
2369 struct znode *pn = sibling->sibling;
2370 while (pn->sibling)
2371 pn = pn->sibling;
2372 pn->sibling = zn;
2373 }
2374 zn->parent = sibling->parent;
2375 return zn;
2376 }
2377
zvolume_addtolist(struct zvolume * zv)2378 static void zvolume_addtolist (struct zvolume *zv)
2379 {
2380 if (!zv)
2381 return;
2382 if (!zvolume_list) {
2383 zvolume_list = zv;
2384 } else {
2385 struct zvolume *v = zvolume_list;
2386 while (v->next)
2387 v = v->next;
2388 v->next = zv;
2389 }
2390 }
2391
zvolume_alloc_2(const TCHAR * name,struct zfile * z,unsigned int id,void * handle,const TCHAR * volname)2392 static struct zvolume *zvolume_alloc_2 (const TCHAR *name, struct zfile *z, unsigned int id, void *handle, const TCHAR *volname)
2393 {
2394 struct zvolume *zv = xcalloc (struct zvolume, 1);
2395 struct znode *root;
2396 uae_s64 pos;
2397 int i;
2398
2399 root = &zv->root;
2400 zv->last = root;
2401 zv->archive = z;
2402 zv->handle = handle;
2403 zv->id = id;
2404 zv->blocks = 4;
2405 if (z)
2406 zv->zfdmask = z->zfdmask;
2407 root->volume = zv;
2408 root->type = ZNODE_DIR;
2409 i = 0;
2410 if (name[0] != '/' && name[0] != '\\' && _tcsncmp (name, _T(".\\"), 2) != 0) {
2411 if (_tcschr (name, ':') == 0) {
2412 for (i = _tcslen (name) - 1; i > 0; i--) {
2413 if (name[i] == FSDB_DIR_SEPARATOR) {
2414 i++;
2415 break;
2416 }
2417 }
2418 }
2419 }
2420 root->name = my_strdup (name + i);
2421 root->fullname = my_strdup (name);
2422 #ifdef ZFILE_DEBUG
2423 write_log (_T("created zvolume: '%s' (%s)\n"), root->name, root->fullname);
2424 #endif
2425 if (volname)
2426 zv->volumename = my_strdup (volname);
2427 if (z) {
2428 pos = zfile_ftell (z);
2429 zfile_fseek (z, 0, SEEK_END);
2430 zv->archivesize = zfile_ftell (z);
2431 zfile_fseek (z, pos, SEEK_SET);
2432 }
2433 return zv;
2434 }
zvolume_alloc(struct zfile * z,unsigned int id,void * handle,const TCHAR * volumename)2435 struct zvolume *zvolume_alloc (struct zfile *z, unsigned int id, void *handle, const TCHAR *volumename)
2436 {
2437 return zvolume_alloc_2 (zfile_getname (z), z, id, handle, volumename);
2438 }
2439
zvolume_alloc_nofile(const TCHAR * name,unsigned int id,void * handle,const TCHAR * volumename)2440 struct zvolume *zvolume_alloc_nofile (const TCHAR *name, unsigned int id, void *handle, const TCHAR *volumename)
2441 {
2442 return zvolume_alloc_2 (name, NULL, id, handle, volumename);
2443 }
2444
zvolume_alloc_empty(struct zvolume * prev,const TCHAR * name)2445 struct zvolume *zvolume_alloc_empty (struct zvolume *prev, const TCHAR *name)
2446 {
2447 struct zvolume *zv = zvolume_alloc_2(name, 0, 0, 0, NULL);
2448 if (!zv)
2449 return NULL;
2450 if (prev)
2451 zv->zfdmask = prev->zfdmask;
2452 return zv;
2453 }
2454
get_zvolume(const TCHAR * path)2455 static struct zvolume *get_zvolume (const TCHAR *path)
2456 {
2457 struct zvolume *zv = zvolume_list;
2458 while (zv) {
2459 TCHAR *s = zfile_getname (zv->archive);
2460 if (!s)
2461 s = zv->root.name;
2462 if (_tcslen (path) >= _tcslen (s) && !memcmp (path, s, _tcslen (s) * sizeof (TCHAR)))
2463 return zv;
2464 zv = zv->next;
2465 }
2466 return NULL;
2467 }
2468
zfile_fopen_archive_ext(struct znode * parent,struct zfile * zf,int flags)2469 static struct zvolume *zfile_fopen_archive_ext (struct znode *parent, struct zfile *zf, int flags)
2470 {
2471 struct zvolume *zv = NULL;
2472 TCHAR *name = zfile_getname (zf);
2473 TCHAR *ext;
2474 uae_u8 header[7];
2475
2476 if (!name)
2477 return NULL;
2478
2479 memset (header, 0, sizeof (header));
2480 zfile_fseek (zf, 0, SEEK_SET);
2481 zfile_fread (header, sizeof (header), 1, zf);
2482 zfile_fseek (zf, 0, SEEK_SET);
2483
2484 ext = _tcsrchr (name, '.');
2485 if (ext != NULL) {
2486 ext++;
2487 if (flags & ZFD_ARCHIVE) {
2488 #ifdef A_LHA
2489 if (strcasecmp (ext, _T("lha")) == 0 || strcasecmp (ext, _T("lzh")) == 0)
2490 zv = archive_directory_lha (zf);
2491 #endif
2492 #ifdef A_ZIP
2493 if (strcasecmp (ext, _T("zip")) == 0)
2494 zv = archive_directory_zip (zf);
2495 #endif
2496 #ifdef A_7Z
2497 if (strcasecmp (ext, _T("7z")) == 0)
2498 zv = archive_directory_7z (zf);
2499 #endif
2500 #ifdef A_LZX
2501 if (strcasecmp (ext, _T("lzx")) == 0)
2502 zv = archive_directory_lzx (zf);
2503 #endif
2504 #ifdef A_RAR
2505 if (strcasecmp (ext, _T("rar")) == 0)
2506 zv = archive_directory_rar (zf);
2507 #endif
2508 if (strcasecmp (ext, _T("tar")) == 0)
2509 zv = archive_directory_tar (zf);
2510 }
2511 if (flags & ZFD_ADF) {
2512 if (strcasecmp (ext, _T("adf")) == 0 && !memcmp (header, "DOS", 3))
2513 zv = archive_directory_adf (parent, zf);
2514 }
2515 if (flags & ZFD_HD) {
2516 if (strcasecmp (ext, _T("hdf")) == 0) {
2517 if (!memcmp (header, "RDSK", 4))
2518 zv = archive_directory_rdb (zf);
2519 else
2520 zv = archive_directory_adf (parent, zf);
2521 }
2522 }
2523 }
2524 return zv;
2525 }
2526
zfile_fopen_archive_data(struct znode * parent,struct zfile * zf,int flags)2527 static struct zvolume *zfile_fopen_archive_data (struct znode *parent, struct zfile *zf, int flags)
2528 {
2529 struct zvolume *zv = NULL;
2530 uae_u8 header[32];
2531
2532 memset (header, 0, sizeof (header));
2533 zfile_fread (header, sizeof (header), 1, zf);
2534 zfile_fseek (zf, 0, SEEK_SET);
2535 if (flags & ZFD_ARCHIVE) {
2536 #ifdef A_ZIP
2537 if (header[0] == 'P' && header[1] == 'K')
2538 zv = archive_directory_zip (zf);
2539 #endif
2540 #ifdef A_RAR
2541 if (header[0] == 'R' && header[1] == 'a' && header[2] == 'r' && header[3] == '!')
2542 zv = archive_directory_rar (zf);
2543 #endif
2544 #ifdef A_LZX
2545 if (header[0] == 'L' && header[1] == 'Z' && header[2] == 'X')
2546 zv = archive_directory_lzx (zf);
2547 #endif
2548 #ifdef A_LHA
2549 if (header[2] == '-' && header[3] == 'l' && header[4] == 'h' && header[6] == '-')
2550 zv = archive_directory_lha (zf);
2551 #endif
2552 }
2553 if (flags & ZFD_ADF) {
2554 if (header[0] == 'D' && header[1] == 'O' && header[2] == 'S' && header[3] <= 7)
2555 zv = archive_directory_adf (parent, zf);
2556 }
2557 if (flags & ZFD_HD) {
2558 if (header[0] == 'R' && header[1] == 'D' && header[2] == 'S' && header[3] == 'K')
2559 zv = archive_directory_rdb (zf);
2560 if (isfat (header))
2561 zv = archive_directory_fat (zf);
2562 }
2563 return zv;
2564 }
2565
2566 static struct znode *get_znode (struct zvolume *zv, const TCHAR *ppath, int);
2567
zfile_fopen_archive_recurse2(struct zvolume * zv,struct znode * zn,int flags)2568 static void zfile_fopen_archive_recurse2 (struct zvolume *zv, struct znode *zn, int flags)
2569 {
2570 struct zvolume *zvnew;
2571 struct znode *zndir;
2572 TCHAR tmp[MAX_DPATH];
2573
2574 _stprintf (tmp, _T("%s.DIR"), zn->fullname + _tcslen (zv->root.name) + 1);
2575 zndir = get_znode (zv, tmp, true);
2576 if (!zndir) {
2577 struct zarchive_info zai = { 0 };
2578 zvnew = zvolume_alloc_empty (zv, tmp);
2579 zvnew->parentz = zn;
2580 zai.name = tmp;
2581 zai.tv.tv_sec = zn->mtime.tv_sec;
2582 zai.tv.tv_usec = zn->mtime.tv_usec;
2583 zai.comment = zv->volumename;
2584 if (zn->flags < 0)
2585 zai.flags = zn->flags;
2586 zndir = zvolume_adddir_abs (zv, &zai);
2587 zndir->type = ZNODE_VDIR;
2588 zndir->vfile = zn;
2589 zndir->vchild = zvnew;
2590 zvnew->parent = zv;
2591 zndir->offset = zn->offset;
2592 zndir->offset2 = zn->offset2;
2593 }
2594 }
2595
zfile_fopen_archive_recurse(struct zvolume * zv,int flags)2596 static int zfile_fopen_archive_recurse (struct zvolume *zv, int flags)
2597 {
2598 struct znode *zn;
2599 int i, added;
2600
2601 added = 0;
2602 zn = zv->root.child;
2603 while (zn) {
2604 int done = 0;
2605 struct zfile *z;
2606 TCHAR *ext = _tcsrchr (zn->name, '.');
2607 if (ext && !zn->vchild && zn->type == ZNODE_FILE) {
2608 for (i = 0; !done && archive_extensions[i]; i++) {
2609 if (!strcasecmp (ext + 1, archive_extensions[i])) {
2610 zfile_fopen_archive_recurse2 (zv, zn, flags);
2611 done = 1;
2612 }
2613 }
2614 }
2615 if (!done) {
2616 z = archive_getzfile (zn, zv->method, 0);
2617 if (z && iszip (z))
2618 zfile_fopen_archive_recurse2 (zv, zn, flags);
2619 }
2620 zn = zn->next;
2621 }
2622 return 0;
2623 }
2624
prepare_recursive_volume(struct zvolume * zv,const TCHAR * path,int flags)2625 static struct zvolume *prepare_recursive_volume (struct zvolume *zv, const TCHAR *path, int flags)
2626 {
2627 struct zfile *zf = NULL;
2628 struct zvolume *zvnew = NULL;
2629 int done = 0;
2630
2631 #ifdef ZFILE_DEBUG
2632 write_log (_T("unpacking '%s'\n"), path);
2633 #endif
2634 zf = zfile_open_archive (path, 0);
2635 if (!zf)
2636 goto end;
2637 zvnew = zfile_fopen_archive_ext (zv->parentz, zf, flags);
2638 if (!zvnew && !(flags & ZFD_NORECURSE)) {
2639 #if 1
2640 zvnew = archive_directory_plain (zf);
2641 if (zvnew) {
2642 zfile_fopen_archive_recurse (zvnew, flags);
2643 done = 1;
2644 }
2645 #else
2646 int rc;
2647 int index;
2648 struct zfile *zf2, *zf3;
2649 TCHAR oldname[MAX_DPATH];
2650 _tcscpy (oldname, zf->name);
2651 index = 0;
2652 for (;;) {
2653 zf3 = zfile_dup (zf);
2654 if (!zf3)
2655 break;
2656 zf2 = zuncompress (&zv->root, zf3, 0, ZFD_ALL, &rc, index);
2657 if (zf2) {
2658 zvnew = archive_directory_plain (zf2);
2659 if (zvnew) {
2660 zvnew->parent = zv->parent;
2661 zfile_fopen_archive_recurse (zvnew);
2662 done = 1;
2663 }
2664 } else {
2665 zfile_fclose (zf3);
2666 if (rc <= 0)
2667 break;
2668 }
2669 index++;
2670 break; // TODO
2671 }
2672 #endif
2673 } else if (zvnew) {
2674 zvnew->parent = zv->parent;
2675 zfile_fopen_archive_recurse (zvnew, flags);
2676 done = 1;
2677 }
2678 if (!done)
2679 goto end;
2680 zfile_fclose_archive (zv);
2681 return zvnew;
2682 end:
2683 write_log (_T("unpack '%s' failed\n"), path);
2684 zfile_fclose_archive (zvnew);
2685 zfile_fclose (zf);
2686 return NULL;
2687 }
2688
get_znode(struct zvolume * zv,const TCHAR * ppath,int recurse)2689 static struct znode *get_znode (struct zvolume *zv, const TCHAR *ppath, int recurse)
2690 {
2691 struct znode *zn;
2692 TCHAR path[MAX_DPATH], zpath[MAX_DPATH];
2693
2694 if (!zv)
2695 return NULL;
2696 _tcscpy (path, ppath);
2697 zn = &zv->root;
2698 while (zn) {
2699 zpath[0] = 0;
2700 recurparent (zpath, zn, recurse);
2701 if (zn->type == ZNODE_FILE) {
2702 if (!_tcsicmp (zpath, path))
2703 return zn;
2704 } else {
2705 size_t len = _tcslen (zpath);
2706 if (_tcslen (path) >= len && (path[len] == 0 || path[len] == FSDB_DIR_SEPARATOR) && !_tcsnicmp (zpath, path, len)) {
2707 if (path[len] == 0)
2708 return zn;
2709 if (zn->vchild) {
2710 /* jump to separate tree, recursive archives */
2711 struct zvolume *zvdeep = zn->vchild;
2712 if (zvdeep->archive == NULL) {
2713 TCHAR newpath[MAX_DPATH];
2714 newpath[0] = 0;
2715 recurparent (newpath, zn, recurse);
2716 #ifdef ZFILE_DEBUG
2717 write_log (_T("'%s'\n"), newpath);
2718 #endif
2719 zvdeep = prepare_recursive_volume (zvdeep, newpath, ZFD_ALL);
2720 if (!zvdeep) {
2721 write_log (_T("failed to unpack '%s'\n"), newpath);
2722 return NULL;
2723 }
2724 /* replace dummy empty volume with real volume */
2725 zn->vchild = zvdeep;
2726 zvdeep->parentz = zn;
2727 }
2728 zn = zvdeep->root.child;
2729 } else {
2730 zn = zn->child;
2731 }
2732 continue;
2733 }
2734 }
2735 zn = zn->sibling;
2736 }
2737 return NULL;
2738 }
2739
addvolumesize(struct zvolume * zv,uae_s64 size)2740 static void addvolumesize (struct zvolume *zv, uae_s64 size)
2741 {
2742 unsigned int blocks = (size + 511) / 512;
2743
2744 if (blocks == 0)
2745 blocks++;
2746 while (zv) {
2747 zv->blocks += blocks;
2748 zv->size += size;
2749 zv = zv->parent;
2750 }
2751 }
2752
znode_adddir(struct znode * parent,const TCHAR * name,struct zarchive_info * zai)2753 struct znode *znode_adddir (struct znode *parent, const TCHAR *name, struct zarchive_info *zai)
2754 {
2755 struct znode *zn = NULL;
2756 TCHAR path[MAX_DPATH];
2757
2758 path[0] = 0;
2759 recurparent (path, parent, 0);
2760 _tcscat (path, FSDB_DIR_SEPARATOR_S);
2761 _tcscat (path, name);
2762 zn = get_znode (parent->volume, path, 0);
2763 if (zn)
2764 return zn;
2765 zn = znode_alloc_child (parent, name);
2766 zn->mtime.tv_sec = zai->tv.tv_sec;
2767 zn->mtime.tv_usec = zai->tv.tv_usec;
2768 zn->type = ZNODE_DIR;
2769 if (zai->comment)
2770 zn->comment = my_strdup (zai->comment);
2771 if (zai->flags < 0)
2772 zn->flags = zai->flags;
2773 addvolumesize (parent->volume, 0);
2774 return zn;
2775 }
2776
zvolume_adddir_abs(struct zvolume * zv,struct zarchive_info * zai)2777 struct znode *zvolume_adddir_abs (struct zvolume *zv, struct zarchive_info *zai)
2778 {
2779 struct znode *zn2;
2780 TCHAR *path = my_strdup (zai->name);
2781 TCHAR *p, *p2;
2782 int i;
2783
2784 if (_tcslen (path) > 0) {
2785 /* remove possible trailing / or \ */
2786 TCHAR last;
2787 last = path[_tcslen (path) - 1];
2788 if (last == '/' || last == '\\')
2789 path[_tcslen (path) - 1] = 0;
2790 }
2791 zn2 = &zv->root;
2792 p = p2 = path;
2793 for (i = 0; path[i]; i++) {
2794 if (path[i] == '/' || path[i] == '\\') {
2795 path[i] = 0;
2796 zn2 = znode_adddir (zn2, p, zai);
2797 path[i] = FSDB_DIR_SEPARATOR;
2798 p = p2 = &path[i + 1];
2799 }
2800 }
2801 return znode_adddir (zn2, p, zai);
2802 }
2803
zvolume_addfile_abs(struct zvolume * zv,struct zarchive_info * zai)2804 struct znode *zvolume_addfile_abs (struct zvolume *zv, struct zarchive_info *zai)
2805 {
2806 struct znode *zn = NULL, *zn2;
2807 int i;
2808 TCHAR *path = my_strdup (zai->name);
2809 TCHAR *p, *p2;
2810
2811 zn2 = &zv->root;
2812 p = p2 = path;
2813 for (i = 0; path[i]; i++) {
2814 if (path[i] == '/' || path[i] == '\\') {
2815 path[i] = 0;
2816 zn2 = znode_adddir (zn2, p, zai);
2817 path[i] = FSDB_DIR_SEPARATOR;
2818 p = p2 = &path[i + 1];
2819 }
2820 }
2821 if (p2) {
2822 zn = znode_alloc_child (zn2, p2);
2823 zn->size = zai->size;
2824 zn->type = ZNODE_FILE;
2825 zn->mtime.tv_sec = zai->tv.tv_sec;
2826 zn->mtime.tv_usec = zai->tv.tv_usec;
2827 if (zai->comment)
2828 zn->comment = my_strdup (zai->comment);
2829 zn->flags = zai->flags;
2830 addvolumesize (zn->volume, zai->size);
2831 }
2832 xfree (path);
2833 return zn;
2834 }
2835
zfile_fopen_directory(const TCHAR * dirname)2836 struct zvolume *zfile_fopen_directory (const TCHAR *dirname)
2837 {
2838 struct zvolume *zv = NULL;
2839 struct my_opendir_s *dir;
2840 TCHAR fname[MAX_DPATH];
2841
2842 dir = my_opendir (dirname, 0);
2843 if (!dir)
2844 return NULL;
2845 zv = zvolume_alloc_nofile (dirname, ArchiveFormatDIR, NULL, NULL);
2846 while (my_readdir (dir, fname)) {
2847 TCHAR fullname[MAX_DPATH];
2848 struct mystat statbuf;
2849 struct zarchive_info zai = { 0 };
2850 if (!_tcscmp (fname, _T(".")) || !_tcscmp (fname, _T("..")))
2851 continue;
2852 _tcscpy (fullname, dirname);
2853 _tcscat (fullname, FSDB_DIR_SEPARATOR_S);
2854 _tcscat (fullname, fname);
2855 if (!my_stat (fullname, &statbuf))
2856 continue;
2857 zai.name = fname;
2858 zai.size = statbuf.size;
2859 zai.tv.tv_sec = statbuf.mtime.tv_sec;
2860 zai.tv.tv_usec = statbuf.mtime.tv_usec;
2861 if (statbuf.mode & FILEFLAG_DIR) {
2862 zvolume_adddir_abs (zv, &zai);
2863 } else {
2864 struct znode *zn;
2865 zn = zvolume_addfile_abs (zv, &zai);
2866 //zfile_fopen_archive_recurse2 (zv, zn);
2867 }
2868 }
2869 my_closedir (dir);
2870 // zfile_fopen_archive_recurse (zv);
2871 if (zv)
2872 zvolume_addtolist (zv);
2873 return zv;
2874 }
2875
zfile_fopen_archive_flags(const TCHAR * filename,int flags)2876 struct zvolume *zfile_fopen_archive_flags (const TCHAR *filename, int flags)
2877 {
2878 struct zvolume *zv = NULL;
2879 struct zfile *zf = zfile_fopen_nozip (filename, _T("rb"));
2880
2881 if (!zf)
2882 return NULL;
2883 zf->zfdmask = flags;
2884 zv = zfile_fopen_archive_ext (NULL, zf, flags);
2885 if (!zv)
2886 zv = zfile_fopen_archive_data (NULL, zf, flags);
2887
2888 /* pointless but who cares? */
2889 if (!zv && !(flags & ZFD_NORECURSE))
2890 zv = archive_directory_plain (zf);
2891
2892 #if RECURSIVE_ARCHIVES
2893 if (zv && !(flags & ZFD_NORECURSE))
2894 zfile_fopen_archive_recurse (zv, flags);
2895 #endif
2896
2897 if (zv)
2898 zvolume_addtolist (zv);
2899 else
2900 zfile_fclose (zf);
2901
2902 return zv;
2903 }
2904
zfile_fopen_archive(const TCHAR * filename)2905 struct zvolume *zfile_fopen_archive (const TCHAR *filename)
2906 {
2907 return zfile_fopen_archive_flags (filename, ZFD_ALL);
2908 }
2909
zfile_fopen_archive_root(const TCHAR * filename,int flags)2910 struct zvolume *zfile_fopen_archive_root (const TCHAR *filename, int flags)
2911 {
2912 TCHAR path[MAX_DPATH], *p1, *p2, *lastp;
2913 struct zvolume *zv = NULL;
2914 //int last = 0;
2915 int num, i;
2916
2917 if (my_existsdir (filename))
2918 return zfile_fopen_directory (filename);
2919
2920 num = 1;
2921 lastp = NULL;
2922 for (;;) {
2923 _tcscpy (path, filename);
2924 p1 = p2 = path;
2925 for (i = 0; i < num; i++) {
2926 while (*p1 != FSDB_DIR_SEPARATOR && *p1 != 0)
2927 p1++;
2928 if (*p1 == 0 && p1 == lastp)
2929 return NULL;
2930 if (i + 1 < num)
2931 p1++;
2932 }
2933 *p1 = 0;
2934 lastp = p1;
2935 if (my_existsfile (p2))
2936 return zfile_fopen_archive_flags (p2, flags);
2937 num++;
2938 }
2939
2940 return NULL;
2941 }
2942
zfile_fclose_archive(struct zvolume * zv)2943 void zfile_fclose_archive (struct zvolume *zv)
2944 {
2945 struct znode *zn;
2946 struct zvolume *v;
2947
2948 if (!zv)
2949 return;
2950 zn = &zv->root;
2951 while (zn) {
2952 struct znode *zn2 = zn->next;
2953 if (zn->vchild)
2954 zfile_fclose_archive (zn->vchild);
2955 xfree (zn->comment);
2956 xfree (zn->fullname);
2957 xfree (zn->name);
2958 zfile_fclose (zn->f);
2959 memset (zn, 0, sizeof (struct znode));
2960 if (zn != &zv->root)
2961 xfree (zn);
2962 zn = zn2;
2963 }
2964 archive_access_close (zv->handle, zv->id);
2965 if (zvolume_list == zv) {
2966 zvolume_list = zvolume_list->next;
2967 } else {
2968 v = zvolume_list;
2969 while (v) {
2970 if (v->next == zv) {
2971 v->next = zv->next;
2972 break;
2973 }
2974 v = v->next;
2975 }
2976 }
2977 xfree (zv);
2978 }
2979
2980 struct zdirectory {
2981 TCHAR *parentpath;
2982 struct znode *first;
2983 struct znode *n;
2984 bool doclose;
2985 struct zvolume *zv;
2986 int cnt;
2987 int offset;
2988 TCHAR **filenames;
2989 };
2990
zfile_opendir_archive_flags(const TCHAR * path,int flags)2991 struct zdirectory *zfile_opendir_archive_flags (const TCHAR *path, int flags)
2992 {
2993 struct zvolume *zv = get_zvolume (path);
2994 bool created = false;
2995 if (zv == NULL) {
2996 zv = zfile_fopen_archive_flags (path, flags);
2997 created = true;
2998 }
2999 struct znode *zn = get_znode (zv, path, true);
3000 struct zdirectory *zd;
3001 if (!zn || (!zn->child && !zn->vchild)) {
3002 if (created)
3003 zfile_fclose_archive (zv);
3004 return NULL;
3005 }
3006 zd = xcalloc (struct zdirectory, 1);
3007 if (created)
3008 zd->zv = zv;
3009 if (zn->child) {
3010 zd->n = zn->child;
3011 } else {
3012 if (zn->vchild->archive == NULL) {
3013 struct zvolume *zvnew = prepare_recursive_volume (zn->vchild, path, flags);
3014 if (zvnew) {
3015 zn->vchild = zvnew;
3016 zvnew->parentz = zn;
3017 }
3018 }
3019 zd->n = zn->vchild->root.next;
3020 }
3021 zd->parentpath = my_strdup (path);
3022 zd->first = zd->n;
3023 return zd;
3024 }
zfile_opendir_archive(const TCHAR * path)3025 struct zdirectory *zfile_opendir_archive (const TCHAR *path)
3026 {
3027 return zfile_opendir_archive_flags (path, ZFD_ALL | ZFD_NORECURSE);
3028 }
3029
zfile_closedir_archive(struct zdirectory * zd)3030 void zfile_closedir_archive (struct zdirectory *zd)
3031 {
3032 if (!zd)
3033 return;
3034 zfile_fclose_archive (zd->zv);
3035 xfree (zd->parentpath);
3036 xfree (zd->filenames);
3037 xfree (zd);
3038 }
3039
zfile_readdir_archive_fullpath(struct zdirectory * zd,TCHAR * out,bool fullpath)3040 int zfile_readdir_archive_fullpath (struct zdirectory *zd, TCHAR *out, bool fullpath)
3041 {
3042 if (out)
3043 out[0] = 0;
3044 if (!zd->n || (zd->filenames != NULL && zd->offset >= zd->cnt))
3045 return 0;
3046 if (zd->filenames == NULL) {
3047 struct znode *n = zd->first;
3048 int cnt = 0, len = 0;
3049 while (n) {
3050 cnt++;
3051 n = n->sibling;
3052 }
3053 n = zd->first;
3054 uae_u8 *buf = xmalloc (uae_u8, cnt * sizeof (TCHAR*));
3055 zd->filenames = (TCHAR**)buf;
3056 buf += cnt * sizeof (TCHAR*);
3057 for (int i = 0; i < cnt; i++) {
3058 zd->filenames[i] = n->name;
3059 n = n->sibling;
3060 }
3061 for (int i = 0; i < cnt; i++) {
3062 for (int j = i + 1; j < cnt; j++) {
3063 if (_tcscmp (zd->filenames[i], zd->filenames[j]) > 0) {
3064 TCHAR *tmp = zd->filenames[i];
3065 zd->filenames[i] = zd->filenames[j];
3066 zd->filenames[j] = tmp;
3067 }
3068 }
3069 }
3070 zd->cnt = cnt;
3071 }
3072 if (out == NULL)
3073 return zd->cnt;
3074 if (fullpath) {
3075 _tcscpy (out, zd->parentpath);
3076 _tcscat (out, FSDB_DIR_SEPARATOR_S);
3077 }
3078 _tcscat (out, zd->filenames[zd->offset]);
3079 zd->offset++;
3080 return 1;
3081 }
3082
zfile_readdir_archive(struct zdirectory * zd,TCHAR * out)3083 int zfile_readdir_archive (struct zdirectory *zd, TCHAR *out)
3084 {
3085 return zfile_readdir_archive_fullpath (zd, out, false);
3086 }
3087
zfile_resetdir_archive(struct zdirectory * zd)3088 void zfile_resetdir_archive (struct zdirectory *zd)
3089 {
3090 zd->offset = 0;
3091 zd->n = zd->first;
3092 }
3093
zfile_fill_file_attrs_archive(const TCHAR * path,int * isdir,int * flags,TCHAR ** comment)3094 int zfile_fill_file_attrs_archive (const TCHAR *path, int *isdir, int *flags, TCHAR **comment)
3095 {
3096 struct zvolume *zv = get_zvolume (path);
3097 struct znode *zn = get_znode (zv, path, true);
3098
3099 *isdir = 0;
3100 *flags = 0;
3101 if (comment)
3102 *comment = 0;
3103 if (!zn)
3104 return 0;
3105 if (zn->type == ZNODE_DIR)
3106 *isdir = 1;
3107 else if (zn->type == ZNODE_VDIR)
3108 *isdir = -1;
3109 *flags = zn->flags;
3110 if (zn->comment && comment)
3111 *comment = my_strdup (zn->comment);
3112 return 1;
3113 }
3114
zfile_fs_usage_archive(const TCHAR * path,const TCHAR * disk,struct fs_usage * fsp)3115 int zfile_fs_usage_archive (const TCHAR *path, const TCHAR *disk, struct fs_usage *fsp)
3116 {
3117 struct zvolume *zv = get_zvolume (path);
3118
3119 if (!zv)
3120 return -1;
3121 fsp->fsu_blocks = zv->blocks;
3122 fsp->fsu_bavail = 0;
3123 return 0;
3124 }
3125
zfile_stat_archive(const TCHAR * path,struct mystat * s)3126 int zfile_stat_archive (const TCHAR *path, struct mystat *s)
3127 {
3128 struct zvolume *zv = get_zvolume (path);
3129 struct znode *zn = get_znode (zv, path, true);
3130
3131 memset (s, 0, sizeof (struct mystat));
3132 if (!zn)
3133 return 0;
3134 s->size = zn->size;
3135 s->mtime.tv_sec = zn->mtime.tv_sec;
3136 s->mtime.tv_usec = zn->mtime.tv_usec;
3137 return 1;
3138 }
3139
zfile_lseek_archive(struct zfile * d,uae_s64 offset,int whence)3140 uae_s64 zfile_lseek_archive (struct zfile *d, uae_s64 offset, int whence)
3141 {
3142 uae_s64 old = zfile_ftell (d);
3143 if (old < 0 || zfile_fseek (d, offset, whence))
3144 return -1;
3145 return old;
3146 }
zfile_fsize_archive(struct zfile * d)3147 uae_s64 zfile_fsize_archive (struct zfile *d)
3148 {
3149 return zfile_size (d);
3150 }
3151
zfile_read_archive(struct zfile * d,void * b,unsigned int size)3152 unsigned int zfile_read_archive (struct zfile *d, void *b, unsigned int size)
3153 {
3154 return zfile_fread (b, 1, size, d);
3155 }
3156
zfile_close_archive(struct zfile * d)3157 void zfile_close_archive (struct zfile *d)
3158 {
3159 /* do nothing, keep file cached */
3160 }
3161
zfile_open_archive(const TCHAR * path,int flags)3162 struct zfile *zfile_open_archive (const TCHAR *path, int flags)
3163 {
3164 struct zvolume *zv = get_zvolume (path);
3165 struct znode *zn = get_znode (zv, path, true);
3166 struct zfile *z;
3167
3168 if (!zn)
3169 return 0;
3170 if (zn->f) {
3171 zfile_fseek (zn->f, 0, SEEK_SET);
3172 return zn->f;
3173 }
3174 if (zn->vfile)
3175 zn = zn->vfile;
3176 z = archive_getzfile (zn, zn->volume->id, 0);
3177 if (z)
3178 zfile_fseek (z, 0, SEEK_SET);
3179 zn->f = z;
3180 return zn->f;
3181 }
3182
zfile_exists_archive(const TCHAR * path,const TCHAR * rel)3183 int zfile_exists_archive (const TCHAR *path, const TCHAR *rel)
3184 {
3185 TCHAR tmp[MAX_DPATH];
3186 struct zvolume *zv;
3187 struct znode *zn;
3188
3189 _stprintf (tmp, _T("%s%c%s"), path, FSDB_DIR_SEPARATOR, rel);
3190 zv = get_zvolume (tmp);
3191 zn = get_znode (zv, tmp, true);
3192 return zn ? 1 : 0;
3193 }
3194
zfile_convertimage(const TCHAR * src,const TCHAR * dst)3195 int zfile_convertimage (const TCHAR *src, const TCHAR *dst)
3196 {
3197 struct zfile *s, *d;
3198 int ret = 0;
3199
3200 s = zfile_fopen (src, _T("rb"), ZFD_NORMAL);
3201 if (s) {
3202 uae_u8 *b;
3203 int size;
3204 zfile_fseek (s, 0, SEEK_END);
3205 size = zfile_ftell (s);
3206 zfile_fseek (s, 0, SEEK_SET);
3207 b = xcalloc (uae_u8, size);
3208 if (b) {
3209 if (zfile_fread (b, size, 1, s) == 1) {
3210 d = zfile_fopen (dst, _T("wb"), 0);
3211 if (d) {
3212 if (zfile_fwrite (b, size, 1, d) == 1)
3213 ret = 1;
3214 zfile_fclose (d);
3215 }
3216 }
3217 xfree (b);
3218 }
3219 zfile_fclose (s);
3220 }
3221 return ret;
3222 }
3223
3224 #ifdef _CONSOLE
3225 static TCHAR *zerror;
3226 #define WRITE_LOG_BUF_SIZE 4096
zfile_seterror(const TCHAR * format,...)3227 void zfile_seterror (const TCHAR *format, ...)
3228 {
3229 int count;
3230 if (!zerror) {
3231 TCHAR buffer[WRITE_LOG_BUF_SIZE];
3232 va_list parms;
3233 va_start (parms, format);
3234 count = vsnprintf (buffer, WRITE_LOG_BUF_SIZE - 1, format, parms);
3235 zerror = my_strdup (buffer);
3236 va_end (parms);
3237 }
3238 }
zfile_geterror(void)3239 TCHAR *zfile_geterror (void)
3240 {
3241 return zerror;
3242 }
3243 #else
zfile_seterror(const TCHAR * format,...)3244 void zfile_seterror (const TCHAR *format, ...)
3245 {
3246 }
3247 #endif
3248
3249