diskimage: Compiler delint
[AROS.git] / workbench / devs / diskimage / plugins / dmg / dmg.c
blob209ac1bd1db0b7b306929ec26224ce65c0b1f8b0
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 struct Library *BZ2Base;
39 struct Library *ZBase;
40 struct Library *ExpatBase;
41 #else
42 # include <libraries/expat.h>
43 # include <libraries/z.h>
44 # include <libraries/bz2.h>
45 # include <proto/expat.h>
46 # include <proto/z.h>
47 # include <proto/bz2.h>
48 #endif
50 #include "endian.h"
51 #include "base64.h"
52 #include "adc.h"
53 #include "device_locale.h"
54 #include <string.h>
55 #include <SDI_compiler.h>
56 #include "rev/diskimage.device_rev.h"
58 PLUGIN_VERSTAG("DMG")
60 extern struct DiskImagePlugin dmg_plugin;
62 PLUGIN_TABLE(&dmg_plugin)
64 struct DMGPart {
65 ULONG type;
66 ULONG in_offs;
67 ULONG in_size;
68 ULONG out_size;
71 struct DMGHash {
72 struct MinNode *pnode;
73 struct DMGPart *part;
74 UQUAD offset;
77 #define HASH_FUNC 20
79 struct DMGImage {
80 BPTR file;
81 BYTE uses_adc;
82 BYTE uses_zlib;
83 BYTE uses_bzlib;
84 struct List *plist;
85 struct DMGHash *hash;
86 UBYTE *in_buf, *out_buf;
87 ULONG in_size, out_size;
88 struct DMGPart *part_in_buf;
89 ULONG block_size;
90 ULONG total_blocks;
91 UQUAD total_bytes;
92 struct Library *expatbase;
93 struct Library *zbase;
94 struct Library *bz2base;
97 BOOL DMG_Init (struct DiskImagePlugin *Self, const struct PluginData *data);
98 BOOL DMG_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
99 const UBYTE *test, LONG testsize);
100 APTR DMG_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name);
101 void DMG_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr);
102 LONG DMG_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg);
103 LONG DMG_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io);
105 struct DiskImagePlugin dmg_plugin = {
106 PLUGIN_NODE(0, "DMG"),
107 PLUGIN_FLAG_FOOTER|PLUGIN_FLAG_M68K,
108 512,
109 ZERO,
110 NULL,
111 DMG_Init,
112 NULL,
113 DMG_CheckImage,
114 DMG_OpenImage,
115 DMG_CloseImage,
116 DMG_Geometry,
117 DMG_Read,
118 NULL,
119 NULL,
120 NULL,
121 NULL,
122 NULL
125 struct Library *SysBase;
126 struct Library *DOSBase;
127 static struct DIPluginIFace *IPlugin;
128 #define ZBase image->zbase
129 #define BZ2Base image->bz2base
131 BOOL DMG_Init (struct DiskImagePlugin *Self, const struct PluginData *data) {
132 SysBase = data->SysBase;
133 DOSBase = data->DOSBase;
134 IPlugin = data->IPlugin;
135 return TRUE;
138 #define ID_koly MAKE_ID('k','o','l','y')
139 #define ID_mish MAKE_ID('m','i','s','h')
141 BOOL DMG_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
142 const UBYTE *test, LONG testsize)
144 return testsize >= 512 && rbe32(&test[testsize-512]) == ID_koly;
147 #pragma pack(1)
149 typedef struct {
150 ULONG id;
151 ULONG version;
152 ULONG header_size;
153 ULONG flags;
154 UQUAD running_data_fork_offset;
155 UQUAD data_fork_offset;
156 UQUAD data_fork_length;
157 UQUAD rsrc_fork_offset;
158 UQUAD rsrc_fork_length;
159 ULONG segment_number;
160 ULONG segment_count;
161 ULONG segment_id1;
162 ULONG segment_id2;
163 ULONG segment_id3;
164 ULONG segment_id4;
165 ULONG data_fork_checksum_type;
166 ULONG reserved1;
167 ULONG data_fork_checksum;
168 ULONG reserved2[31];
169 UQUAD xml_offset;
170 UQUAD xml_length;
171 ULONG reserved3[30];
172 ULONG master_checksum_type;
173 ULONG reserved4;
174 ULONG master_checksum;
175 ULONG reserved5[31];
176 ULONG image_variant;
177 UQUAD sector_count;
178 ULONG reserved6[3];
179 } dmg_koly_t;
181 typedef struct {
182 ULONG id;
183 ULONG version;
184 UQUAD first_sector;
185 UQUAD sector_count;
186 UQUAD data_start;
187 ULONG decompressed_buffer_size;
188 ULONG blocks_descriptor;
189 ULONG reserved1[6];
190 ULONG checksum_type;
191 ULONG reserved2;
192 ULONG checksum;
193 ULONG reserved3[31];
194 ULONG blocks_run_count;
195 } dmg_mish_t;
197 #define PT_ZERO 0x00000000
198 #define PT_COPY 0x00000001
199 #define PT_IGNORE 0x00000002
200 #define PT_COMMENT 0x7ffffffe
201 #define PT_ADC 0x80000004
202 #define PT_ZLIB 0x80000005
203 #define PT_BZLIB 0x80000006
204 #define PT_END 0xffffffff
206 #pragma pack()
208 typedef struct {
209 struct Library *expatbase;
210 XML_Parser parser;
211 struct DMGImage *image;
212 LONG current_tag_depth;
213 BYTE is_in_data_tag;
214 STRPTR data;
215 LONG len, size;
216 LONG error;
217 LONG error_string;
218 IPTR error_args[4];
219 } XML_Parser_Data;
221 static LONG add_to_plist (struct DMGImage *image, CONST_STRPTR src, LONG len);
223 static void xml_start_element_handler (void *user_data,
224 const char *name, const char **attrs);
225 static void xml_end_element_handler (void *user_data,
226 const char *name);
227 static void xml_character_data_handler (void *user_data,
228 const char *s, int len);
230 APTR DMG_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file,
231 CONST_STRPTR name)
233 LONG done = FALSE;
234 LONG error = NO_ERROR;
235 LONG error_string = NO_ERROR_STRING;
236 IPTR error_args[4] = {0};
237 dmg_koly_t *koly = NULL;
238 STRPTR data = NULL;
239 struct DMGImage *image = NULL;
240 struct MinNode *pnode;
241 struct DMGPart *part;
242 ULONG type;
243 ULONG hash_size;
244 struct DMGHash *hash;
245 UQUAD offset, next_offset;
246 UQUAD hash_offset;
248 koly = AllocVec(sizeof(*koly), MEMF_ANY);
249 if (!koly) {
250 error = ERROR_NO_FREE_STORE;
251 goto error;
254 if (!ChangeFilePosition(file, -(int)sizeof(*koly), OFFSET_END) ||
255 Read(file, koly, sizeof(*koly)) != sizeof(*koly))
257 error = IoErr();
258 goto error;
261 if (rbe32(&koly->id) != ID_koly) {
262 error = ERROR_OBJECT_WRONG_TYPE;
263 goto error;
266 image = AllocVec(sizeof(*image), MEMF_CLEAR);
267 if (!image) {
268 error = ERROR_NO_FREE_STORE;
269 goto error;
271 image->file = file;
273 image->plist = AllocVec(sizeof(struct MinList), MEMF_ANY);
274 if (!image->plist) {
275 error = ERROR_NO_FREE_STORE;
276 goto error;
278 image->plist->lh_Head = (struct Node *)&image->plist->lh_Tail;
279 image->plist->lh_Tail = NULL;
280 image->plist->lh_TailPred = (struct Node *)&image->plist->lh_Head;
282 if (koly->xml_offset && koly->xml_length) {
283 UQUAD xml_offset;
284 ULONG xml_length;
285 XML_Parser parser;
286 XML_Parser_Data parser_data;
287 int xml_error;
288 struct Library __unused *ExpatBase;
290 xml_offset = rbe64(&koly->xml_offset);
291 xml_length = rbe64(&koly->xml_length);
293 data = AllocVec(xml_length, MEMF_ANY);
294 if (!data) {
295 error = ERROR_NO_FREE_STORE;
296 goto error;
299 if (!ChangeFilePosition(file, xml_offset, OFFSET_BEGINNING) ||
300 Read(file, data, xml_length) != xml_length)
302 error = IoErr();
303 goto error;
306 #ifdef __AROS__
307 image->expatbase = OpenLibrary("expat_au.library", 1);
308 #else
309 image->expatbase = OpenLibrary("expat.library", 4);
310 #endif
311 if (!image->expatbase) {
312 error = ERROR_OBJECT_NOT_FOUND;
313 error_string = MSG_REQVER;
314 error_args[0] = (IPTR)"expat.library";
315 error_args[1] = 4;
316 error_args[2] = 1;
317 goto error;
319 ExpatBase = image->expatbase;
321 parser = XML_ParserCreate(NULL);
322 if (!parser) {
323 error = ERROR_NO_FREE_STORE;
324 goto error;
327 memset(&parser_data, 0, sizeof(parser_data));
328 parser_data.parser = parser;
329 parser_data.image = image;
331 XML_SetUserData(parser, &parser_data);
332 XML_SetElementHandler(parser,
333 xml_start_element_handler,
334 xml_end_element_handler);
335 XML_SetCharacterDataHandler(parser,
336 xml_character_data_handler);
337 if (!XML_Parse(parser, data, xml_length, TRUE)) {
338 xml_error = XML_GetErrorCode(parser);
339 } else {
340 xml_error = XML_ERROR_NONE;
342 XML_ParserFree(parser);
343 if (parser_data.error) {
344 error = parser_data.error;
345 error_string = parser_data.error_string;
346 CopyMem(parser_data.error_args, error_args, sizeof(error_args));
347 goto error;
349 if (xml_error != XML_ERROR_NONE) {
350 if (xml_error == XML_ERROR_NO_MEMORY) {
351 error = ERROR_NO_FREE_STORE;
352 } else {
353 error = ERROR_OBJECT_WRONG_TYPE;
354 error_string = MSG_EXPATERR;
356 goto error;
359 CloseLibrary(image->expatbase);
360 image->expatbase = NULL;
361 } else if (koly->rsrc_fork_offset && koly->rsrc_fork_length) {
362 UQUAD rsrc_offset;
363 ULONG rsrc_length;
364 CONST_STRPTR src;
365 LONG len;
366 dmg_mish_t *mish;
367 LONG num_parts;
369 rsrc_offset = rbe64(&koly->rsrc_fork_offset);
370 rsrc_length = rbe64(&koly->rsrc_fork_length);
372 data = AllocVec(rsrc_length, MEMF_ANY);
373 if (!data) {
374 error = ERROR_NO_FREE_STORE;
375 goto error;
378 if (!ChangeFilePosition(file, rsrc_offset, OFFSET_BEGINNING) ||
379 Read(file, data, rsrc_length) != rsrc_length)
381 error = IoErr();
382 goto error;
385 src = data + 0x104;
386 len = rsrc_length - 0x104;
387 while (len >= 0xcc) {
388 mish = (dmg_mish_t *)src;
389 if (rbe32(&mish->id) != ID_mish) {
390 error = ERROR_OBJECT_WRONG_TYPE;
391 goto error;
394 num_parts = rbe32(&mish->blocks_run_count);
395 error = add_to_plist(image, src + 0xcc, 0x28*num_parts);
396 if (error != NO_ERROR) goto error;
398 src += (0xcc + (0x28*num_parts) + 0x04);
399 len -= (0xcc + (0x28*num_parts) + 0x04);
401 } else {
402 error = ERROR_NOT_IMPLEMENTED;
403 goto error;
406 if (image->uses_zlib) {
407 #ifdef __AROS__
408 image->zbase = OpenLibrary("z_au.library", 1);
409 ZBase = image->zbase;
410 #else
411 image->zbase = OpenLibrary("z.library", 1);
412 #endif
413 if (!image->zbase || !CheckLib(image->zbase, 1, 6)) {
414 error = ERROR_OBJECT_NOT_FOUND;
415 error_string = MSG_REQVER;
416 error_args[0] = (IPTR)"z.library";
417 error_args[1] = 1;
418 error_args[2] = 6;
419 goto error;
423 if (image->uses_bzlib) {
424 #ifdef __AROS__
425 image->bz2base = OpenLibrary("bz2_au.library", 1);
426 BZ2Base = image->bz2base;
427 #else
428 image->bz2base = OpenLibrary("bz2.library", 1);
429 #endif
430 if (!image->bz2base) {
431 error = ERROR_OBJECT_NOT_FOUND;
432 error_string = MSG_REQVER;
433 error_args[0] = (IPTR)"bz2.library";
434 error_args[1] = 1;
435 error_args[2] = 1;
436 goto error;
440 if (image->total_bytes == 0) {
441 goto error;
444 image->block_size = 512;
445 image->total_blocks = image->total_bytes / image->block_size;
447 hash_size = ((image->total_bytes >> HASH_FUNC) + 1) * sizeof(*hash);
448 image->hash = hash = AllocVec(hash_size, MEMF_ANY);
449 if (!hash) {
450 error = ERROR_NO_FREE_STORE;
451 goto error;
454 offset = next_offset = hash_offset = 0;
455 pnode = (struct MinNode *)image->plist->lh_Head;
456 while (pnode->mln_Succ) {
457 part = (struct DMGPart *)(pnode + 1);
458 do {
459 type = part->type;
460 switch (type) {
461 case PT_ZERO:
462 case PT_COPY:
463 case PT_IGNORE:
464 case PT_ADC:
465 case PT_ZLIB:
466 case PT_BZLIB:
467 next_offset += part->out_size;
468 while (next_offset > hash_offset) {
469 hash->pnode = pnode;
470 hash->part = part;
471 hash->offset = offset;
472 hash++;
473 hash_offset += (1 << HASH_FUNC);
475 offset = next_offset;
476 break;
478 part++;
479 } while (type != PT_END);
480 pnode = pnode->mln_Succ;
483 done = TRUE;
485 error:
486 FreeVec(data);
487 FreeVec(koly);
488 if (!done) {
489 if (image) {
490 Plugin_CloseImage(Self, image);
491 image = NULL;
492 } else {
493 Close(file);
495 if (error == NO_ERROR) {
496 error = ERROR_OBJECT_WRONG_TYPE;
497 error_string = MSG_EOF;
499 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
501 return image;
504 static LONG add_to_plist (struct DMGImage *image, CONST_STRPTR src, LONG len) {
505 struct MinNode *pnode;
506 LONG num_parts = len / 0x28;
507 struct DMGPart *part;
508 ULONG type;
510 if (num_parts <= 0) {
511 return NO_ERROR;
514 pnode = AllocVec(sizeof(*pnode) + (num_parts+1)*sizeof(*part), MEMF_CLEAR);
515 if (!pnode) {
516 return ERROR_NO_FREE_STORE;
519 AddTail(image->plist, (struct Node *)pnode);
521 part = (struct DMGPart *)(pnode + 1);
522 do {
523 part->type = type = rbe32(src);
524 part->in_offs = rbe32(src+28);
525 part->in_size = rbe32(src+36);
526 part->out_size = rbe32(src+20) << 9;
527 switch (type) {
528 case PT_ZERO:
529 case PT_COPY:
530 case PT_IGNORE:
531 image->total_bytes += part->out_size;
532 break;
533 case PT_COMMENT:
534 break;
535 case PT_ADC:
536 image->uses_adc = TRUE;
537 image->total_bytes += part->out_size;
538 break;
539 case PT_ZLIB:
540 image->uses_zlib = TRUE;
541 image->total_bytes += part->out_size;
542 break;
543 case PT_BZLIB:
544 image->uses_bzlib = TRUE;
545 image->total_bytes += part->out_size;
546 break;
547 case PT_END:
548 break;
549 default:
550 return ERROR_NOT_IMPLEMENTED;
551 break;
553 src += 0x28;
554 part++;
555 } while (type != PT_END && --num_parts);
556 part->type = PT_END;
557 part->in_offs = 0;
558 part->in_size = 0;
559 part->out_size = 0;
561 return NO_ERROR;
564 static const char *XML_GetAttrVal (const char *attr, const char **attrs, const char *defVal) {
565 while (*attrs) {
566 if (!strcmp(*attrs, attr)) {
567 return attrs[1];
569 attrs += 2;
571 return defVal;
574 static void xml_start_element_handler (void *user_data,
575 const char *name, const char **attrs)
577 XML_Parser_Data *data = user_data;
578 struct Library __unused *ExpatBase = data->expatbase;
579 if (data->error) return;
581 if (data->current_tag_depth == 0) {
582 if (strcmp(name, "plist") ||
583 strcmp(XML_GetAttrVal("version", attrs, ""), "1.0"))
585 data->error = ERROR_OBJECT_WRONG_TYPE;
586 XML_StopParser(data->parser, XML_TRUE);
587 return;
589 } else {
590 if (!strcmp(name, "data")) {
591 if (data->is_in_data_tag) {
592 data->error = ERROR_TOO_MANY_LEVELS;
593 XML_StopParser(data->parser, XML_TRUE);
594 return;
596 data->is_in_data_tag = TRUE;
597 data->len = 0;
600 data->current_tag_depth++;
603 static void xml_end_element_handler (void *user_data,
604 const char *name)
606 XML_Parser_Data *data = user_data;
607 struct Library __unused *ExpatBase = data->expatbase;
608 if (data->error) return;
610 data->current_tag_depth--;
611 if (data->current_tag_depth == 0) {
612 if (strcmp(name, "plist")) {
613 data->error = ERROR_OBJECT_WRONG_TYPE;
614 XML_StopParser(data->parser, XML_TRUE);
615 return;
617 } else {
618 if (!strcmp(name, "data")) {
619 if (!data->is_in_data_tag) {
620 data->error = ERROR_TOO_MANY_LEVELS;
621 XML_StopParser(data->parser, XML_TRUE);
622 return;
624 data->is_in_data_tag = FALSE;
625 if (data->len > 0) {
626 struct DMGImage *image = data->image;
627 LONG len;
629 cleanup_base64(data->data);
630 len = decode_base64(data->data, data->data);
632 data->error = add_to_plist(image, data->data + 0xcc, len - 0xcc);
633 if (data->error != NO_ERROR) {
634 XML_StopParser(data->parser, XML_TRUE);
635 return;
642 static void xml_character_data_handler (void *user_data,
643 const char *s, int len)
645 XML_Parser_Data *data = user_data;
646 struct Library __unused *ExpatBase = data->expatbase;
647 if (data->error) return;
649 if (data->is_in_data_tag && len > 0) {
650 if (len <= (data->size - data->len)) {
651 CopyMem(s, data->data + data->len, len);
652 data->len += len;
653 data->data[data->len] = 0;
654 } else {
655 STRPTR new_data;
656 new_data = AllocVec(data->len + len + 1, MEMF_ANY);
657 if (!new_data) {
658 data->error = ERROR_NO_FREE_STORE;
659 XML_StopParser(data->parser, XML_TRUE);
660 return;
662 if (data->data) {
663 CopyMem(data->data, new_data, data->len);
664 FreeVec(data->data);
666 CopyMem(s, new_data + data->len, len);
667 data->data = new_data;
668 data->len += len;
669 data->size = data->len;
670 data->data[data->len] = 0;
675 void DMG_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr) {
676 struct DMGImage *image = image_ptr;
677 if (image) {
678 if (image->bz2base) CloseLibrary(image->bz2base);
679 if (image->zbase) CloseLibrary(image->zbase);
680 if (image->expatbase) CloseLibrary(image->expatbase);
681 FreeVec(image->hash);
682 if (image->plist) {
683 struct Node *pnode;
684 while ((pnode = RemHead(image->plist))) {
685 FreeVec(pnode);
687 FreeVec(image->plist);
689 FreeVec(image->in_buf);
690 FreeVec(image->out_buf);
691 Close(image->file);
692 FreeVec(image);
696 LONG DMG_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg) {
697 struct DMGImage *image = image_ptr;
698 dg->dg_SectorSize = image->block_size;
699 dg->dg_Heads =
700 dg->dg_TrackSectors =
701 dg->dg_CylSectors = 1;
702 dg->dg_Cylinders =
703 dg->dg_TotalSectors = image->total_blocks;
704 return IOERR_SUCCESS;
707 LONG DMG_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io) {
708 struct DMGImage *image = image_ptr;
709 BPTR file = image->file;
710 UBYTE *buffer;
711 UQUAD offset;
712 ULONG size;
713 struct DMGHash *hash;
714 struct MinNode *pnode;
715 struct DMGPart *part;
716 UQUAD read_offs, next_offs;
717 ULONG to_skip, to_read;
719 buffer = io->io_Data;
720 offset = ((UQUAD)io->io_Offset)|((UQUAD)io->io_Actual << 32);
721 size = io->io_Length;
722 io->io_Actual = 0;
724 if (offset >= image->total_bytes) {
725 return TDERR_SeekError;
728 hash = &image->hash[offset >> HASH_FUNC];
729 pnode = hash->pnode;
730 part = hash->part;
731 read_offs = next_offs = hash->offset;
732 for (;;) {
733 switch (part->type) {
734 case PT_ZERO:
735 case PT_COPY:
736 case PT_IGNORE:
737 case PT_ADC:
738 case PT_ZLIB:
739 case PT_BZLIB:
740 next_offs += part->out_size;
741 part++;
742 break;
743 case PT_END:
744 pnode = (struct MinNode *)GetSucc((struct Node *)pnode);
745 if (!pnode) {
746 return TDERR_SeekError;
748 part = (struct DMGPart *)(pnode + 1);
749 break;
750 default:
751 part++;
752 break;
754 if (next_offs > offset) break;
755 read_offs = next_offs;
758 part--;
759 to_skip = offset - read_offs;
760 while (size) {
761 to_read = max((LONG)min(size, part->out_size - to_skip), 0);
763 switch (part->type) {
765 case PT_ADC:
766 if (!part->out_size) break;
767 if (image->part_in_buf != part) {
768 image->part_in_buf = NULL;
770 if (!(image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, part->in_size)) ||
771 !(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, part->out_size)))
773 return TDERR_NoMem;
776 if (!ChangeFilePosition(file, part->in_offs, OFFSET_BEGINNING)) {
777 return TDERR_SeekError;
779 if (Read(file, image->in_buf, part->in_size) != part->in_size) {
780 LONG error;
781 error = IoErr();
782 return error ? IPlugin_DOS2IOErr(error) : IOERR_BADLENGTH;
785 adc_decompress(image->out_buf, part->out_size, image->in_buf, part->in_size);
787 image->part_in_buf = part;
789 CopyMem(image->out_buf + to_skip, buffer, to_read);
790 part++;
791 break;
793 case PT_ZLIB:
794 if (!part->out_size) break;
795 if (image->part_in_buf != part) {
796 LONG status;
797 uLongf out_len;
798 image->part_in_buf = NULL;
800 if (!(image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, part->in_size)) ||
801 !(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, part->out_size)))
803 return TDERR_NoMem;
806 if (!ChangeFilePosition(file, part->in_offs, OFFSET_BEGINNING)) {
807 return TDERR_SeekError;
809 if (Read(file, image->in_buf, part->in_size) != part->in_size) {
810 return IPlugin_DOS2IOErr(IoErr());
813 out_len = part->out_size;
814 if ((status = Uncompress(image->out_buf, &out_len, image->in_buf,
815 part->in_size)) != Z_OK)
817 return TDERR_NotSpecified;
820 image->part_in_buf = part;
822 CopyMem(image->out_buf + to_skip, buffer, to_read);
823 part++;
824 break;
826 case PT_BZLIB:
827 if (!part->out_size) break;
828 if (image->part_in_buf != part) {
829 LONG status;
830 unsigned int out_len;
831 image->part_in_buf = NULL;
833 if (!(image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, part->in_size)) ||
834 !(image->out_buf = ReAllocBuf(image->out_buf, &image->out_size, part->out_size)))
836 return TDERR_NoMem;
839 if (!ChangeFilePosition(file, part->in_offs, OFFSET_BEGINNING)) {
840 return TDERR_SeekError;
842 if (Read(file, image->in_buf, part->in_size) != part->in_size) {
843 return IPlugin_DOS2IOErr(IoErr());
846 out_len = part->out_size;
847 if ((status = BZ2_bzBuffToBuffDecompress(image->out_buf, &out_len,
848 image->in_buf, part->in_size, 0, 0)) != BZ_OK)
850 return TDERR_NotSpecified;
853 image->part_in_buf = part;
855 CopyMem(image->out_buf + to_skip, buffer, to_read);
856 part++;
857 break;
859 case PT_COPY:
860 if (!part->out_size) break;
861 if (!ChangeFilePosition(file, part->in_offs + to_skip, OFFSET_BEGINNING)) {
862 return TDERR_SeekError;
864 if (Read(file, buffer, to_read) != to_read) {
865 LONG error;
866 error = IoErr();
867 return error ? IPlugin_DOS2IOErr(error) : IOERR_BADLENGTH;
869 part++;
870 break;
872 case PT_ZERO:
873 case PT_IGNORE:
874 memset(buffer, 0, to_read);
875 part++;
876 break;
878 case PT_END:
879 to_read = 0;
880 pnode = (struct MinNode *)GetSucc((struct Node *)pnode);
881 if (!pnode) return IOERR_BADLENGTH;
882 part = (struct DMGPart *)(pnode + 1);
883 break;
885 default:
886 to_read = 0;
887 part++;
888 break;
891 to_skip = 0;
892 buffer += to_read;
893 size -= to_read;
894 io->io_Actual += to_read;
896 return IOERR_SUCCESS;