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