1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * transparent archive handling
5 *
6 *     2007 Toni Wilen
7 */
8 
9 #include "sysconfig.h"
10 #include "sysdeps.h"
11 
12 #ifdef FSUAE
13 #else
14 #ifdef _WIN32
15 #include <windows.h>
16 #include "win32.h"
17 #endif
18 #endif
19 
20 #include "options.h"
21 #include "zfile.h"
22 #include "archivers/zip/unzip.h"
23 #include "archivers/dms/pfile.h"
24 #include "crc32.h"
25 #include "zarchive.h"
26 #include "disk.h"
27 
28 #ifdef FSUAE // NL
29 #undef _WIN32
30 #endif
31 
32 #include <zlib.h>
33 
34 #define unpack_log write_log
35 #undef unpack_log
36 #define unpack_log(fmt, ...)
37 
38 
fromdostime(uae_u32 dd)39 static time_t fromdostime (uae_u32 dd)
40 {
41 	struct tm tm;
42 	time_t t;
43 
44 	memset (&tm, 0, sizeof tm);
45 	tm.tm_hour = (dd >> 11) & 0x1f;
46 	tm.tm_min  = (dd >> 5) & 0x3f;
47 	tm.tm_sec  = ((dd >> 0) & 0x1f) * 2;
48 	tm.tm_year = ((dd >> 25) & 0x7f) + 80;
49 	tm.tm_mon  = ((dd >> 21) & 0x0f) - 1;
50 	tm.tm_mday = (dd >> 16) & 0x1f;
51 	t = mktime (&tm);
52 	t -= _timezone;
53 	return t;
54 }
55 
getzvolume(struct znode * parent,struct zfile * zf,unsigned int id)56 static struct zvolume *getzvolume (struct znode *parent, struct zfile *zf, unsigned int id)
57 {
58 	struct zvolume *zv = NULL;
59 
60 	switch (id)
61 	{
62 #ifdef A_ZIP
63 	case ArchiveFormatZIP:
64 		zv = archive_directory_zip (zf);
65 		break;
66 #endif
67 #ifdef A_7Z
68 	case ArchiveFormat7Zip:
69 		zv = archive_directory_7z (zf);
70 		break;
71 #endif
72 #ifdef A_RAR
73 	case ArchiveFormatRAR:
74 		zv = archive_directory_rar (zf);
75 		break;
76 #endif
77 #ifdef A_LHA
78 	case ArchiveFormatLHA:
79 		zv = archive_directory_lha (zf);
80 		break;
81 #endif
82 #ifdef A_LZX
83 	case ArchiveFormatLZX:
84 		zv = archive_directory_lzx (zf);
85 		break;
86 #endif
87 	case ArchiveFormatPLAIN:
88 		zv = archive_directory_plain (zf);
89 		break;
90 	case ArchiveFormatADF:
91 		zv = archive_directory_adf (parent, zf);
92 		break;
93 	case ArchiveFormatRDB:
94 		zv = archive_directory_rdb (zf);
95 		break;
96 	case ArchiveFormatTAR:
97 		zv = archive_directory_tar (zf);
98 		break;
99 	case ArchiveFormatFAT:
100 		zv = archive_directory_fat (zf);
101 		break;
102 	}
103 #ifdef ARCHIVEACCESS
104 	if (!zv)
105 		zv = archive_directory_arcacc (zf, id);
106 #endif
107 	return zv;
108 }
109 
archive_access_select(struct znode * parent,struct zfile * zf,unsigned int id,int dodefault,int * retcode,int index)110 struct zfile *archive_access_select (struct znode *parent, struct zfile *zf, unsigned int id, int dodefault, int *retcode, int index)
111 {
112 	struct zvolume *zv;
113 	struct znode *zn;
114 	int zipcnt, first, select;
115 	TCHAR tmphist[MAX_DPATH];
116 	struct zfile *z = NULL;
117 	int we_have_file;
118 	int diskimg;
119 	int mask = zf->zfdmask;
120 	int canhistory = (mask & ZFD_DISKHISTORY) && !(mask & ZFD_CHECKONLY);
121 	int getflag = (mask &  ZFD_DELAYEDOPEN) ? FILE_DELAYEDOPEN : 0;
122 
123 	if (retcode)
124 		*retcode = 0;
125 	if (index > 0)
126 		return NULL;
127 	if (zfile_needwrite (zf)) {
128 		if (retcode)
129 			*retcode = -1;
130 		return NULL;
131 	}
132 	zv = getzvolume (parent, zf, id);
133 	if (!zv)
134 		return NULL;
135 	we_have_file = 0;
136 	tmphist[0] = 0;
137 	zipcnt = 1;
138 	first = 1;
139 	zn = &zv->root;
140 	while (zn) {
141 		int isok = 1;
142 
143 		diskimg = -1;
144 		if (zn->type != ZNODE_FILE)
145 			isok = 0;
146 		if (zfile_is_ignore_ext (zn->fullname))
147 			isok = 0;
148 		diskimg = zfile_is_diskimage (zn->fullname);
149 		if (isok) {
150 			if (tmphist[0]) {
151 #ifndef _CONSOLE
152 				if (diskimg >= 0 && canhistory)
153 					DISK_history_add (tmphist, -1, diskimg, 1);
154 #endif
155 				tmphist[0] = 0;
156 				first = 0;
157 			}
158 			if (first) {
159 				if (diskimg >= 0)
160 					_tcscpy (tmphist, zn->fullname);
161 			} else {
162 				_tcscpy (tmphist, zn->fullname);
163 #ifndef _CONSOLE
164 				if (diskimg >= 0 && canhistory)
165 					DISK_history_add (tmphist, -1, diskimg, 1);
166 #endif
167 				tmphist[0] = 0;
168 			}
169 			select = 0;
170 			if (!zf->zipname)
171 				select = 1;
172 			if (zf->zipname && _tcslen (zn->fullname) >= _tcslen (zf->zipname) && !strcasecmp (zf->zipname, zn->fullname + _tcslen (zn->fullname) - _tcslen (zf->zipname)))
173 				select = -1;
174 			if (zf->zipname && zf->zipname[0] == '#' && _tstol (zf->zipname + 1) == zipcnt)
175 				select = -1;
176 			if (select && we_have_file < 10) {
177 				struct zfile *zt = NULL;
178 				TCHAR *ext = _tcsrchr (zn->fullname, '.');
179 				int whf = 1;
180 				int ft = 0;
181 				if (mask & ZFD_CD) {
182 					if (ext && !_tcsicmp (ext, _T(".iso"))) {
183 						whf = 2;
184 						ft = ZFILE_CDIMAGE;
185 					}
186 					if (ext && !_tcsicmp (ext, _T(".chd"))) {
187 						whf = 2;
188 						ft = ZFILE_CDIMAGE;
189 					}
190 					if (ext && !_tcsicmp (ext, _T(".ccd"))) {
191 						whf = 9;
192 						ft = ZFILE_CDIMAGE;
193 					}
194 					if (ext && !_tcsicmp (ext, _T(".cue"))) {
195 						whf = 10;
196 						ft = ZFILE_CDIMAGE;
197 					}
198 				} else {
199 					zt = archive_getzfile (zn, id, getflag);
200 					ft = zfile_gettype (zt);
201 				}
202 				if ((select < 0 || ft) && whf > we_have_file) {
203 					if (!zt)
204 						zt = archive_getzfile (zn, id, getflag);
205 					we_have_file = whf;
206 					if (z)
207 						zfile_fclose (z);
208 					z = zt;
209 					zt = NULL;
210 				}
211 				zfile_fclose (zt);
212 			}
213 		}
214 		zipcnt++;
215 		zn = zn->next;
216 	}
217 #ifndef _CONSOLE
218 	diskimg = zfile_is_diskimage (zfile_getname (zf));
219 	if (diskimg >= 0 && first && tmphist[0] && canhistory)
220 		DISK_history_add (zfile_getname (zf), -1, diskimg, 1);
221 #endif
222 	zfile_fclose_archive (zv);
223 	if (z) {
224 		zfile_fclose (zf);
225 		zf = z;
226 	} else if (!dodefault && zf->zipname && zf->zipname[0]) {
227 		if (retcode)
228 			*retcode = -1;
229 		zf = NULL;
230 	} else {
231 		zf = NULL;
232 	}
233 	return zf;
234 }
235 
archive_access_arcacc_select(struct zfile * zf,unsigned int id,int * retcode)236 struct zfile *archive_access_arcacc_select (struct zfile *zf, unsigned int id, int *retcode)
237 {
238 	if (zfile_needwrite (zf)) {
239 		if (retcode)
240 			*retcode = -1;
241 		return NULL;
242 	}
243 	return zf;
244 }
245 
archive_access_scan(struct zfile * zf,zfile_callback zc,void * user,unsigned int id)246 void archive_access_scan (struct zfile *zf, zfile_callback zc, void *user, unsigned int id)
247 {
248 	struct zvolume *zv;
249 	struct znode *zn;
250 
251 	zv = getzvolume (NULL, zf, id);
252 	if (!zv)
253 		return;
254 	zn = &zv->root;
255 	while (zn) {
256 		if (zn->type == ZNODE_FILE) {
257 			struct zfile *zf2 = archive_getzfile (zn, id, 0);
258 			if (zf2) {
259 				int ztype = iszip (zf2);
260 				if (ztype) {
261 					zfile_fclose (zf2);
262 				} else {
263 					int ret = zc (zf2, user);
264 					zfile_fclose (zf2);
265 					if (ret)
266 						break;
267 				}
268 			}
269 		}
270 		zn = zn->next;
271 	}
272 	zfile_fclose_archive (zv);
273 }
274 
275 /* TAR */
276 
archive_close_tar(void * handle)277 static void archive_close_tar (void *handle)
278 {
279 }
280 
archive_directory_tar(struct zfile * z)281 struct zvolume *archive_directory_tar (struct zfile *z)
282 {
283 	struct zvolume *zv;
284 	struct znode *zn;
285 
286 	_tzset ();
287 	zv = zvolume_alloc (z, ArchiveFormatTAR, NULL, NULL);
288 	for (;;) {
289 		uae_u8 block[512];
290 		char name[MAX_DPATH];
291 		int ustar = 0;
292 		struct zarchive_info zai;
293 		int valid = 1;
294 		uae_u64 size;
295 
296 		if (zfile_fread (block, 512, 1, z) != 1)
297 			break;
298 		if (block[0] == 0)
299 			break;
300 
301 		if (!memcmp (block + 257, "ustar  ", 8))
302 			ustar = 1;
303 		name[0] = 0;
304 		if (ustar)
305 			strcpy (name, (char*)block + 345);
306 		strcat (name, (char*)block);
307 
308 		if (name[0] == 0)
309 			valid = 0;
310 		if (block[156] != '0')
311 			valid = 0;
312 		if (ustar && (block[256] != 0 && block[256] != '0'))
313 			valid = 0;
314 
315 		size = _strtoui64 ((char*)block + 124, NULL, 8);
316 
317 		if (valid) {
318 			memset (&zai, 0, sizeof zai);
319 			zai.name = au (name);
320 			zai.size = size;
321 			zai.tv.tv_sec = _strtoui64 ((char*)block + 136, NULL, 8);
322 			zai.tv.tv_sec += _timezone;
323 			if (_daylight)
324 				zai.tv.tv_sec -= 1 * 60 * 60;
325 			if (zai.name[_tcslen (zai.name) - 1] == '/') {
326 				zn = zvolume_adddir_abs (zv, &zai);
327 			} else {
328 				zn = zvolume_addfile_abs (zv, &zai);
329 				if (zn)
330 					zn->offset = zfile_ftell (z);
331 			}
332 			xfree (zai.name);
333 		}
334 		zfile_fseek (z, (size + 511) & ~511, SEEK_CUR);
335 	}
336 	zv->method = ArchiveFormatTAR;
337 	return zv;
338 }
339 
archive_access_tar(struct znode * zn)340 struct zfile *archive_access_tar (struct znode *zn)
341 {
342 #if 0
343 	struct zfile *zf = zfile_fopen_empty (zn->volume->archive, zn->fullname, zn->size);
344 	zfile_fseek (zn->volume->archive, zn->offset, SEEK_SET);
345 	zfile_fwrite (zf->data, zn->size, 1, zn->volume->archive);
346 	return zf;
347 #else
348 	return zfile_fopen_parent (zn->volume->archive, zn->fullname, zn->offset, zn->size);
349 #endif
350 }
351 
352 /* ZIP */
353 #ifdef A_ZIP
354 
archive_close_zip(void * handle)355 static void archive_close_zip (void *handle)
356 {
357 }
358 
archive_directory_zip(struct zfile * z)359 struct zvolume *archive_directory_zip (struct zfile *z)
360 {
361 	unzFile uz;
362 	unz_file_info file_info;
363 	struct zvolume *zv;
364 	int err;
365 
366 	uz = unzOpen (z);
367 	if (!uz)
368 		return 0;
369 	if (unzGoToFirstFile (uz) != UNZ_OK)
370 		return 0;
371 	zv = zvolume_alloc (z, ArchiveFormatZIP, NULL, NULL);
372 	for (;;) {
373 		char filename_inzip2[MAX_DPATH];
374 		TCHAR c;
375 		struct zarchive_info zai;
376 		time_t t;
377 		unsigned int dd;
378 		TCHAR *filename_inzip;
379 
380 		err = unzGetCurrentFileInfo (uz, &file_info, filename_inzip2, sizeof (filename_inzip2), NULL, 0, NULL, 0);
381 		if (err != UNZ_OK)
382 			return 0;
383 		if (file_info.flag & (1 << 11)) { // UTF-8 encoded
384 			filename_inzip = utf8u (filename_inzip2);
385 		} else {
386 			filename_inzip = au (filename_inzip2);
387 		}
388 		dd = file_info.dosDate;
389 		t = fromdostime (dd);
390 		memset (&zai, 0, sizeof zai);
391 		zai.name = filename_inzip;
392 		zai.tv.tv_sec = t;
393 		zai.flags = -1;
394 		c = filename_inzip[_tcslen (filename_inzip) - 1];
395 		if (c != '/' && c != '\\') {
396 			int err = unzOpenCurrentFile (uz);
397 			if (err == UNZ_OK) {
398 				struct znode *zn;
399 				zai.size = file_info.uncompressed_size;
400 				zn = zvolume_addfile_abs (zv, &zai);
401 			}
402 		} else {
403 			filename_inzip[_tcslen (filename_inzip) - 1] = 0;
404 			zvolume_adddir_abs (zv, &zai);
405 		}
406 		xfree (filename_inzip);
407 		err = unzGoToNextFile (uz);
408 		if (err != UNZ_OK)
409 			break;
410 	}
411 	unzClose (uz);
412 	zv->method = ArchiveFormatZIP;
413 	return zv;
414 }
415 
416 
archive_do_zip(struct znode * zn,struct zfile * z,int flags)417 static struct zfile *archive_do_zip (struct znode *zn, struct zfile *z, int flags)
418 {
419 	unzFile uz;
420 	int i;
421 	TCHAR tmp[MAX_DPATH];
422 	TCHAR *name = z ? z->archiveparent->name : zn->volume->root.fullname;
423 	char *s;
424 
425 	uz = unzOpen (z ? z->archiveparent : zn->volume->archive);
426 	if (!uz)
427 		return 0;
428 	if (z)
429 		_tcscpy (tmp, z->archiveparent->name);
430 	else
431 		_tcscpy (tmp, zn->fullname + _tcslen (zn->volume->root.fullname) + 1);
432 	if (unzGoToFirstFile (uz) != UNZ_OK)
433 		goto error;
434 	for (i = 0; tmp[i]; i++) {
435 		if (tmp[i] == '\\')
436 			tmp[i] = '/';
437 	}
438 	s = ua (tmp);
439 	if (unzLocateFile (uz, s, 1) != UNZ_OK) {
440 		xfree (s);
441 		for (i = 0; tmp[i]; i++) {
442 #ifdef FSUAE
443 
444 #else
445 			if (tmp[i] == '/')
446 				tmp[i] = '\\';
447 #endif
448 		}
449 		s = ua (tmp);
450 		if (unzLocateFile (uz, s, 1) != UNZ_OK) {
451 			xfree (s);
452 			goto error;
453 		}
454 	}
455 	xfree (s);
456 	s = NULL;
457 	if (unzOpenCurrentFile (uz) != UNZ_OK)
458 		goto error;
459 	if (!z)
460 		z = zfile_fopen_empty (NULL, zn->fullname, zn->size);
461 	if (z) {
462 		int err = -1;
463 		if (!(flags & FILE_DELAYEDOPEN) || z->size <= PEEK_BYTES) {
464 			unpack_log (_T("ZIP: unpacking %s, flags=%d\n"), name, flags);
465 			err = unzReadCurrentFile (uz, z->data, z->datasize);
466 			unpack_log (_T("ZIP: unpacked, code=%d\n"), err);
467 		} else {
468 			z->archiveparent = zfile_dup (zn->volume->archive);
469 			if (z->archiveparent) {
470 				unpack_log (_T("ZIP: delayed open '%s'\n"), name);
471 				xfree (z->archiveparent->name);
472 				z->archiveparent->name = my_strdup (tmp);
473 				z->datasize = PEEK_BYTES;
474 				err = unzReadCurrentFile (uz, z->data, z->datasize);
475 				unpack_log (_T("ZIP: unpacked, code=%d\n"), err);
476 			} else {
477 				unpack_log (_T("ZIP: unpacking %s (failed DELAYEDOPEN)\n"), name);
478 				err = unzReadCurrentFile (uz, z->data, z->datasize);
479 				unpack_log (_T("ZIP: unpacked, code=%d\n"), err);
480 			}
481 		}
482 	}
483 	unzCloseCurrentFile (uz);
484 	unzClose (uz);
485 	return z;
486 error:
487 	unzClose (uz);
488 	return NULL;
489 }
490 
archive_access_zip(struct znode * zn,int flags)491 static struct zfile *archive_access_zip (struct znode *zn, int flags)
492 {
493 	return archive_do_zip (zn, NULL, flags);
494 }
archive_unpack_zip(struct zfile * zf)495 static struct zfile *archive_unpack_zip (struct zfile *zf)
496 {
497 	return archive_do_zip (NULL, zf, 0);
498 }
499 #endif
500 
501 #ifdef A_7Z
502 /* 7Z */
503 
504 #include "7z/7z.h"
505 #include "7z/Alloc.h"
506 #include "7z/7zFile.h"
507 #include "7z/7zVersion.h"
508 #include "7z/7zCrc.h"
509 
SzAlloc(void * p,size_t size)510 static void *SzAlloc (void *p, size_t size)
511 {
512 	return xmalloc (uae_u8, size);
513 }
SzFree(void * p,void * address)514 static void SzFree(void *p, void *address)
515 {
516 	xfree (address);
517 }
518 
519 static ISzAlloc allocImp;
520 static ISzAlloc allocTempImp;
521 
SzFileReadImp(void * object,void * buffer,size_t * size)522 static SRes SzFileReadImp (void *object, void *buffer, size_t *size)
523 {
524 	CFileInStream *s = (CFileInStream *)object;
525 	struct zfile *zf = (struct zfile*)s->file.myhandle;
526 	*size = zfile_fread (buffer, 1, *size, zf);
527 	return SZ_OK;
528 }
529 
SzFileSeekImp(void * object,Int64 * pos,ESzSeek origin)530 static SRes SzFileSeekImp(void *object, Int64 *pos, ESzSeek origin)
531 {
532 	CFileInStream *s = (CFileInStream *)object;
533 	struct zfile *zf = (struct zfile*)s->file.myhandle;
534 	int org = 0;
535 	switch (origin)
536 	{
537 	case SZ_SEEK_SET: org = SEEK_SET; break;
538 	case SZ_SEEK_CUR: org = SEEK_CUR; break;
539 	case SZ_SEEK_END: org = SEEK_END; break;
540 	}
541 	zfile_fseek (zf, *pos, org);
542 	*pos = zfile_ftell (zf);
543 	return SZ_OK;
544 }
545 
init_7z(void)546 static void init_7z (void)
547 {
548 	static int initialized;
549 
550 	if (initialized)
551 		return;
552 	initialized = 1;
553 	allocImp.Alloc = SzAlloc;
554 	allocImp.Free = SzFree;
555 	allocTempImp.Alloc = SzAlloc;
556 	allocTempImp.Free = SzFree;
557 	CrcGenerateTable ();
558 	_tzset ();
559 }
560 
561 struct SevenZContext
562 {
563 	CSzArEx db;
564 	CFileInStream archiveStream;
565 	CLookToRead lookStream;
566 	Byte *outBuffer;
567 	size_t outBufferSize;
568 	UInt32 blockIndex;
569 };
570 
archive_close_7z(void * ctx)571 static void archive_close_7z (void *ctx)
572 {
573 	struct SevenZContext *ctx7 = (struct SevenZContext*)ctx;
574 	SzArEx_Free (&ctx7->db, &allocImp);
575 	allocImp.Free (&allocImp, ctx7->outBuffer);
576 	xfree (ctx);
577 }
578 
579 #define EPOCH_DIFF 0x019DB1DED53E8000LL /* 116444736000000000 nsecs */
580 #define RATE_DIFF 10000000 /* 100 nsecs */
581 
archive_directory_7z(struct zfile * z)582 struct zvolume *archive_directory_7z (struct zfile *z)
583 {
584 	SRes res;
585 	struct zvolume *zv;
586 	int i;
587 	struct SevenZContext *ctx;
588 
589 	init_7z ();
590 	ctx = xcalloc (struct SevenZContext, 1);
591 	ctx->blockIndex = 0xffffffff;
592 	ctx->archiveStream.s.Read = SzFileReadImp;
593 	ctx->archiveStream.s.Seek = SzFileSeekImp;
594 	ctx->archiveStream.file.myhandle = (void*)z;
595 	LookToRead_CreateVTable (&ctx->lookStream, False);
596 	ctx->lookStream.realStream = &ctx->archiveStream.s;
597 	LookToRead_Init (&ctx->lookStream);
598 
599 	SzArEx_Init (&ctx->db);
600 	res = SzArEx_Open (&ctx->db, &ctx->lookStream.s, &allocImp, &allocTempImp);
601 	if (res != SZ_OK) {
602 		write_log (_T("7Z: SzArchiveOpen %s returned %d\n"), zfile_getname (z), res);
603 		xfree (ctx);
604 		return NULL;
605 	}
606 	zv = zvolume_alloc (z, ArchiveFormat7Zip, ctx, NULL);
607 	for (i = 0; i < ctx->db.db.NumFiles; i++) {
608 		CSzFileItem *f = ctx->db.db.Files + i;
609 		TCHAR *name = (TCHAR*)(ctx->db.FileNames.data + ctx->db.FileNameOffsets[i] * 2);
610 		struct zarchive_info zai;
611 
612 		memset(&zai, 0, sizeof zai);
613 		zai.name = name;
614 		zai.flags = f->AttribDefined ? f->Attrib : -1;
615 		zai.size = f->Size;
616 		if (f->MTimeDefined) {
617 			uae_u64 t = (((uae_u64)f->MTime.High) << 32) | f->MTime.Low;
618 			if (t >= EPOCH_DIFF) {
619 				zai.tv.tv_sec = (t - EPOCH_DIFF) / RATE_DIFF;
620 				zai.tv.tv_sec -= _timezone;
621 				if (_daylight)
622 					zai.tv.tv_sec += 1 * 60 * 60;
623 			}
624 		}
625 		if (!f->IsDir) {
626 			struct znode *zn = zvolume_addfile_abs (zv, &zai);
627 			zn->offset = i;
628 		}
629 	}
630 	zv->method = ArchiveFormat7Zip;
631 	return zv;
632 }
633 
archive_access_7z(struct znode * zn)634 static struct zfile *archive_access_7z (struct znode *zn)
635 {
636 	SRes res;
637 	struct zvolume *zv = zn->volume;
638 	struct zfile *z = NULL;
639 	size_t offset;
640 	size_t outSizeProcessed;
641 	struct SevenZContext *ctx;
642 
643 	z = zfile_fopen_empty (NULL, zn->fullname, zn->size);
644 	if (!z)
645 		return NULL;
646 	ctx = (struct SevenZContext*)zv->handle;
647 	res = SzArEx_Extract (&ctx->db, &ctx->lookStream.s, zn->offset,
648 		&ctx->blockIndex, &ctx->outBuffer, &ctx->outBufferSize,
649 		&offset, &outSizeProcessed,
650 		&allocImp, &allocTempImp);
651 	if (res == SZ_OK) {
652 		zfile_fwrite (ctx->outBuffer + offset, zn->size, 1, z);
653 	} else {
654 		write_log (_T("7Z: SzExtract %s returned %d\n"), zn->fullname, res);
655 		zfile_fclose (z);
656 		z = NULL;
657 	}
658 	return z;
659 }
660 #endif
661 
662 /* RAR */
663 #ifdef A_RAR
664 
665 /* copy and paste job? you are only imagining it! */
666 static struct zfile *rarunpackzf; /* stupid unrar.dll */
667 #include <unrar.h>
668 typedef HANDLE (_stdcall* RAROPENARCHIVEEX)(struct RAROpenArchiveDataEx*);
669 static RAROPENARCHIVEEX pRAROpenArchiveEx;
670 typedef int (_stdcall* RARREADHEADEREX)(HANDLE,struct RARHeaderDataEx*);
671 static RARREADHEADEREX pRARReadHeaderEx;
672 typedef int (_stdcall* RARPROCESSFILE)(HANDLE,int,char*,char*);
673 static RARPROCESSFILE pRARProcessFile;
674 typedef int (_stdcall* RARCLOSEARCHIVE)(HANDLE);
675 static RARCLOSEARCHIVE pRARCloseArchive;
676 typedef void (_stdcall* RARSETCALLBACK)(HANDLE,UNRARCALLBACK,LONG);
677 static RARSETCALLBACK pRARSetCallback;
678 typedef int (_stdcall* RARGETDLLVERSION)(void);
679 static RARGETDLLVERSION pRARGetDllVersion;
680 
canrar(void)681 static int canrar (void)
682 {
683 	static int israr;
684 
685 	if (israr == 0) {
686 		israr = -1;
687 #ifdef _WIN32
688 		{
689 			HMODULE rarlib;
690 
691 			rarlib = WIN32_LoadLibrary (_T("unrar.dll"));
692 			if (rarlib) {
693 				TCHAR tmp[MAX_DPATH];
694 				tmp[0] = 0;
695 				GetModuleFileName (rarlib, tmp, sizeof tmp / sizeof (TCHAR));
696 				pRAROpenArchiveEx = (RAROPENARCHIVEEX)GetProcAddress (rarlib, "RAROpenArchiveEx");
697 				pRARReadHeaderEx = (RARREADHEADEREX)GetProcAddress (rarlib, "RARReadHeaderEx");
698 				pRARProcessFile = (RARPROCESSFILE)GetProcAddress (rarlib, "RARProcessFile");
699 				pRARCloseArchive = (RARCLOSEARCHIVE)GetProcAddress (rarlib, "RARCloseArchive");
700 				pRARSetCallback = (RARSETCALLBACK)GetProcAddress (rarlib, "RARSetCallback");
701 				pRARGetDllVersion = (RARGETDLLVERSION)GetProcAddress (rarlib, "RARGetDllVersion");
702 				if (pRAROpenArchiveEx && pRARReadHeaderEx && pRARProcessFile && pRARCloseArchive && pRARSetCallback) {
703 					int version = -1;
704 					israr = 1;
705 					if (pRARGetDllVersion)
706 						version = pRARGetDllVersion ();
707 					write_log (_T("%s version %08X detected\n"), tmp, version);
708 					if (version < 4) {
709 						write_log (_T("Too old unrar.dll, must be at least version 4\n"));
710 						israr = -1;
711 					}
712 
713 				}
714 			}
715 		}
716 #endif
717 	}
718 	return israr < 0 ? 0 : 1;
719 }
720 
RARCallbackProc(UINT msg,LONG UserData,LONG P1,LONG P2)721 static int CALLBACK RARCallbackProc (UINT msg, LONG UserData, LONG P1, LONG P2)
722 {
723 	if (msg == UCM_PROCESSDATA) {
724 		zfile_fwrite ((uae_u8*)P1, 1, P2, rarunpackzf);
725 		return 0;
726 	}
727 	return -1;
728 }
729 
730 struct RARContext
731 {
732 	struct RAROpenArchiveDataEx OpenArchiveData;
733 	struct RARHeaderDataEx HeaderData;
734 	HANDLE hArcData;
735 };
736 
archive_close_rar(void * ctx)737 static void archive_close_rar (void *ctx)
738 {
739 	struct RARContext* rc = (struct RARContext*)ctx;
740 	xfree (rc);
741 }
742 
archive_directory_rar(struct zfile * z)743 struct zvolume *archive_directory_rar (struct zfile *z)
744 {
745 #ifdef WIN64
746 	return archive_directory_arcacc (z, ArchiveFormatRAR);
747 #else
748 	struct zvolume *zv;
749 	struct RARContext *rc;
750 	struct zfile *zftmp;
751 	int cnt;
752 
753 	if (!canrar ())
754 		return archive_directory_arcacc (z, ArchiveFormatRAR);
755 	if (z->data)
756 		/* wtf? stupid unrar.dll only accept filename as an input.. */
757 		return archive_directory_arcacc (z, ArchiveFormatRAR);
758 	rc = xcalloc (struct RARContext, 1);
759 	zv = zvolume_alloc (z, ArchiveFormatRAR, rc, NULL);
760 	rc->OpenArchiveData.ArcNameW = z->name;
761 	rc->OpenArchiveData.OpenMode = RAR_OM_LIST;
762 	rc->hArcData = pRAROpenArchiveEx (&rc->OpenArchiveData);
763 	if (rc->OpenArchiveData.OpenResult != 0) {
764 		zfile_fclose_archive (zv);
765 		return archive_directory_arcacc (z, ArchiveFormatRAR);
766 	}
767 	pRARSetCallback (rc->hArcData, RARCallbackProc, 0);
768 	cnt = 0;
769 	while (pRARReadHeaderEx (rc->hArcData, &rc->HeaderData) == 0) {
770 		struct zarchive_info zai;
771 		struct znode *zn;
772 		memset (&zai, 0, sizeof zai);
773 		zai.name = rc->HeaderData.FileNameW;
774 		zai.size = rc->HeaderData.UnpSize;
775 		zai.flags = -1;
776 		zai.tv.tv_sec = fromdostime (rc->HeaderData.FileTime);
777 		zn = zvolume_addfile_abs (zv, &zai);
778 		zn->offset = cnt++;
779 		pRARProcessFile (rc->hArcData, RAR_SKIP, NULL, NULL);
780 	}
781 	pRARCloseArchive (rc->hArcData);
782 	zftmp = zfile_fopen_empty (z, z->name, 0);
783 	zv->archive = zftmp;
784 	zv->method = ArchiveFormatRAR;
785 	return zv;
786 #endif
787 }
788 
archive_access_rar(struct znode * zn)789 static struct zfile *archive_access_rar (struct znode *zn)
790 {
791 #ifndef WIN64
792 	struct RARContext *rc = (struct RARContext*)zn->volume->handle;
793 	int i;
794 	struct zfile *zf = NULL;
795 
796 	if (zn->volume->method != ArchiveFormatRAR)
797 		return archive_access_arcacc (zn);
798 	rc->OpenArchiveData.OpenMode = RAR_OM_EXTRACT;
799 	rc->hArcData = pRAROpenArchiveEx (&rc->OpenArchiveData);
800 	if (rc->OpenArchiveData.OpenResult != 0)
801 		return NULL;
802 	pRARSetCallback (rc->hArcData, RARCallbackProc, 0);
803 	for (i = 0; i <= zn->offset; i++) {
804 		if (pRARReadHeaderEx (rc->hArcData, &rc->HeaderData))
805 			return NULL;
806 		if (i < zn->offset) {
807 			if (pRARProcessFile (rc->hArcData, RAR_SKIP, NULL, NULL))
808 				goto end;
809 		}
810 	}
811 	zf = zfile_fopen_empty (zn->volume->archive, zn->fullname, zn->size);
812 	if (zf) {
813 		rarunpackzf = zf;
814 		if (pRARProcessFile (rc->hArcData, RAR_TEST, NULL, NULL)) {
815 			zfile_fclose (zf);
816 			zf = NULL;
817 		}
818 	}
819 end:
820 	pRARCloseArchive(rc->hArcData);
821 	return zf;
822 #else
823 	return NULL;
824 #endif
825 }
826 #endif
827 
828 
829 /* ArchiveAccess */
830 
831 
832 #if defined(ARCHIVEACCESS)
833 
834 struct aaFILETIME
835 {
836 	uae_u32 dwLowDateTime;
837 	uae_u32 dwHighDateTime;
838 };
839 typedef void* aaHandle;
840 // This struct contains file information from an archive. The caller may store
841 // this information for accessing this file after calls to findFirst, findNext
842 #define FileInArchiveInfoStringSize 1024
843 struct aaFileInArchiveInfo {
844 	int ArchiveHandle; // handle for Archive/class pointer
845 	uae_u64 CompressedFileSize;
846 	uae_u64 UncompressedFileSize;
847 	uae_u32 attributes;
848 	int IsDir;
849 	struct aaFILETIME LastWriteTime;
850 	char path[FileInArchiveInfoStringSize];
851 };
852 
853 typedef HRESULT (__stdcall *aaReadCallback)(int StreamID, uae_u64 offset, uae_u32 count, void* buf, uae_u32 *processedSize);
854 typedef HRESULT (__stdcall *aaWriteCallback)(int StreamID, uae_u64 offset, uae_u32 count, const void *buf, uae_u32 *processedSize);
855 typedef aaHandle (__stdcall *aapOpenArchive)(aaReadCallback function, int StreamID, uae_u64 FileSize, int ArchiveType, int *result, TCHAR *password);
856 typedef int (__stdcall *aapGetFileCount)(aaHandle ArchiveHandle);
857 typedef int (__stdcall *aapGetFileInfo)(aaHandle ArchiveHandle, int FileNum, struct aaFileInArchiveInfo *FileInfo);
858 typedef int (__stdcall *aapExtract)(aaHandle ArchiveHandle, int FileNum, int StreamID, aaWriteCallback WriteFunc, uae_u64 *written);
859 typedef int (__stdcall *aapCloseArchive)(aaHandle ArchiveHandle);
860 
861 static aapOpenArchive aaOpenArchive;
862 static aapGetFileCount aaGetFileCount;
863 static aapGetFileInfo aaGetFileInfo;
864 static aapExtract aaExtract;
865 static aapCloseArchive aaCloseArchive;
866 
867 #ifdef _WIN32
868 static HMODULE arcacc_mod;
869 
arcacc_free(void)870 static void arcacc_free (void)
871 {
872 	if (arcacc_mod)
873 		FreeLibrary (arcacc_mod);
874 	arcacc_mod = NULL;
875 }
876 
arcacc_init(struct zfile * zf)877 static int arcacc_init (struct zfile *zf)
878 {
879 	if (arcacc_mod)
880 		return 1;
881 	arcacc_mod = WIN32_LoadLibrary (_T("archiveaccess.dll"));
882 	if (!arcacc_mod) {
883 		write_log (_T("failed to open archiveaccess.dll ('%s')\n"), zfile_getname (zf));
884 		return 0;
885 	}
886 	aaOpenArchive = (aapOpenArchive) GetProcAddress (arcacc_mod, "aaOpenArchive");
887 	aaGetFileCount = (aapGetFileCount) GetProcAddress (arcacc_mod, "aaGetFileCount");
888 	aaGetFileInfo = (aapGetFileInfo) GetProcAddress (arcacc_mod, "aaGetFileInfo");
889 	aaExtract = (aapExtract) GetProcAddress (arcacc_mod, "aaExtract");
890 	aaCloseArchive = (aapCloseArchive) GetProcAddress (arcacc_mod, "aaCloseArchive");
891 	if (!aaOpenArchive || !aaGetFileCount || !aaGetFileInfo || !aaExtract || !aaCloseArchive) {
892 		write_log (_T("Missing functions in archiveaccess.dll. Old version?\n"));
893 		arcacc_free ();
894 		return 0;
895 	}
896 	return 1;
897 }
898 #endif
899 
900 #define ARCACC_STACKSIZE 10
901 static struct zfile *arcacc_stack[ARCACC_STACKSIZE];
902 static int arcacc_stackptr = -1;
903 
arcacc_push(struct zfile * f)904 static int arcacc_push (struct zfile *f)
905 {
906 	if (arcacc_stackptr == ARCACC_STACKSIZE - 1)
907 		return -1;
908 	arcacc_stackptr++;
909 	arcacc_stack[arcacc_stackptr] = f;
910 	return arcacc_stackptr;
911 }
arcacc_pop(void)912 static void arcacc_pop (void)
913 {
914 	arcacc_stackptr--;
915 }
916 
readCallback(int StreamID,uae_u64 offset,uae_u32 count,void * buf,uae_u32 * processedSize)917 static HRESULT __stdcall readCallback (int StreamID, uae_u64 offset, uae_u32 count, void *buf, uae_u32 *processedSize)
918 {
919 	struct zfile *f = arcacc_stack[StreamID];
920 	int ret;
921 
922 	zfile_fseek (f, (long)offset, SEEK_SET);
923 	ret = zfile_fread (buf, 1, count, f);
924 	if (processedSize)
925 		*processedSize = ret;
926 	return 0;
927 }
writeCallback(int StreamID,uae_u64 offset,uae_u32 count,const void * buf,uae_u32 * processedSize)928 static HRESULT __stdcall writeCallback (int StreamID, uae_u64 offset, uae_u32 count, const void *buf, uae_u32 *processedSize)
929 {
930 	struct zfile *f = arcacc_stack[StreamID];
931 	int ret;
932 
933 	ret = zfile_fwrite ((void*)buf, 1, count, f);
934 	if (processedSize)
935 		*processedSize = ret;
936 	if (ret != count)
937 		return -1;
938 	return 0;
939 }
940 
archive_directory_arcacc(struct zfile * z,unsigned int id)941 struct zvolume *archive_directory_arcacc (struct zfile *z, unsigned int id)
942 {
943 	aaHandle ah;
944 	int id_r, status;
945 	int fc, f;
946 	struct zvolume *zv;
947 	int skipsize = 0;
948 
949 	if (!arcacc_init (z))
950 		return NULL;
951 	zv = zvolume_alloc (z, ArchiveFormatAA, NULL, NULL);
952 	id_r = arcacc_push (z);
953 	ah = aaOpenArchive (readCallback, id_r, zv->archivesize, id, &status, NULL);
954 	if (!status) {
955 		zv->handle = ah;
956 		fc = aaGetFileCount (ah);
957 		for (f = 0; f < fc; f++) {
958 			struct aaFileInArchiveInfo fi;
959 			TCHAR *name;
960 			struct znode *zn;
961 			struct zarchive_info zai;
962 
963 			memset (&fi, 0, sizeof (fi));
964 			aaGetFileInfo (ah, f, &fi);
965 			if (fi.IsDir)
966 				continue;
967 
968 			name = au (fi.path);
969 			memset (&zai, 0, sizeof zai);
970 			zai.name = name;
971 			zai.flags = -1;
972 			zai.size = (unsigned int)fi.UncompressedFileSize;
973 			zn = zvolume_addfile_abs (zv, &zai);
974 			xfree (name);
975 			zn->offset = f;
976 			zn->method = id;
977 
978 			if (id == ArchiveFormat7Zip) {
979 				if (fi.CompressedFileSize)
980 					skipsize = 0;
981 				skipsize += (int)fi.UncompressedFileSize;
982 			}
983 		}
984 		aaCloseArchive (ah);
985 	}
986 	arcacc_pop ();
987 	zv->method = ArchiveFormatAA;
988 	return zv;
989 }
990 
991 
archive_access_arcacc(struct znode * zn)992 static struct zfile *archive_access_arcacc (struct znode *zn)
993 {
994 	struct zfile *zf;
995 	struct zfile *z = zn->volume->archive;
996 	int status, id_r, id_w;
997 	aaHandle ah;
998 	int ok = 0;
999 
1000 	id_r = arcacc_push (z);
1001 	ah = aaOpenArchive (readCallback, id_r, zn->volume->archivesize, zn->method, &status, NULL);
1002 	if (!status) {
1003 		int err;
1004 		uae_u64 written = 0;
1005 		struct aaFileInArchiveInfo fi;
1006 		memset (&fi, 0, sizeof (fi));
1007 		aaGetFileInfo (ah, zn->offset, &fi);
1008 		zf = zfile_fopen_empty (z, zn->fullname, zn->size);
1009 		id_w = arcacc_push (zf);
1010 		err = aaExtract(ah, zn->offset, id_w, writeCallback, &written);
1011 		if (zf->seek == fi.UncompressedFileSize)
1012 			ok = 1;
1013 		arcacc_pop();
1014 	}
1015 	aaCloseArchive(ah);
1016 	arcacc_pop();
1017 	if (ok)
1018 		return zf;
1019 	zfile_fclose(zf);
1020 	return NULL;
1021 }
1022 #endif
1023 
1024 /* plain single file */
1025 
addfile(struct zvolume * zv,struct zfile * zf,const TCHAR * path,uae_u8 * data,int size)1026 static struct znode *addfile (struct zvolume *zv, struct zfile *zf, const TCHAR *path, uae_u8 *data, int size)
1027 {
1028 	struct zarchive_info zai;
1029 	struct znode *zn;
1030 	struct zfile *z;
1031 
1032 	z = zfile_fopen_empty (zf, path, size);
1033 	if (!z)
1034 		return NULL;
1035 	zfile_fwrite (data, size, 1, z);
1036 	memset (&zai, 0, sizeof zai);
1037 	zai.name = my_strdup (path);
1038 	zai.flags = -1;
1039 	zai.size = size;
1040 	zn = zvolume_addfile_abs (zv, &zai);
1041 	if (zn)
1042 		zn->f = z;
1043 	else
1044 		zfile_fclose (z);
1045 	xfree (zai.name);
1046 	return zn;
1047 }
1048 
1049 static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00};
archive_directory_plain(struct zfile * z)1050 struct zvolume *archive_directory_plain (struct zfile *z)
1051 {
1052 	struct zfile *zf, *zf2;
1053 	struct zvolume *zv;
1054 	struct znode *zn;
1055 	struct zarchive_info zai;
1056 	uae_u8 id[8];
1057 	int rc, index;
1058 
1059 	memset (&zai, 0, sizeof zai);
1060 	zv = zvolume_alloc (z, ArchiveFormatPLAIN, NULL, NULL);
1061 	memset(id, 0, sizeof id);
1062 	zai.name = zfile_getfilename (z);
1063 	zai.flags = -1;
1064 	zfile_fseek(z, 0, SEEK_END);
1065 	zai.size = zfile_ftell (z);
1066 	zfile_fseek(z, 0, SEEK_SET);
1067 	zfile_fread(id, sizeof id, 1, z);
1068 	zfile_fseek(z, 0, SEEK_SET);
1069 	zn = zvolume_addfile_abs (zv, &zai);
1070 	if (!memcmp (id, exeheader, sizeof id)) {
1071 		char *an = ua (zai.name);
1072 		char *data = xmalloc (char, 1 + strlen (an) + 1 + 1 + 1);
1073 		sprintf (data, "\"%s\"\n", an);
1074 		zn = addfile (zv, z, _T("s/startup-sequence"), (uae_u8*)data, strlen (data));
1075 		xfree (data);
1076 		xfree (an);
1077 	}
1078 	index = 0;
1079 	for (;;) {
1080 		zf = zfile_dup (z);
1081 		if (!zf)
1082 			break;
1083 		zf2 = zuncompress (NULL, zf, 0, ZFD_ALL & ~ZFD_ADF, &rc, index);
1084 		if (zf2) {
1085 			zf = NULL;
1086 			zai.name = zfile_getfilename (zf2);
1087 			zai.flags = -1;
1088 			zfile_fseek (zf2, 0, SEEK_END);
1089 			zai.size = zfile_ftell (zf2);
1090 			zfile_fseek (zf2, 0, SEEK_SET);
1091 			zn = zvolume_addfile_abs (zv, &zai);
1092 			zn->f = zf2;
1093 //			if (zn)
1094 //				zn->offset = index + 1;
1095 //			zfile_fclose (zf2);
1096 		} else {
1097 			if (rc == 0) {
1098 				zfile_fclose (zf);
1099 				break;
1100 			}
1101 		}
1102 		index++;
1103 		zfile_fclose (zf);
1104 	}
1105 	return zv;
1106 }
archive_access_plain(struct znode * zn)1107 static struct zfile *archive_access_plain (struct znode *zn)
1108 {
1109 	struct zfile *z;
1110 
1111 	if (zn->offset) {
1112 		struct zfile *zf;
1113 		z = zfile_fopen_empty (zn->volume->archive, zn->fullname, zn->size);
1114 		zf = zfile_fopen (zfile_getname (zn->volume->archive), _T("rb"), zn->volume->archive->zfdmask & ~ZFD_ADF, zn->offset - 1);
1115 		if (zf) {
1116 			zfile_fread (z->data, zn->size, 1, zf);
1117 			zfile_fclose (zf);
1118 		}
1119 	} else {
1120 		z = zfile_fopen_empty (zn->volume->archive, zn->fullname, zn->size);
1121 		if (z) {
1122 			zfile_fseek (zn->volume->archive, 0, SEEK_SET);
1123 			zfile_fread (z->data, zn->size, 1, zn->volume->archive);
1124 		}
1125 	}
1126 	return z;
1127 }
1128 
1129 struct adfhandle {
1130 	int size;
1131 	int highblock;
1132 	int blocksize;
1133 	int rootblock;
1134 	struct zfile *z;
1135 	uae_u8 block[65536];
1136 	uae_u32 dostype;
1137 };
1138 
1139 
dos_checksum(uae_u8 * p,int blocksize)1140 static int dos_checksum (uae_u8 *p, int blocksize)
1141 {
1142 	uae_u32 cs = 0;
1143 	int i;
1144 	for (i = 0; i < blocksize; i += 4)
1145 		cs += (p[i] << 24) | (p[i + 1] << 16) | (p[i + 2] << 8) | (p[i + 3] << 0);
1146 	return cs;
1147 }
sfs_checksum(uae_u8 * p,int blocksize,int sfs2)1148 static int sfs_checksum (uae_u8 *p, int blocksize, int sfs2)
1149 {
1150 	uae_u32 cs = sfs2 ? 2 : 1;
1151 	int i;
1152 	for (i = 0; i < blocksize; i += 4)
1153 		cs += (p[i] << 24) | (p[i + 1] << 16) | (p[i + 2] << 8) | (p[i + 3] << 0);
1154 	return cs;
1155 }
1156 
getBSTR(uae_u8 * bstr)1157 static TCHAR *getBSTR (uae_u8 *bstr)
1158 {
1159 	int n = *bstr++;
1160 	uae_char buf[257];
1161 	int i;
1162 
1163 	for (i = 0; i < n; i++)
1164 		buf[i] = *bstr++;
1165 	buf[i] = 0;
1166 	return au (buf);
1167 }
1168 
gl(struct adfhandle * adf,int off)1169 static uae_u32 gl (struct adfhandle *adf, int off)
1170 {
1171 	uae_u8 *p = adf->block + off;
1172 	return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
1173 }
glx(uae_u8 * p)1174 static uae_u32 glx (uae_u8 *p)
1175 {
1176 	return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
1177 }
gwx(uae_u8 * p)1178 static uae_u32 gwx (uae_u8 *p)
1179 {
1180 	return (p[0] << 8) | (p[1] << 0);
1181 }
1182 
1183 static const int secs_per_day = 24 * 60 * 60;
1184 static const int diff = (8 * 365 + 2) * (24 * 60 * 60);
1185 static const int diff2 = (-8 * 365 - 2) * (24 * 60 * 60);
1186 
put_time(long days,long mins,long ticks)1187 static time_t put_time (long days, long mins, long ticks)
1188 {
1189 	time_t t;
1190 
1191 	if (days < 0)
1192 		days = 0;
1193 	if (days > 9900 * 365)
1194 		days = 9900 * 365; // in future far enough?
1195 	if (mins < 0 || mins >= 24 * 60)
1196 		mins = 0;
1197 	if (ticks < 0 || ticks >= 60 * 50)
1198 		ticks = 0;
1199 
1200 	t = ticks / 50;
1201 	t += mins * 60;
1202 	t += ((uae_u64)days) * secs_per_day;
1203 	t += diff;
1204 
1205 	return t;
1206 }
1207 
adf_read_block(struct adfhandle * adf,int block)1208 static int adf_read_block (struct adfhandle *adf, int block)
1209 {
1210 	memset (adf->block, 0, adf->blocksize);
1211 	if (block >= adf->highblock || block < 0)
1212 		return 0;
1213 	zfile_fseek (adf->z, block * adf->blocksize, SEEK_SET);
1214 	zfile_fread (adf->block, adf->blocksize, 1, adf->z);
1215 	return 1;
1216 }
1217 
recurseadf(struct znode * zn,int root,TCHAR * name)1218 static void recurseadf (struct znode *zn, int root, TCHAR *name)
1219 {
1220 	int i;
1221 	struct zvolume *zv = zn->volume;
1222 	struct adfhandle *adf = (struct adfhandle*)zv->handle;
1223 	TCHAR name2[MAX_DPATH];
1224 	int bs = adf->blocksize;
1225 
1226 	for (i = 0; i < bs / 4 - 56; i++) {
1227 		int block;
1228 		if (!adf_read_block (adf, root))
1229 			return;
1230 		block = gl (adf, (i + 6) * 4);
1231 		while (block > 0 && block < adf->size / bs) {
1232 			struct zarchive_info zai;
1233 			TCHAR *fname;
1234 			uae_u32 size, secondary;
1235 
1236 			if (!adf_read_block (adf, block))
1237 				return;
1238 			if (gl (adf, 0) != 2)
1239 				break;
1240 			if (gl (adf, 1 * 4) != block)
1241 				break;
1242 			secondary = gl (adf, bs - 1 * 4);
1243 			if (secondary != -3 && secondary != 2)
1244 				break;
1245 			memset (&zai, 0, sizeof zai);
1246 			fname = getBSTR (adf->block + bs - 20 * 4);
1247 			size = gl (adf, bs - 47 * 4);
1248 			name2[0] = 0;
1249 			if (name[0]) {
1250 				TCHAR sep[] = { FSDB_DIR_SEPARATOR, 0 };
1251 				_tcscpy (name2, name);
1252 				_tcscat (name2, sep);
1253 			}
1254 			_tcscat (name2, fname);
1255 			zai.name = name2;
1256 			if (size < 0 || size > 0x7fffffff)
1257 				size = 0;
1258 			zai.size = size;
1259 			zai.flags = gl (adf, bs - 48 * 4);
1260 			amiga_to_timeval (&zai.tv, gl (adf, bs - 23 * 4), gl (adf, bs - 22 * 4),gl (adf, bs - 21 * 4), 50);
1261 			if (secondary == -3) {
1262 				struct znode *znnew = zvolume_addfile_abs (zv, &zai);
1263 				znnew->offset = block;
1264 			} else {
1265 				struct znode *znnew = zvolume_adddir_abs (zv, &zai);
1266 				znnew->offset = block;
1267 				recurseadf (znnew, block, name2);
1268 				if (!adf_read_block (adf, block))
1269 					return;
1270 			}
1271 			xfree (fname);
1272 			block = gl (adf, bs - 4 * 4);
1273 		}
1274 	}
1275 }
1276 
recursesfs(struct znode * zn,int root,TCHAR * name,int sfs2)1277 static void recursesfs (struct znode *zn, int root, TCHAR *name, int sfs2)
1278 {
1279 	struct zvolume *zv = zn->volume;
1280 	struct adfhandle *adf = (struct adfhandle*)zv->handle;
1281 	TCHAR name2[MAX_DPATH];
1282 	int block;
1283 	uae_u8 *p, *s;
1284 	struct zarchive_info zai;
1285 
1286 	block = root;
1287 	while (block) {
1288 		if (!adf_read_block (adf, block))
1289 			return;
1290 		p = adf->block + 12 + 3 * 4;
1291 		while (glx (p + 4) && p < adf->block + adf->blocksize - 27) {
1292 			TCHAR *fname;
1293 			int i;
1294 			int align;
1295 
1296 			memset (&zai, 0, sizeof zai);
1297 			zai.flags = glx (p + 8) ^ 0x0f;
1298 			s = p + (sfs2 ? 27 : 25);
1299 			fname = au ((char*)s);
1300 			i = 0;
1301 			while (*s) {
1302 				s++;
1303 				i++;
1304 			}
1305 			s++;
1306 			i++;
1307 			if (*s)
1308 				zai.comment = au ((char*)s);
1309 			while (*s) {
1310 				s++;
1311 				i++;
1312 			}
1313 			s++;
1314 			i++;
1315 			i += sfs2 ? 27 : 25;
1316 			align = i & 1;
1317 
1318 			name2[0] = 0;
1319 			if (name[0]) {
1320 				TCHAR sep[] = { FSDB_DIR_SEPARATOR, 0 };
1321 				_tcscpy (name2, name);
1322 				_tcscat (name2, sep);
1323 			}
1324 			_tcscat (name2, fname);
1325 			zai.name = name2;
1326 			if (sfs2)
1327 				zai.tv.tv_sec = glx (p + 22) - diff2;
1328 			else
1329 				zai.tv.tv_sec = glx (p + 20) - diff;
1330 			if (p[sfs2 ? 26 : 24] & 0x80) { // dir
1331 				struct znode *znnew = zvolume_adddir_abs (zv, &zai);
1332 				int newblock = glx (p + 16);
1333 				if (newblock) {
1334 					znnew->offset = block;
1335 					recursesfs (znnew, newblock, name2, sfs2);
1336 				}
1337 				if (!adf_read_block (adf, block))
1338 					return;
1339 			} else {
1340 				struct znode *znnew;
1341 				if (sfs2) {
1342 					uae_u64 b1 = p[16];
1343 					uae_u64 b2 = p[17];
1344 					zai.size = (b1 << 40) | (b2 << 32) | glx (p + 18) ;
1345 				} else {
1346 					zai.size = glx (p + 16);
1347 				}
1348 				znnew = zvolume_addfile_abs (zv, &zai);
1349 				znnew->offset = block;
1350 				znnew->offset2 = p - adf->block;
1351 			}
1352 			xfree (zai.comment);
1353 			xfree (fname);
1354 			p += i + align;
1355 		}
1356 		block = gl (adf, 12 + 4);
1357 	}
1358 
1359 }
1360 
archive_directory_adf(struct znode * parent,struct zfile * z)1361 struct zvolume *archive_directory_adf (struct znode *parent, struct zfile *z)
1362 {
1363 	struct zvolume *zv;
1364 	struct adfhandle *adf;
1365 	TCHAR name[MAX_DPATH];
1366 	int gotroot = 0;
1367 
1368 	adf = xcalloc (struct adfhandle, 1);
1369 	zfile_fseek (z, 0, SEEK_END);
1370 	adf->size = zfile_ftell (z);
1371 	zfile_fseek (z, 0, SEEK_SET);
1372 
1373 	adf->blocksize = 512;
1374 	if (parent && parent->offset2) {
1375 		if (parent->offset2 == 1024 || parent->offset2 == 2048 || parent->offset2 == 4096 || parent->offset2 == 8192 ||
1376 			parent->offset2 == 16384 || parent->offset2 == 32768 || parent->offset2 == 65536) {
1377 				adf->blocksize = parent->offset2;
1378 				gotroot = 1;
1379 		}
1380 	}
1381 
1382 	adf->highblock = adf->size / adf->blocksize;
1383 	adf->z = z;
1384 
1385 	if (!adf_read_block (adf, 0))
1386 		goto fail;
1387 	adf->dostype = gl (adf, 0);
1388 
1389 	if ((adf->dostype & 0xffffff00) == MCC('D', 'O', 'S', '\0')) {
1390 		int bs = adf->blocksize;
1391 		int res;
1392 
1393 		adf->rootblock = ((adf->size / bs) - 1 + 2) / 2;
1394 		if (!gotroot) {
1395 			for (res = 2; res >= 1; res--) {
1396 				for (bs = 512; bs < 65536; bs <<= 1) {
1397 					adf->blocksize = bs;
1398 					adf->rootblock = ((adf->size / bs) - 1 + res) / 2;
1399 					if (!adf_read_block (adf, adf->rootblock))
1400 						continue;
1401 					if (gl (adf, 0) != 2 || gl (adf, bs - 1 * 4) != 1)
1402 						continue;
1403 					if (dos_checksum (adf->block, bs) != 0)
1404 						continue;
1405 					gotroot = 1;
1406 					break;
1407 				}
1408 				if (gotroot)
1409 					break;
1410 			}
1411 		}
1412 		if (!gotroot) {
1413 			bs = adf->blocksize = 512;
1414 			if (adf->size < 2000000 && adf->rootblock != 880) {
1415 				adf->rootblock = 880;
1416 				if (!adf_read_block (adf, adf->rootblock))
1417 					goto fail;
1418 				if (gl (adf, 0) != 2 || gl (adf, bs - 1 * 4) != 1)
1419 					goto fail;
1420 				if (dos_checksum (adf->block, bs) != 0)
1421 					goto fail;
1422 			}
1423 		}
1424 
1425 		if (!adf_read_block (adf, adf->rootblock))
1426 			goto fail;
1427 		if (gl (adf, 0) != 2 || gl (adf, bs - 1 * 4) != 1)
1428 			goto fail;
1429 		if (dos_checksum (adf->block, adf->blocksize) != 0)
1430 			goto fail;
1431 		adf->blocksize = bs;
1432 		adf->highblock = adf->size / adf->blocksize;
1433 		zv = zvolume_alloc (z, ArchiveFormatADF, NULL, NULL);
1434 		zv->method = ArchiveFormatADF;
1435 		zv->handle = adf;
1436 		zv->volumename = getBSTR (adf->block + adf->blocksize - 20 * 4);
1437 
1438 		name[0] = 0;
1439 		recurseadf (&zv->root, adf->rootblock, name);
1440 
1441 	} else if ((adf->dostype & 0xffffff00) == MCC('S', 'F', 'S', '\0')) {
1442 
1443 		uae_u16 version, sfs2;
1444 
1445 		for (;;) {
1446 			for (;;) {
1447 				version = gl (adf, 12) >> 16;
1448 				sfs2 = version > 3;
1449 				if (version > 4)
1450 					break;
1451 				adf->rootblock = gl (adf, 104);
1452 				if (!adf_read_block (adf, adf->rootblock))
1453 					break;
1454 				if (gl (adf, 0) != MCC('O', 'B', 'J', 'C'))
1455 					break;
1456 				if (sfs_checksum (adf->block, adf->blocksize, sfs2))
1457 					break;
1458 				adf->rootblock = gl (adf, 40);
1459 				if (!adf_read_block (adf, adf->rootblock))
1460 					break;
1461 				if (gl (adf, 0) != MCC('O', 'B', 'J', 'C'))
1462 					break;
1463 				if (sfs_checksum (adf->block, adf->blocksize, sfs2))
1464 					break;
1465 				gotroot = 1;
1466 				break;
1467 			}
1468 			if (gotroot)
1469 				break;
1470 			adf->blocksize <<= 1;
1471 			if (adf->blocksize == 65536)
1472 				break;
1473 		}
1474 		if (!gotroot)
1475 			goto fail;
1476 
1477 		zv = zvolume_alloc (z, ArchiveFormatADF, NULL, NULL);
1478 		zv->method = ArchiveFormatADF;
1479 		zv->handle = adf;
1480 
1481 		name[0] = 0;
1482 		recursesfs (&zv->root, adf->rootblock, name, version > 3);
1483 
1484 	} else {
1485 		goto fail;
1486 	}
1487 
1488 	return zv;
1489 fail:
1490 	xfree (adf);
1491 	return NULL;
1492 }
1493 
1494 struct sfsblock
1495 {
1496 	int block;
1497 	int length;
1498 };
1499 
sfsfindblock(struct adfhandle * adf,int btree,int theblock,struct sfsblock ** sfsb,int * sfsblockcnt,int * sfsmaxblockcnt,int sfs2)1500 static int sfsfindblock (struct adfhandle *adf, int btree, int theblock, struct sfsblock **sfsb, int *sfsblockcnt, int *sfsmaxblockcnt, int sfs2)
1501 {
1502 	int nodecount, isleaf, nodesize;
1503 	int i;
1504 	uae_u8 *p;
1505 
1506 	if (!btree)
1507 		return 0;
1508 	if (!adf_read_block (adf, btree))
1509 		return 0;
1510 	if (memcmp (adf->block, "BNDC", 4))
1511 		return 0;
1512 	nodecount = gwx (adf->block + 12);
1513 	isleaf = adf->block[14];
1514 	nodesize = adf->block[15];
1515 	p = adf->block + 16;
1516 	for (i = 0; i < nodecount; i++) {
1517 		if (isleaf) {
1518 			uae_u32 key = glx (p);
1519 			uae_u32 next = glx (p + 4);
1520 			uae_u32 prev = glx (p + 8);
1521 			uae_u32 blocks;
1522 			if (sfs2)
1523 				blocks = glx (p + 12);
1524 			else
1525 				blocks = gwx (p + 12);
1526 			if (key == theblock) {
1527 				struct sfsblock *sb;
1528 				if (*sfsblockcnt >= *sfsmaxblockcnt) {
1529 					*sfsmaxblockcnt += 100;
1530 					*sfsb = xrealloc (struct sfsblock, *sfsb, *sfsmaxblockcnt);
1531 				}
1532 				sb = *sfsb + (*sfsblockcnt);
1533 				sb->block = key;
1534 				sb->length = blocks;
1535 				(*sfsblockcnt)++;
1536 				return next;
1537 			}
1538 		} else {
1539 			uae_u32 key = glx (p);
1540 			uae_u32 data = glx (p + 4);
1541 			int newblock = sfsfindblock (adf, data, theblock, sfsb, sfsblockcnt, sfsmaxblockcnt, sfs2);
1542 			if (newblock)
1543 				return newblock;
1544 			if (!adf_read_block (adf, btree))
1545 				return 0;
1546 			if (memcmp (adf->block, "BNDC", 4))
1547 				return 0;
1548 		}
1549 		p += nodesize;
1550 	}
1551 	return 0;
1552 }
1553 
1554 
archive_access_adf(struct znode * zn)1555 static struct zfile *archive_access_adf (struct znode *zn)
1556 {
1557 	struct zfile *z = NULL;
1558 	int root, ffs;
1559 	struct adfhandle *adf = (struct adfhandle*)zn->volume->handle;
1560 	uae_s64 size;
1561 	int i, bs;
1562 	uae_u8 *dst;
1563 
1564 	size = zn->size;
1565 	bs = adf->blocksize;
1566 	z = zfile_fopen_empty (zn->volume->archive, zn->fullname, size);
1567 	if (!z)
1568 		return NULL;
1569 
1570 	if ((adf->dostype & 0xffffff00) == MCC('D', 'O', 'S', '\0')) {
1571 
1572 		ffs = adf->dostype & 1;
1573 		root = zn->offset;
1574 		dst = z->data;
1575 		for (;;) {
1576 			adf_read_block (adf, root);
1577 			for (i = bs / 4 - 51; i >= 6; i--) {
1578 				uae_s64 bsize = ffs ? bs : bs - 24;
1579 				int block = gl (adf, i * 4);
1580 				if (size < bsize)
1581 					bsize = size;
1582 				if (ffs)
1583 					zfile_fseek (adf->z, block * adf->blocksize, SEEK_SET);
1584 				else
1585 					zfile_fseek (adf->z, block * adf->blocksize + 24, SEEK_SET);
1586 				zfile_fread (dst, bsize, 1, adf->z);
1587 				size -= bsize;
1588 				dst += bsize;
1589 				if (size <= 0)
1590 					break;
1591 			}
1592 			if (size <= 0)
1593 				break;
1594 			root = gl (adf, bs - 2 * 4);
1595 		}
1596 	} else if ((adf->dostype & 0xffffff00) == MCC('S', 'F', 'S', '\0')) {
1597 
1598 		struct sfsblock *sfsblocks;
1599 		int sfsblockcnt, sfsmaxblockcnt, i;
1600 		uae_s64 bsize;
1601 		int block = zn->offset;
1602 		int dblock;
1603 		int btree, version, sfs2;
1604 		uae_u8 *p;
1605 
1606 		if (!adf_read_block (adf, 0))
1607 			goto end;
1608 		btree = glx (adf->block + 108);
1609 		version = gwx (adf->block + 12);
1610 		sfs2 = version > 3;
1611 
1612 		if (!adf_read_block (adf, block))
1613 			goto end;
1614 		p = adf->block + zn->offset2;
1615 		dblock = glx (p + 12);
1616 
1617 		sfsblockcnt = 0;
1618 		sfsmaxblockcnt = 0;
1619 		sfsblocks = NULL;
1620 		if (size > 0) {
1621 			int nextblock = dblock;
1622 			while (nextblock) {
1623 				nextblock = sfsfindblock (adf, btree, nextblock, &sfsblocks, &sfsblockcnt, &sfsmaxblockcnt, sfs2);
1624 			}
1625 		}
1626 
1627 		bsize = 0;
1628 		for (i = 0; i < sfsblockcnt; i++)
1629 			bsize += sfsblocks[i].length * adf->blocksize;
1630 		if (bsize < size)
1631 			write_log (_T("SFS extracting error, %s size mismatch %lld<%lld\n"), z->name, bsize, size);
1632 
1633 		dst = z->data;
1634 		block = zn->offset;
1635 		for (i = 0; i < sfsblockcnt; i++) {
1636 			block = sfsblocks[i].block;
1637 			bsize = sfsblocks[i].length * adf->blocksize;
1638 			zfile_fseek (adf->z, block * adf->blocksize, SEEK_SET);
1639 			if (bsize > size)
1640 				bsize = size;
1641 			zfile_fread (dst, bsize, 1, adf->z);
1642 			dst += bsize;
1643 			size -= bsize;
1644 		}
1645 
1646 		xfree (sfsblocks);
1647 	}
1648 	return z;
1649 end:
1650 	zfile_fclose (z);
1651 	return NULL;
1652 }
1653 
archive_close_adf(void * v)1654 static void archive_close_adf (void *v)
1655 {
1656 	struct adfhandle *adf = (struct adfhandle*)v;
1657 	xfree (adf);
1658 }
1659 
rl(uae_u8 * p)1660 static int rl (uae_u8 *p)
1661 {
1662 	return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
1663 }
tochar(uae_u8 * s,int len)1664 static TCHAR *tochar (uae_u8 *s, int len)
1665 {
1666 	int i, j;
1667 	uae_char tmp[256];
1668 	j = 0;
1669 	for (i = 0; i < len; i++) {
1670 		uae_char c = *s++;
1671 		if (c >= 0 && c <= 9) {
1672 			tmp[j++] = FSDB_DIR_SEPARATOR;
1673 			tmp[j++] = '0' + c;
1674 		} else if (c < ' ' || c > 'z') {
1675 			tmp[j++] = '.';
1676 		} else {
1677 			tmp[j++] = c;
1678 		}
1679 		tmp[j] = 0;
1680 	}
1681 	return au (tmp);
1682 }
1683 
archive_directory_rdb(struct zfile * z)1684 struct zvolume *archive_directory_rdb (struct zfile *z)
1685 {
1686 	uae_u8 buf[512] = { 0 };
1687 	int partnum, bs;
1688 	TCHAR *devname;
1689 	struct zvolume *zv;
1690 	struct zarchive_info zai;
1691 	uae_u8 *p;
1692 	struct znode *zn;
1693 
1694 	zv = zvolume_alloc (z, ArchiveFormatRDB, NULL, NULL);
1695 
1696 	zfile_fseek (z, 0, SEEK_SET);
1697 	zfile_fread (buf, 1, 512, z);
1698 
1699 	partnum = 0;
1700 	for (;;) {
1701 		int partblock;
1702 		TCHAR tmp[MAX_DPATH];
1703 		int surf, spt, spb, lowcyl, highcyl, reserved;
1704 		int size, block, blocksize, rootblock;
1705 		TCHAR comment[81], *dos;
1706 
1707 		if (partnum == 0)
1708 			partblock = rl (buf + 28);
1709 		else
1710 			partblock = rl (buf + 4 * 4);
1711 		partnum++;
1712 		if (partblock <= 0)
1713 			break;
1714 		zfile_fseek (z, partblock * 512, SEEK_SET);
1715 		zfile_fread (buf, 1, 512, z);
1716 		if (memcmp (buf, "PART", 4))
1717 			break;
1718 
1719 		p = buf + 128 - 16;
1720 		surf = rl (p + 28);
1721 		spb = rl (p + 32);
1722 		spt = rl (p + 36);
1723 		reserved = rl (p + 40);
1724 		lowcyl = rl (p + 52);
1725 		highcyl = rl (p + 56);
1726 		blocksize = rl (p + 20) * 4 * spb;
1727 		block = lowcyl * surf * spt;
1728 
1729 		size = (highcyl - lowcyl + 1) * surf * spt;
1730 		size *= blocksize;
1731 
1732 		dos = tochar (buf + 192, 4);
1733 
1734 		if (!memcmp (dos, _T("DOS"), 3))
1735 			rootblock = ((size / blocksize) - 1 + 2) / 2;
1736 		else
1737 			rootblock = 0;
1738 
1739 		devname = getBSTR (buf + 36);
1740 		_stprintf (tmp, _T("%s.hdf"), devname);
1741 		memset (&zai, 0, sizeof zai);
1742 		_stprintf (comment, _T("FS=%s LO=%d HI=%d HEADS=%d SPT=%d RES=%d BLOCK=%d ROOT=%d"),
1743 			dos, lowcyl, highcyl, surf, spt, reserved, blocksize, rootblock);
1744 		zai.comment = comment;
1745 		xfree (dos);
1746 		zai.name = tmp;
1747 		zai.size = size;
1748 		zai.flags = -1;
1749 		zn = zvolume_addfile_abs (zv, &zai);
1750 		zn->offset = partblock;
1751 		zn->offset2 = blocksize; // abuse of offset2..
1752 	}
1753 
1754 	zfile_fseek (z, 0, SEEK_SET);
1755 	p = buf;
1756 	zfile_fread (buf, 1, 512, z);
1757 	zai.name = my_strdup(_T("rdb_dump.dat"));
1758 	bs = rl (p + 16);
1759 	zai.size = rl (p + 140) * bs;
1760 	zai.comment = NULL;
1761 	zn = zvolume_addfile_abs (zv, &zai);
1762 	zn->offset = 0;
1763 
1764 	zv->method = ArchiveFormatRDB;
1765 	return zv;
1766 }
1767 
archive_access_rdb(struct znode * zn)1768 static struct zfile *archive_access_rdb (struct znode *zn)
1769 {
1770 	struct zfile *z = zn->volume->archive;
1771 	struct zfile *zf;
1772 	uae_u8 buf[512] = { 0 };
1773 	int surf, spb, spt, lowcyl, highcyl;
1774 	int block, blocksize;
1775 	uae_s64 size;
1776 	uae_u8 *p;
1777 
1778 	if (zn->offset) {
1779 		zfile_fseek (z, zn->offset * 512, SEEK_SET);
1780 		zfile_fread (buf, 1, 512, z);
1781 
1782 		p = buf + 128 - 16;
1783 		surf = rl (p + 28);
1784 		spb = rl (p + 32);
1785 		spt = rl (p + 36);
1786 		lowcyl = rl (p + 52);
1787 		highcyl = rl (p + 56);
1788 		blocksize = rl (p + 20) * 4;
1789 		block = lowcyl * surf * spt;
1790 
1791 		size = (highcyl - lowcyl + 1) * surf * spt;
1792 		size *= blocksize;
1793 	} else {
1794 		zfile_fseek (z, 0, SEEK_SET);
1795 		zfile_fread (buf, 1, 512, z);
1796 		p = buf;
1797 		blocksize = rl (p + 16);
1798 		block = 0;
1799 		size = zn->size;
1800 	}
1801 
1802 	zf = zfile_fopen_parent (z, zn->fullname, block * blocksize, size);
1803 	return zf;
1804 }
1805 
isfat(uae_u8 * p)1806 int isfat (uae_u8 *p)
1807 {
1808 	int i, b;
1809 
1810 	if ((p[0x15] & 0xf0) != 0xf0)
1811 		return 0;
1812 	if (p[0x0b] != 0x00 || p[0x0c] != 0x02)
1813 		return 0;
1814 	b = 0;
1815 	for (i = 0; i < 8; i++) {
1816 		if (p[0x0d] & (1 << i))
1817 			b++;
1818 	}
1819 	if (b != 1)
1820 		return 0;
1821 	if (p[0x0f] != 0)
1822 		return 0;
1823 	if (p[0x0e] > 8 || p[0x0e] == 0)
1824 		return 0;
1825 	if (p[0x10] == 0 || p[0x10] > 8)
1826 		return 0;
1827 	b = (p[0x12] << 8) | p[0x11];
1828 	if (b > 8192 || b <= 0)
1829 		return 0;
1830 	b = p[0x16] | (p[0x17] << 8);
1831 	if (b == 0 || b > 8192)
1832 		return 0;
1833 	return 1;
1834 }
1835 
1836 /*
1837 * The epoch of FAT timestamp is 1980.
1838 *     :  bits :     value
1839 * date:  0 -  4: day   (1 -  31)
1840 * date:  5 -  8: month (1 -  12)
1841 * date:  9 - 15: year  (0 - 127) from 1980
1842 * time:  0 -  4: sec   (0 -  29) 2sec counts
1843 * time:  5 - 10: min   (0 -  59)
1844 * time: 11 - 15: hour  (0 -  23)
1845 */
1846 #define SECS_PER_MIN    60
1847 #define SECS_PER_HOUR   (60 * 60)
1848 #define SECS_PER_DAY    (SECS_PER_HOUR * 24)
1849 #define UNIX_SECS_1980  315532800L
1850 #if BITS_PER_LONG == 64
1851 #define UNIX_SECS_2108  4354819200L
1852 #endif
1853 /* days between 1.1.70 and 1.1.80 (2 leap days) */
1854 #define DAYS_DELTA      (365 * 10 + 2)
1855 /* 120 (2100 - 1980) isn't leap year */
1856 #define YEAR_2100       120
1857 #define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100)
1858 
1859 /* Linear day numbers of the respective 1sts in non-leap years. */
1860 static time_t days_in_year[] = {
1861 	/* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
1862 	0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
1863 };
1864 
1865 /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
fat_time_fat2unix(uae_u16 time,uae_u16 date,int fat12)1866 static time_t fat_time_fat2unix (uae_u16 time, uae_u16 date, int fat12)
1867 {
1868 	time_t second, day, leap_day, month, year;
1869 
1870 	if (0 && fat12) {
1871 		year = date & 0x7f;
1872 		month = (date >> 7) & 0x0f;
1873 		day = (date >> 11);
1874 	} else {
1875 		year  = date >> 9;
1876 		month = max(1, (date >> 5) & 0xf);
1877 		day   = max(1, date & 0x1f) - 1;
1878 	}
1879 
1880 	leap_day = (year + 3) / 4;
1881 	if (year > YEAR_2100)           /* 2100 isn't leap year */
1882 		leap_day--;
1883 	if (IS_LEAP_YEAR(year) && month > 2)
1884 		leap_day++;
1885 
1886 	second =  (time & 0x1f) << 1;
1887 	second += ((time >> 5) & 0x3f) * SECS_PER_MIN;
1888 	second += (time >> 11) * SECS_PER_HOUR;
1889 	second += (year * 365 + leap_day
1890 		+ days_in_year[month] + day
1891 		+ DAYS_DELTA) * SECS_PER_DAY;
1892 	return second;
1893 }
1894 
getcluster(struct zfile * z,int cluster,int fatstart,int fatbits)1895 static int getcluster (struct zfile *z, int cluster, int fatstart, int fatbits)
1896 {
1897 	uae_u32 fat = 0;
1898 	uae_u8 p[4];
1899 	int offset = cluster * fatbits;
1900 	zfile_fseek (z, fatstart * 512 + offset / 8, SEEK_SET);
1901 	if (fatbits == 12) {
1902 		zfile_fread (p, 2, 1, z);
1903 		if ((offset & 4))
1904 			fat = ((p[0] & 0xf0) >> 4) | (p[1] << 4);
1905 		else
1906 			fat = (p[0]) | ((p[1] & 0x0f) << 8);
1907 		if (fat >= 0xff0)
1908 			return -1;
1909 	} else if (fatbits == 16) {
1910 		zfile_fread (p, 2, 1, z);
1911 		fat = p[0] | (p[1] << 8);
1912 		if (fat >= 0xfff0)
1913 			return -1;
1914 	} else if (fatbits == 32) {
1915 		zfile_fread (p, 4, 1, z);
1916 		fat = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
1917 		fat &= ~0x0fffffff;
1918 		if (fat >= 0x0ffffff0)
1919 			return -1;
1920 	}
1921 	return fat;
1922 }
1923 
fatdirectory(struct zfile * z,struct zvolume * zv,const TCHAR * name,int startblock,int entries,int sectorspercluster,int fatstart,int dataregion,int fatbits)1924 static void fatdirectory (struct zfile *z, struct zvolume *zv, const TCHAR *name, int startblock, int entries, int sectorspercluster, int fatstart, int dataregion, int fatbits)
1925 {
1926 	struct zarchive_info zai;
1927 	struct znode *znnew;
1928 	int i, j;
1929 
1930 	for (i = 0; i < entries; i++) {
1931 		TCHAR name2[MAX_DPATH], *fname;
1932 		uae_s64 size;
1933 		uae_u8 fatname[16];
1934 		uae_u8 buf[32];
1935 		int attr, cnt, ext;
1936 		int startcluster;
1937 
1938 		memset (buf, 0, sizeof buf);
1939 		memset (&zai, 0, sizeof zai);
1940 		zfile_fseek (z, startblock * 512 + i * 32, SEEK_SET);
1941 		zfile_fread (buf, 32, 1, z);
1942 		if (buf[0] == 0)
1943 			break;
1944 		if (buf[0] == 0xe5)
1945 			continue;
1946 		if (buf[0] == 0x05)
1947 			buf[0] = 0xe5;
1948 		size = buf[0x1c] | (buf[0x1d] << 8) | (buf[0x1e] << 16) | (buf[0x1f] << 24);
1949 		attr = buf[0x0b];
1950 		startcluster = buf[0x1a] | (buf[0x1b] << 8);
1951 		if ((attr & (0x4 | 0x2)) == 0x06) // system+hidden
1952 			continue;
1953 		if (attr & 8) // disk name
1954 			continue;
1955 		if (attr & 1) // read-only
1956 			zai.flags |= 1 << 3;
1957 		if (!(attr & 32)) // archive
1958 			zai.flags |= 1 << 4;
1959 
1960 		cnt = 0;
1961 		ext = 0;
1962 		for (j = 0; j < 8 && buf[j] != 0x20 && buf[j] != 0; j++)
1963 			fatname[cnt++] = buf[j];
1964 		for (j = 0; j < 3 && buf[8 + j] != 0x20 && buf[8 + j] != 0; j++) {
1965 			if (ext == 0)
1966 				fatname[cnt++] = '.';
1967 			ext = 1;
1968 			fatname[cnt++] = buf[8 + j];
1969 		}
1970 		fatname[cnt] = 0;
1971 
1972 		fname = au ((char*)fatname);
1973 		name2[0] = 0;
1974 		if (name[0]) {
1975 			TCHAR sep[] = { FSDB_DIR_SEPARATOR, 0 };
1976 			_tcscpy (name2, name);
1977 			_tcscat (name2, sep);
1978 		}
1979 		_tcscat (name2, fname);
1980 
1981 		zai.name = name2;
1982 		zai.tv.tv_sec = fat_time_fat2unix (buf[0x16] | (buf[0x17] << 8), buf[0x18] | (buf[0x19] << 8), 1);
1983 		if (attr & (16 | 8)) {
1984 			int nextblock, cluster;
1985 			nextblock = dataregion + (startcluster - 2) * sectorspercluster;
1986 			cluster = getcluster (z, startcluster, fatstart, fatbits);
1987 			if ((cluster < 0 || cluster >= 3) && nextblock != startblock) {
1988 				znnew = zvolume_adddir_abs (zv, &zai);
1989 				fatdirectory (z, zv, name2, nextblock, sectorspercluster * 512 / 32, sectorspercluster, fatstart, dataregion, fatbits);
1990 				while (cluster >= 3) {
1991 					nextblock = dataregion + (cluster - 2) * sectorspercluster;
1992 					fatdirectory (z, zv, name2, nextblock, sectorspercluster * 512 / 32, sectorspercluster, fatstart, dataregion, fatbits);
1993 					cluster = getcluster (z, cluster, fatstart, fatbits);
1994 				}
1995 			}
1996 		} else {
1997 			zai.size = size;
1998 			znnew = zvolume_addfile_abs (zv, &zai);
1999 			znnew->offset = startcluster;
2000 		}
2001 
2002 		xfree (fname);
2003 	}
2004 }
2005 
archive_directory_fat(struct zfile * z)2006 struct zvolume *archive_directory_fat (struct zfile *z)
2007 {
2008 	uae_u8 buf[512] = { 0 };
2009 	int fatbits = 12;
2010 	struct zvolume *zv;
2011 	int rootdir, reserved, sectorspercluster;
2012 	int numfats, sectorsperfat, rootentries;
2013 	int dataregion;
2014 
2015 	zfile_fseek (z, 0, SEEK_SET);
2016 	zfile_fread (buf, 1, 512, z);
2017 
2018 	if (!isfat (buf))
2019 		return NULL;
2020 	reserved = buf[0x0e] | (buf[0x0f] << 8);
2021 	numfats = buf[0x10];
2022 	sectorsperfat = buf[0x16] | (buf[0x17] << 8);
2023 	rootentries = buf[0x11] | (buf[0x12] << 8);
2024 	sectorspercluster = buf[0x0d];
2025 	rootdir = reserved + numfats * sectorsperfat;
2026 	dataregion = rootdir + rootentries * 32 / 512;
2027 
2028 	zv = zvolume_alloc (z, ArchiveFormatFAT, NULL, NULL);
2029 	fatdirectory (z, zv, _T(""), rootdir, rootentries, sectorspercluster, reserved, dataregion, fatbits);
2030 	zv->method = ArchiveFormatFAT;
2031 	return zv;
2032 }
2033 
archive_access_fat(struct znode * zn)2034 static struct zfile *archive_access_fat (struct znode *zn)
2035 {
2036 	uae_u8 buf[512] = { 0 };
2037 	int fatbits = 12;
2038 	uae_s64 size = zn->size;
2039 	struct zfile *sz, *dz;
2040 	int rootdir, reserved, sectorspercluster;
2041 	int numfats, sectorsperfat, rootentries;
2042 	int dataregion, cluster;
2043 	uae_s64 offset;
2044 
2045 	sz = zn->volume->archive;
2046 
2047 	zfile_fseek (sz, 0, SEEK_SET);
2048 	zfile_fread (buf, 1, 512, sz);
2049 
2050 	if (!isfat (buf))
2051 		return NULL;
2052 	reserved = buf[0x0e] | (buf[0x0f] << 8);
2053 	numfats = buf[0x10];
2054 	sectorsperfat = buf[0x16] | (buf[0x17] << 8);
2055 	rootentries = buf[0x11] | (buf[0x12] << 8);
2056 	sectorspercluster = buf[0x0d];
2057 	rootdir = reserved + numfats * sectorsperfat;
2058 	dataregion = rootdir + rootentries * 32 / 512;
2059 
2060 	dz = zfile_fopen_empty (sz, zn->fullname, size);
2061 	if (!dz)
2062 		return NULL;
2063 
2064 	offset = 0;
2065 	cluster = zn->offset;
2066 	while (size && cluster >= 2) {
2067 		uae_s64 left = size > sectorspercluster * 512 ? sectorspercluster * 512 : size;
2068 		int sector = dataregion + (cluster - 2) * sectorspercluster;
2069 		zfile_fseek (sz, sector * 512, SEEK_SET);
2070 		zfile_fread (dz->data + offset, 1, left, sz);
2071 		size -= left;
2072 		offset += left;
2073 		cluster = getcluster (sz, cluster, reserved, fatbits);
2074 	}
2075 
2076 	return dz;
2077 }
2078 
archive_access_close(void * handle,unsigned int id)2079 void archive_access_close (void *handle, unsigned int id)
2080 {
2081 	switch (id)
2082 	{
2083 #ifdef A_ZIP
2084 	case ArchiveFormatZIP:
2085 		archive_close_zip (handle);
2086 		break;
2087 #endif
2088 #ifdef A_7Z
2089 	case ArchiveFormat7Zip:
2090 		archive_close_7z (handle);
2091 		break;
2092 #endif
2093 #ifdef A_RAR
2094 	case ArchiveFormatRAR:
2095 		archive_close_rar (handle);
2096 		break;
2097 #endif
2098 #ifdef A_LHA
2099 	case ArchiveFormatLHA:
2100 		break;
2101 #endif
2102 	case ArchiveFormatADF:
2103 		archive_close_adf (handle);
2104 		break;
2105 	case ArchiveFormatTAR:
2106 		archive_close_tar (handle);
2107 		break;
2108 	}
2109 }
2110 
archive_access_dir(struct znode * zn)2111 static struct zfile *archive_access_dir (struct znode *zn)
2112 {
2113 	return zfile_fopen (zn->fullname, _T("rb"), 0);
2114 }
2115 
2116 
archive_unpackzfile(struct zfile * zf)2117 struct zfile *archive_unpackzfile (struct zfile *zf)
2118 {
2119 	struct zfile *zout = NULL;
2120 	if (!zf->archiveparent)
2121 		return NULL;
2122 	unpack_log (_T("delayed unpack '%s'\n"), zf->name);
2123 	zf->datasize = zf->size;
2124 	switch (zf->archiveid)
2125 	{
2126 #ifdef A_ZIP
2127 	case ArchiveFormatZIP:
2128 		zout = archive_unpack_zip (zf);
2129 		break;
2130 #endif
2131 	}
2132 	zfile_fclose (zf->archiveparent);
2133 	zf->archiveparent = NULL;
2134 	zf->archiveid = 0;
2135 	return NULL;
2136 }
2137 
archive_getzfile(struct znode * zn,unsigned int id,int flags)2138 struct zfile *archive_getzfile (struct znode *zn, unsigned int id, int flags)
2139 {
2140 	struct zfile *zf = NULL;
2141 
2142 	switch (id)
2143 	{
2144 #ifdef A_ZIP
2145 	case ArchiveFormatZIP:
2146 		zf = archive_access_zip (zn, flags);
2147 		break;
2148 #endif
2149 #ifdef A_7Z
2150 	case ArchiveFormat7Zip:
2151 		zf = archive_access_7z (zn);
2152 		break;
2153 #endif
2154 #ifdef A_RAR
2155 	case ArchiveFormatRAR:
2156 		zf = archive_access_rar (zn);
2157 		break;
2158 #endif
2159 #ifdef A_LHA
2160 	case ArchiveFormatLHA:
2161 		zf = archive_access_lha (zn);
2162 		break;
2163 #endif
2164 #ifdef A_LZX
2165 	case ArchiveFormatLZX:
2166 		zf = archive_access_lzx (zn);
2167 		break;
2168 #endif
2169 	case ArchiveFormatPLAIN:
2170 		zf = archive_access_plain (zn);
2171 		break;
2172 	case ArchiveFormatADF:
2173 		zf = archive_access_adf (zn);
2174 		break;
2175 	case ArchiveFormatRDB:
2176 		zf = archive_access_rdb (zn);
2177 		break;
2178 	case ArchiveFormatFAT:
2179 		zf = archive_access_fat (zn);
2180 		break;
2181 	case ArchiveFormatDIR:
2182 		zf = archive_access_dir (zn);
2183 		break;
2184 	case ArchiveFormatTAR:
2185 		zf = archive_access_tar (zn);
2186 		break;
2187 	}
2188 	if (zf) {
2189 		zf->archiveid = id;
2190 		zfile_fseek (zf, 0, SEEK_SET);
2191 	}
2192 	return zf;
2193 }
2194