bz2_au.library -> bz2.library
[AROS.git] / workbench / devs / diskimage / plugins / dmg / dmg.c
blob0c66e9032fab779c94cc331b281909f68d514202
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #define USED_PLUGIN_API_VERSION 8
28 #include <devices/diskimage.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/utility.h>
33 #ifdef __AROS__
34 # include <expat.h>
35 # include <zlib.h>
36 # include <bzlib.h>
37 # define Uncompress uncompress
38 #else
39 # include <libraries/expat.h>
40 # include <libraries/z.h>
41 # include <libraries/bz2.h>
42 # include <proto/expat.h>
43 # include <proto/z.h>
44 # include <proto/bz2.h>
45 #endif
47 #include "endian.h"
48 #include "base64.h"
49 #include "adc.h"
50 #include "device_locale.h"
51 #include <string.h>
52 #include <SDI_compiler.h>
53 #include "rev/diskimage.device_rev.h"
55 PLUGIN_VERSTAG("DMG")
57 extern struct DiskImagePlugin dmg_plugin;
59 PLUGIN_TABLE(&dmg_plugin)
61 struct DMGPart {
62 ULONG type;
63 ULONG in_offs;
64 ULONG in_size;
65 ULONG out_size;
68 struct DMGHash {
69 struct MinNode *pnode;
70 struct DMGPart *part;
71 UQUAD offset;
74 #define HASH_FUNC 20
76 struct DMGImage {
77 BPTR file;
78 BYTE uses_adc;
79 BYTE uses_zlib;
80 BYTE uses_bzlib;
81 struct List *plist;
82 struct DMGHash *hash;
83 UBYTE *in_buf, *out_buf;
84 ULONG in_size, out_size;
85 struct DMGPart *part_in_buf;
86 ULONG block_size;
87 ULONG total_blocks;
88 UQUAD total_bytes;
89 struct Library *expatbase;
90 struct Library *zbase;
91 struct Library *bz2base;
94 BOOL DMG_Init (struct DiskImagePlugin *Self, const struct PluginData *data);
95 BOOL DMG_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
96 const UBYTE *test, LONG testsize);
97 APTR DMG_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name);
98 void DMG_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr);
99 LONG DMG_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg);
100 LONG DMG_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io);
102 struct DiskImagePlugin dmg_plugin = {
103 PLUGIN_NODE(0, "DMG"),
104 PLUGIN_FLAG_FOOTER|PLUGIN_FLAG_M68K,
105 512,
106 ZERO,
107 NULL,
108 DMG_Init,
109 NULL,
110 DMG_CheckImage,
111 DMG_OpenImage,
112 DMG_CloseImage,
113 DMG_Geometry,
114 DMG_Read,
115 NULL,
116 NULL,
117 NULL,
118 NULL,
119 NULL
122 struct Library *SysBase;
123 struct Library *DOSBase;
124 static struct DIPluginIFace *IPlugin;
125 #ifndef __AROS__
126 #define ZBase image->zbase
127 #define BZ2Base image->bz2base
128 #else
129 struct Library *BZ2Base;
130 struct Library *ZBase;
131 struct Library *ExpatBase;
132 #endif
134 BOOL DMG_Init (struct DiskImagePlugin *Self, const struct PluginData *data) {
135 SysBase = data->SysBase;
136 DOSBase = data->DOSBase;
137 IPlugin = data->IPlugin;
138 return TRUE;
141 #define ID_koly MAKE_ID('k','o','l','y')
142 #define ID_mish MAKE_ID('m','i','s','h')
144 BOOL DMG_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
145 const UBYTE *test, LONG testsize)
147 return testsize >= 512 && rbe32(&test[testsize-512]) == ID_koly;
150 #pragma pack(1)
152 typedef struct {
153 ULONG id;
154 ULONG version;
155 ULONG header_size;
156 ULONG flags;
157 UQUAD running_data_fork_offset;
158 UQUAD data_fork_offset;
159 UQUAD data_fork_length;
160 UQUAD rsrc_fork_offset;
161 UQUAD rsrc_fork_length;
162 ULONG segment_number;
163 ULONG segment_count;
164 ULONG segment_id1;
165 ULONG segment_id2;
166 ULONG segment_id3;
167 ULONG segment_id4;
168 ULONG data_fork_checksum_type;
169 ULONG reserved1;
170 ULONG data_fork_checksum;
171 ULONG reserved2[31];
172 UQUAD xml_offset;
173 UQUAD xml_length;
174 ULONG reserved3[30];
175 ULONG master_checksum_type;
176 ULONG reserved4;
177 ULONG master_checksum;
178 ULONG reserved5[31];
179 ULONG image_variant;
180 UQUAD sector_count;
181 ULONG reserved6[3];
182 } dmg_koly_t;
184 typedef struct {
185 ULONG id;
186 ULONG version;
187 UQUAD first_sector;
188 UQUAD sector_count;
189 UQUAD data_start;
190 ULONG decompressed_buffer_size;
191 ULONG blocks_descriptor;
192 ULONG reserved1[6];
193 ULONG checksum_type;
194 ULONG reserved2;
195 ULONG checksum;
196 ULONG reserved3[31];
197 ULONG blocks_run_count;
198 } dmg_mish_t;
200 #define PT_ZERO 0x00000000
201 #define PT_COPY 0x00000001
202 #define PT_IGNORE 0x00000002
203 #define PT_COMMENT 0x7ffffffe
204 #define PT_ADC 0x80000004
205 #define PT_ZLIB 0x80000005
206 #define PT_BZLIB 0x80000006
207 #define PT_END 0xffffffff
209 #pragma pack()
211 typedef struct {
212 struct Library *expatbase;
213 XML_Parser parser;
214 struct DMGImage *image;
215 LONG current_tag_depth;
216 BYTE is_in_data_tag;
217 STRPTR data;
218 LONG len, size;
219 LONG error;
220 LONG error_string;
221 IPTR error_args[4];
222 } XML_Parser_Data;
224 static LONG add_to_plist (struct DMGImage *image, CONST_STRPTR src, LONG len);
226 static void xml_start_element_handler (void *user_data,
227 const char *name, const char **attrs);
228 static void xml_end_element_handler (void *user_data,
229 const char *name);
230 static void xml_character_data_handler (void *user_data,
231 const char *s, int len);
233 APTR DMG_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file,
234 CONST_STRPTR name)
236 LONG done = FALSE;
237 LONG error = NO_ERROR;
238 LONG error_string = NO_ERROR_STRING;
239 IPTR error_args[4] = {0};
240 dmg_koly_t *koly = NULL;
241 STRPTR data = NULL;
242 struct DMGImage *image = NULL;
243 struct MinNode *pnode;
244 struct DMGPart *part;
245 ULONG type;
246 ULONG hash_size;
247 struct DMGHash *hash;
248 UQUAD offset, next_offset;
249 UQUAD hash_offset;
251 koly = AllocVec(sizeof(*koly), MEMF_ANY);
252 if (!koly) {
253 error = ERROR_NO_FREE_STORE;
254 goto error;
257 if (!ChangeFilePosition(file, -(int)sizeof(*koly), OFFSET_END) ||
258 Read(file, koly, sizeof(*koly)) != sizeof(*koly))
260 error = IoErr();
261 goto error;
264 if (rbe32(&koly->id) != ID_koly) {
265 error = ERROR_OBJECT_WRONG_TYPE;
266 goto error;
269 image = AllocVec(sizeof(*image), MEMF_CLEAR);
270 if (!image) {
271 error = ERROR_NO_FREE_STORE;
272 goto error;
274 image->file = file;
276 image->plist = AllocVec(sizeof(struct MinList), MEMF_ANY);
277 if (!image->plist) {
278 error = ERROR_NO_FREE_STORE;
279 goto error;
281 image->plist->lh_Head = (struct Node *)&image->plist->lh_Tail;
282 image->plist->lh_Tail = NULL;
283 image->plist->lh_TailPred = (struct Node *)&image->plist->lh_Head;
285 if (koly->xml_offset && koly->xml_length) {
286 UQUAD xml_offset;
287 ULONG xml_length;
288 XML_Parser parser;
289 XML_Parser_Data parser_data;
290 int xml_error;
291 #ifndef __AROS__
292 struct Library *ExpatBase;
293 #endif
295 xml_offset = rbe64(&koly->xml_offset);
296 xml_length = rbe64(&koly->xml_length);
298 data = AllocVec(xml_length, MEMF_ANY);
299 if (!data) {
300 error = ERROR_NO_FREE_STORE;
301 goto error;
304 if (!ChangeFilePosition(file, xml_offset, OFFSET_BEGINNING) ||
305 Read(file, data, xml_length) != xml_length)
307 error = IoErr();
308 goto error;
311 image->expatbase = OpenLibrary("expat.library", 4);
312 if (!image->expatbase) {
313 error = ERROR_OBJECT_NOT_FOUND;
314 error_string = MSG_REQVER;
315 error_args[0] = (IPTR)"expat.library";
316 error_args[1] = 4;
317 error_args[2] = 1;
318 goto error;
320 ExpatBase = image->expatbase;
322 parser = XML_ParserCreate(NULL);
323 if (!parser) {
324 error = ERROR_NO_FREE_STORE;
325 goto error;
328 memset(&parser_data, 0, sizeof(parser_data));
329 parser_data.parser = parser;
330 parser_data.image = image;
332 XML_SetUserData(parser, &parser_data);
333 XML_SetElementHandler(parser,
334 xml_start_element_handler,
335 xml_end_element_handler);
336 XML_SetCharacterDataHandler(parser,
337 xml_character_data_handler);
338 if (!XML_Parse(parser, data, xml_length, TRUE)) {
339 xml_error = XML_GetErrorCode(parser);
340 } else {
341 xml_error = XML_ERROR_NONE;
343 XML_ParserFree(parser);
344 if (parser_data.error) {
345 error = parser_data.error;
346 error_string = parser_data.error_string;
347 CopyMem(parser_data.error_args, error_args, sizeof(error_args));
348 goto error;
350 if (xml_error != XML_ERROR_NONE) {
351 if (xml_error == XML_ERROR_NO_MEMORY) {
352 error = ERROR_NO_FREE_STORE;
353 } else {
354 error = ERROR_OBJECT_WRONG_TYPE;
355 error_string = MSG_EXPATERR;
357 goto error;
360 CloseLibrary(image->expatbase);
361 image->expatbase = NULL;
362 } else if (koly->rsrc_fork_offset && koly->rsrc_fork_length) {
363 UQUAD rsrc_offset;
364 ULONG rsrc_length;
365 CONST_STRPTR src;
366 LONG len;
367 dmg_mish_t *mish;
368 LONG num_parts;
370 rsrc_offset = rbe64(&koly->rsrc_fork_offset);
371 rsrc_length = rbe64(&koly->rsrc_fork_length);
373 data = AllocVec(rsrc_length, MEMF_ANY);
374 if (!data) {
375 error = ERROR_NO_FREE_STORE;
376 goto error;
379 if (!ChangeFilePosition(file, rsrc_offset, OFFSET_BEGINNING) ||
380 Read(file, data, rsrc_length) != rsrc_length)
382 error = IoErr();
383 goto error;
386 src = data + 0x104;
387 len = rsrc_length - 0x104;
388 while (len >= 0xcc) {
389 mish = (dmg_mish_t *)src;
390 if (rbe32(&mish->id) != ID_mish) {
391 error = ERROR_OBJECT_WRONG_TYPE;
392 goto error;
395 num_parts = rbe32(&mish->blocks_run_count);
396 error = add_to_plist(image, src + 0xcc, 0x28*num_parts);
397 if (error != NO_ERROR) goto error;
399 src += (0xcc + (0x28*num_parts) + 0x04);
400 len -= (0xcc + (0x28*num_parts) + 0x04);
402 } else {
403 error = ERROR_NOT_IMPLEMENTED;
404 goto error;
407 if (image->uses_zlib) {
408 #ifdef __AROS__
409 image->zbase = OpenLibrary("z_au.library", 1);
410 ZBase = image->zbase;
411 #else
412 image->zbase = OpenLibrary("z.library", 1);
413 #endif
414 if (!image->zbase || !CheckLib(image->zbase, 1, 6)) {
415 error = ERROR_OBJECT_NOT_FOUND;
416 error_string = MSG_REQVER;
417 error_args[0] = (IPTR)"z.library";
418 error_args[1] = 1;
419 error_args[2] = 6;
420 goto error;
424 if (image->uses_bzlib) {
425 image->bz2base = OpenLibrary("bz2.library", 1);
426 #ifdef __AROS__
427 BZ2Base = image->bz2base;
428 #endif
429 if (!image->bz2base) {
430 error = ERROR_OBJECT_NOT_FOUND;
431 error_string = MSG_REQVER;
432 error_args[0] = (IPTR)"bz2.library";
433 error_args[1] = 1;
434 error_args[2] = 1;
435 goto error;
439 if (image->total_bytes == 0) {
440 goto error;
443 image->block_size = 512;
444 image->total_blocks = image->total_bytes / image->block_size;
446 hash_size = ((image->total_bytes >> HASH_FUNC) + 1) * sizeof(*hash);
447 image->hash = hash = AllocVec(hash_size, MEMF_ANY);
448 if (!hash) {
449 error = ERROR_NO_FREE_STORE;
450 goto error;
453 offset = next_offset = hash_offset = 0;
454 pnode = (struct MinNode *)image->plist->lh_Head;
455 while (pnode->mln_Succ) {
456 part = (struct DMGPart *)(pnode + 1);
457 do {
458 type = part->type;
459 switch (type) {
460 case PT_ZERO:
461 case PT_COPY:
462 case PT_IGNORE:
463 case PT_ADC:
464 case PT_ZLIB:
465 case PT_BZLIB:
466 next_offset += part->out_size;
467 while (next_offset > hash_offset) {
468 hash->pnode = pnode;
469 hash->part = part;
470 hash->offset = offset;
471 hash++;
472 hash_offset += (1 << HASH_FUNC);
474 offset = next_offset;
475 break;
477 part++;
478 } while (type != PT_END);
479 pnode = pnode->mln_Succ;
482 done = TRUE;
484 error:
485 FreeVec(data);
486 FreeVec(koly);
487 if (!done) {
488 if (image) {
489 Plugin_CloseImage(Self, image);
490 image = NULL;
491 } else {
492 Close(file);
494 if (error == NO_ERROR) {
495 error = ERROR_OBJECT_WRONG_TYPE;
496 error_string = MSG_EOF;
498 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
500 return image;
503 static LONG add_to_plist (struct DMGImage *image, CONST_STRPTR src, LONG len) {
504 struct MinNode *pnode;
505 LONG num_parts = len / 0x28;
506 struct DMGPart *part;
507 ULONG type;
509 if (num_parts <= 0) {
510 return NO_ERROR;
513 pnode = AllocVec(sizeof(*pnode) + (num_parts+1)*sizeof(*part), MEMF_CLEAR);
514 if (!pnode) {
515 return ERROR_NO_FREE_STORE;
518 AddTail(image->plist, (struct Node *)pnode);
520 part = (struct DMGPart *)(pnode + 1);
521 do {
522 part->type = type = rbe32(src);
523 part->in_offs = rbe32(src+28);
524 part->in_size = rbe32(src+36);
525 part->out_size = rbe32(src+20) << 9;
526 switch (type) {
527 case PT_ZERO:
528 case PT_COPY:
529 case PT_IGNORE:
530 image->total_bytes += part->out_size;
531 break;
532 case PT_COMMENT:
533 break;
534 case PT_ADC:
535 image->uses_adc = TRUE;
536 image->total_bytes += part->out_size;
537 break;
538 case PT_ZLIB:
539 image->uses_zlib = TRUE;
540 image->total_bytes += part->out_size;
541 break;
542 case PT_BZLIB:
543 image->uses_bzlib = TRUE;
544 image->total_bytes += part->out_size;
545 break;
546 case PT_END:
547 break;
548 default:
549 return ERROR_NOT_IMPLEMENTED;
550 break;
552 src += 0x28;
553 part++;
554 } while (type != PT_END && --num_parts);
555 part->type = PT_END;
556 part->in_offs = 0;
557 part->in_size = 0;
558 part->out_size = 0;
560 return NO_ERROR;
563 static const char *XML_GetAttrVal (const char *attr, const char **attrs, const char *defVal) {
564 while (*attrs) {
565 if (!strcmp(*attrs, attr)) {
566 return attrs[1];
568 attrs += 2;
570 return defVal;
573 static void xml_start_element_handler (void *user_data,
574 const char *name, const char **attrs)
576 XML_Parser_Data *data = user_data;
577 #ifndef __AROS__
578 struct Library *ExpatBase = data->expatbase;
579 #endif
580 if (data->error) return;
582 if (data->current_tag_depth == 0) {
583 if (strcmp(name, "plist") ||
584 strcmp(XML_GetAttrVal("version", attrs, ""), "1.0"))
586 data->error = ERROR_OBJECT_WRONG_TYPE;
587 XML_StopParser(data->parser, XML_TRUE);
588 return;
590 } else {
591 if (!strcmp(name, "data")) {
592 if (data->is_in_data_tag) {
593 data->error = ERROR_TOO_MANY_LEVELS;
594 XML_StopParser(data->parser, XML_TRUE);
595 return;
597 data->is_in_data_tag = TRUE;
598 data->len = 0;
601 data->current_tag_depth++;
604 static void xml_end_element_handler (void *user_data,
605 const char *name)
607 XML_Parser_Data *data = user_data;
608 #ifndef __AROS__
609 struct Library *ExpatBase = data->expatbase;
610 #endif
611 if (data->error) return;
613 data->current_tag_depth--;
614 if (data->current_tag_depth == 0) {
615 if (strcmp(name, "plist")) {
616 data->error = ERROR_OBJECT_WRONG_TYPE;
617 XML_StopParser(data->parser, XML_TRUE);
618 return;
620 } else {
621 if (!strcmp(name, "data")) {
622 if (!data->is_in_data_tag) {
623 data->error = ERROR_TOO_MANY_LEVELS;
624 XML_StopParser(data->parser, XML_TRUE);
625 return;
627 data->is_in_data_tag = FALSE;
628 if (data->len > 0) {
629 struct DMGImage *image = data->image;
630 LONG len;
632 cleanup_base64(data->data);
633 len = decode_base64(data->data, data->data);
635 data->error = add_to_plist(image, data->data + 0xcc, len - 0xcc);
636 if (data->error != NO_ERROR) {
637 XML_StopParser(data->parser, XML_TRUE);
638 return;
645 static void xml_character_data_handler (void *user_data,
646 const char *s, int len)
648 XML_Parser_Data *data = user_data;
649 #ifndef __AROS__
650 struct Library *ExpatBase = data->expatbase;
651 #endif
652 if (data->error) return;
654 if (data->is_in_data_tag && len > 0) {
655 if (len <= (data->size - data->len)) {
656 CopyMem(s, data->data + data->len, len);
657 data->len += len;
658 data->data[data->len] = 0;
659 } else {
660 STRPTR new_data;
661 new_data = AllocVec(data->len + len + 1, MEMF_ANY);
662 if (!new_data) {
663 data->error = ERROR_NO_FREE_STORE;
664 XML_StopParser(data->parser, XML_TRUE);
665 return;
667 if (data->data) {
668 CopyMem(data->data, new_data, data->len);
669 FreeVec(data->data);
671 CopyMem(s, new_data + data->len, len);
672 data->data = new_data;
673 data->len += len;
674 data->size = data->len;
675 data->data[data->len] = 0;
680 void DMG_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr) {
681 struct DMGImage *image = image_ptr;
682 if (image) {
683 if (image->bz2base) CloseLibrary(image->bz2base);
684 if (image->zbase) CloseLibrary(image->zbase);
685 if (image->expatbase) CloseLibrary(image->expatbase);
686 FreeVec(image->hash);
687 if (image->plist) {
688 struct Node *pnode;
689 while ((pnode = RemHead(image->plist))) {
690 FreeVec(pnode);
692 FreeVec(image->plist);
694 FreeVec(image->in_buf);
695 FreeVec(image->out_buf);
696 Close(image->file);
697 FreeVec(image);
701 LONG DMG_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg) {
702 struct DMGImage *image = image_ptr;
703 dg->dg_SectorSize = image->block_size;
704 dg->dg_Heads =
705 dg->dg_TrackSectors =
706 dg->dg_CylSectors = 1;
707 dg->dg_Cylinders =
708 dg->dg_TotalSectors = image->total_blocks;
709 return IOERR_SUCCESS;
712 LONG DMG_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io) {
713 struct DMGImage *image = image_ptr;
714 BPTR file = image->file;
715 UBYTE *buffer;
716 UQUAD offset;
717 ULONG size;
718 struct DMGHash *hash;
719 struct MinNode *pnode;
720 struct DMGPart *part;
721 UQUAD read_offs, next_offs;
722 ULONG to_skip, to_read;
724 buffer = io->io_Data;
725 offset = ((UQUAD)io->io_Offset)|((UQUAD)io->io_Actual << 32);
726 size = io->io_Length;
727 io->io_Actual = 0;
729 if (offset >= image->total_bytes) {
730 return TDERR_SeekError;
733 hash = &image->hash[offset >> HASH_FUNC];
734 pnode = hash->pnode;
735 part = hash->part;
736 read_offs = next_offs = hash->offset;
737 for (;;) {
738 switch (part->type) {
739 case PT_ZERO:
740 case PT_COPY:
741 case PT_IGNORE:
742 case PT_ADC:
743 case PT_ZLIB:
744 case PT_BZLIB:
745 next_offs += part->out_size;
746 part++;
747 break;
748 case PT_END:
749 pnode = (struct MinNode *)GetSucc((struct Node *)pnode);
750 if (!pnode) {
751 return TDERR_SeekError;
753 part = (struct DMGPart *)(pnode + 1);
754 break;
755 default:
756 part++;
757 break;
759 if (next_offs > offset) break;
760 read_offs = next_offs;
763 part--;
764 to_skip = offset - read_offs;
765 while (size) {
766 to_read = max((LONG)min(size, part->out_size - to_skip), 0);
768 switch (part->type) {
770 case PT_ADC:
771 if (!part->out_size) break;
772 if (image->part_in_buf != part) {
773 image->part_in_buf = NULL;
775 if (!(image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, part->in_size)) ||
776 !(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, part->out_size)))
778 return TDERR_NoMem;
781 if (!ChangeFilePosition(file, part->in_offs, OFFSET_BEGINNING)) {
782 return TDERR_SeekError;
784 if (Read(file, image->in_buf, part->in_size) != part->in_size) {
785 LONG error;
786 error = IoErr();
787 return error ? IPlugin_DOS2IOErr(error) : IOERR_BADLENGTH;
790 adc_decompress(image->out_buf, part->out_size, image->in_buf, part->in_size);
792 image->part_in_buf = part;
794 CopyMem(image->out_buf + to_skip, buffer, to_read);
795 part++;
796 break;
798 case PT_ZLIB:
799 if (!part->out_size) break;
800 if (image->part_in_buf != part) {
801 LONG status;
802 uLongf out_len;
803 image->part_in_buf = NULL;
805 if (!(image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, part->in_size)) ||
806 !(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, part->out_size)))
808 return TDERR_NoMem;
811 if (!ChangeFilePosition(file, part->in_offs, OFFSET_BEGINNING)) {
812 return TDERR_SeekError;
814 if (Read(file, image->in_buf, part->in_size) != part->in_size) {
815 return IPlugin_DOS2IOErr(IoErr());
818 out_len = part->out_size;
819 if ((status = Uncompress(image->out_buf, &out_len, image->in_buf,
820 part->in_size)) != Z_OK)
822 return TDERR_NotSpecified;
825 image->part_in_buf = part;
827 CopyMem(image->out_buf + to_skip, buffer, to_read);
828 part++;
829 break;
831 case PT_BZLIB:
832 if (!part->out_size) break;
833 if (image->part_in_buf != part) {
834 LONG status;
835 unsigned int out_len;
836 image->part_in_buf = NULL;
838 if (!(image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, part->in_size)) ||
839 !(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, part->out_size)))
841 return TDERR_NoMem;
844 if (!ChangeFilePosition(file, part->in_offs, OFFSET_BEGINNING)) {
845 return TDERR_SeekError;
847 if (Read(file, image->in_buf, part->in_size) != part->in_size) {
848 return IPlugin_DOS2IOErr(IoErr());
851 out_len = part->out_size;
852 if ((status = BZ2_bzBuffToBuffDecompress(image->out_buf, &out_len,
853 image->in_buf, part->in_size, 0, 0)) != BZ_OK)
855 return TDERR_NotSpecified;
858 image->part_in_buf = part;
860 CopyMem(image->out_buf + to_skip, buffer, to_read);
861 part++;
862 break;
864 case PT_COPY:
865 if (!part->out_size) break;
866 if (!ChangeFilePosition(file, part->in_offs + to_skip, OFFSET_BEGINNING)) {
867 return TDERR_SeekError;
869 if (Read(file, buffer, to_read) != to_read) {
870 LONG error;
871 error = IoErr();
872 return error ? IPlugin_DOS2IOErr(error) : IOERR_BADLENGTH;
874 part++;
875 break;
877 case PT_ZERO:
878 case PT_IGNORE:
879 memset(buffer, 0, to_read);
880 part++;
881 break;
883 case PT_END:
884 to_read = 0;
885 pnode = (struct MinNode *)GetSucc((struct Node *)pnode);
886 if (!pnode) return IOERR_BADLENGTH;
887 part = (struct DMGPart *)(pnode + 1);
888 break;
890 default:
891 to_read = 0;
892 part++;
893 break;
896 to_skip = 0;
897 buffer += to_read;
898 size -= to_read;
899 io->io_Actual += to_read;
901 return IOERR_SUCCESS;