z_au.library -> z1.library
[AROS.git] / workbench / devs / diskimage / plugins / daa.c
blobafa6c787dfe687fa6e14395603ae16096c8cbcf3
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>
32 #include <string.h>
34 #ifdef __AROS__
35 # include <zlib.h>
36 # define InflateInit2 inflateInit2
37 # define Inflate inflate
38 # define InflateEnd inflateEnd
39 # define InflateReset inflateReset
40 #else
41 # include <libraries/z.h>
42 # include <proto/z.h>
43 #endif
45 #include "endian.h"
46 #include "device_locale.h"
47 #include "support.h"
48 #include <SDI_compiler.h>
49 #include "rev/diskimage.device_rev.h"
51 PLUGIN_VERSTAG("DAA")
53 extern struct DiskImagePlugin daa_plugin;
55 PLUGIN_TABLE(&daa_plugin)
57 typedef struct daa_file_s {
58 struct daa_file_s *next;
59 BPTR file;
60 UQUAD size;
61 ULONG offset;
62 } daa_file_t;
64 typedef struct {
65 daa_file_t *file;
66 ULONG size;
67 UQUAD offset;
68 } daa_data_t;
70 struct DAAImage {
71 daa_file_t *files;
72 daa_data_t *data;
73 z_stream zs;
74 UBYTE *in_buf, *out_buf;
75 ULONG in_size, out_size;
76 daa_data_t *data_in_buf;
77 UQUAD total_bytes;
78 ULONG block_size;
79 ULONG total_blocks;
80 struct Library *zbase;
83 BOOL DAA_Init (struct DiskImagePlugin *Self, const struct PluginData *data);
84 BOOL DAA_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
85 const UBYTE *test, LONG testsize);
86 APTR DAA_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name);
87 void DAA_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr);
88 LONG DAA_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg);
89 LONG DAA_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io);
91 struct DiskImagePlugin daa_plugin = {
92 PLUGIN_NODE(0, "DAA"),
93 PLUGIN_FLAG_M68K,
95 ZERO,
96 NULL,
97 DAA_Init,
98 NULL,
99 DAA_CheckImage,
100 DAA_OpenImage,
101 DAA_CloseImage,
102 DAA_Geometry,
103 DAA_Read,
104 NULL,
105 NULL,
106 NULL,
107 NULL,
108 NULL
111 struct Library *SysBase;
112 struct Library *DOSBase;
113 static struct Library *UtilityBase;
114 static struct DIPluginIFace *IPlugin;
115 #ifndef __AROS__
116 #define ZBase image->zbase
117 #else
118 struct Library *Z1Base;
119 #endif
121 BOOL DAA_Init (struct DiskImagePlugin *Self, const struct PluginData *data) {
122 SysBase = data->SysBase;
123 DOSBase = data->DOSBase;
124 UtilityBase = data->UtilityBase;
125 IPlugin = data->IPlugin;
126 return TRUE;
129 BOOL DAA_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
130 const UBYTE *test, LONG testsize)
132 return testsize >= 8 && (!strcmp(test, "DAA") || !strcmp(test, "DAA VOL"));
135 #pragma pack(1)
137 typedef struct {
138 UBYTE sign[16]; // 00: DAA
139 ULONG size_offset; // 10: where starts the list of sizes of the zipped chunks
140 ULONG b100; // 14: must be 0x100
141 ULONG data_offset; // 18: where starts the zipped chunks
142 ULONG b1; // 1C: must be 1
143 ULONG b0; // 20: ever 0
144 ULONG chunksize; // 24: size of each output chunk
145 UQUAD isosize; // 28: total size of the output ISO
146 UQUAD filesize; // 30: total size of the DAA file
147 UBYTE zero[16]; // 38: it's ever zero
148 ULONG crc; // 48: checksum calculated on the first 0x48 bytes
149 } daa_t;
151 #pragma pack()
153 static CONST_STRPTR find_ext (CONST_STRPTR fname, CONST_STRPTR ext) {
154 LONG len, extlen;
155 CONST_STRPTR ret;
156 len = strlen(fname);
157 extlen = strlen(ext);
158 ret = fname+len-extlen;
159 if (len >= extlen && !Stricmp(ret, ext)) {
160 return ret;
162 return NULL;
165 APTR DAA_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name) {
166 LONG done = FALSE;
167 LONG error = NO_ERROR;
168 LONG error_string = NO_ERROR_STRING;
169 IPTR error_args[4] = {0};
170 struct DAAImage *image = NULL;
171 daa_t daa;
172 UQUAD offset;
173 ULONG size_offset;
174 ULONG type, len;
175 LONG multi = FALSE, multinum = 0;
176 daa_file_t *fn;
177 STRPTR namebuf = NULL, extbuf = NULL;
178 CONST_STRPTR fmt = NULL;
179 ULONG daa_size, daas, i;
180 UBYTE *daa_data = NULL, *src;
181 daa_data_t *data;
183 if (FRead(file, &daa, 1, sizeof(daa)) != sizeof(daa)) {
184 error = IoErr();
185 goto error;
187 if (!strcmp(daa.sign, "DAA VOL")) {
188 error = ERROR_OBJECT_WRONG_TYPE;
189 error_string = MSG_WRONGDAA;
190 goto error;
192 if (strcmp(daa.sign, "DAA") ||
193 rle32(&daa.b100) != 0x100 ||
194 rle32(&daa.b1) != 1)
196 error = ERROR_OBJECT_WRONG_TYPE;
197 goto error;
200 offset = sizeof(daa);
201 size_offset = rle32(&daa.size_offset);
202 while (offset < size_offset) {
203 if (FRead(file, &type, 1, 4) != 4 ||
204 FRead(file, &len, 1, 4) != 4)
206 error = IoErr();
207 goto error;
210 switch (type) {
211 case 1:
212 multi = TRUE;
213 break;
214 case 3:
215 error = ERROR_OBJECT_WRONG_TYPE;
216 goto error;
219 if (!ChangeFilePosition(file, len-8, OFFSET_CURRENT)) {
220 error = IoErr();
221 goto error;
223 offset += len;
226 image = AllocVec(sizeof(*image), MEMF_CLEAR);
227 if (!image) {
228 error = ERROR_NO_FREE_STORE;
229 goto error;
232 image->files =
233 fn = AllocVec(sizeof(*fn), MEMF_CLEAR);
234 if (!fn) {
235 error = ERROR_NO_FREE_STORE;
236 goto error;
238 fn->file = file;
239 fn->size = GetFileSize(file);
240 fn->offset = rle32(&daa.data_offset);
241 if (fn->size == (UQUAD)-1) {
242 error = IoErr();
243 goto error;
246 #ifdef __AROS__
247 image->zbase = OpenLibrary("z1.library", 1);
248 Z1Base = image->zbase;
249 #else
250 image->zbase = OpenLibrary("z.library", 1);
251 #endif
252 if (!image->zbase || !CheckLib(image->zbase, 1, 6)) {
253 error = ERROR_OBJECT_NOT_FOUND;
254 error_string = MSG_REQVER;
255 error_args[0] = (IPTR)"z.library";
256 error_args[1] = 1;
257 error_args[2] = 6;
258 goto error;
261 if (multi || fn->size != rle64(&daa.filesize)) {
262 CONST_STRPTR p;
263 if ((p = find_ext(name, "001.daa"))) {
264 multi = 1;
265 multinum = 2;
266 } else
267 if ((p = find_ext(name, "01.daa"))) {
268 multi = 2;
269 multinum = 2;
270 } else {
271 multi = 3;
272 multinum = 0;
273 p = find_ext(name, ".daa");
274 if (!p) p = strchr(p, 0);
276 len = p - name;
277 namebuf = AllocVec(len + 16, MEMF_ANY);
278 if (!namebuf) {
279 error = ERROR_NO_FREE_STORE;
280 goto error;
282 memcpy(namebuf, name, len);
283 extbuf = namebuf + len;
284 switch (multi) {
285 case 1: fmt = "%03ld.daa"; break;
286 case 2: fmt = "%02ld.daa"; break;
287 default: fmt = ".d%02ld"; break;
291 daa_size = rle32(&daa.data_offset) - size_offset;
292 daas = daa_size / 3;
293 image->out_size = rle32(&daa.chunksize);
294 image->block_size = 2048;
295 image->total_bytes = daas * image->out_size;
296 image->total_blocks = image->total_bytes >> 11;
298 daa_data = AllocVec(daa_size, MEMF_ANY);
299 image->data = data = AllocVec(daas * sizeof(*image->data), MEMF_ANY);
300 image->out_buf = AllocVec(image->out_size, MEMF_ANY);
301 if (!daa_data || !data || !image->out_buf) {
302 error = ERROR_NO_FREE_STORE;
303 goto error;
306 if (!ChangeFilePosition(file, size_offset - offset, OFFSET_CURRENT) ||
307 FRead(file, daa_data, 1, daa_size) != daa_size)
309 error = IoErr();
310 goto error;
313 offset = fn->offset;
314 src = daa_data;
315 for (i = 0; i < daas; i++) {
316 while (offset >= fn->size) {
317 offset -= fn->size;
319 if (!multi) {
320 error = ERROR_OBJECT_WRONG_TYPE;
321 goto error;
324 fn->next = AllocVec(sizeof(*fn), MEMF_CLEAR);
325 if (!(fn = fn->next)) {
326 error = ERROR_NO_FREE_STORE;
327 goto error;
330 SNPrintf(extbuf, 16, fmt, multinum++);
331 fn->file = file = Open(namebuf, MODE_OLDFILE);
332 if (!file ||
333 (fn->size = GetFileSize(file)) == (UQUAD)-1 ||
334 Read(file, &daa, sizeof(daa)) != sizeof(daa))
336 error = IoErr();
337 goto error;
339 if (strcmp(daa.sign, "DAA VOL")) {
340 error = ERROR_OBJECT_WRONG_TYPE;
341 goto error;
344 fn->offset = rle32(&daa.size_offset);
345 offset += fn->offset;
346 if (!ChangeFilePosition(file, fn->offset, OFFSET_BEGINNING)) {
347 error = IoErr();
348 goto error;
352 len = (src[0] << 16)|(src[2] << 8)|(src[1]);
353 src += 3;
355 data->file = fn;
356 data->size = len;
357 data->offset = offset;
358 offset += len;
359 data++;
362 if (InflateInit2(&image->zs, -15) != Z_OK) {
363 error = ERROR_OBJECT_WRONG_TYPE;
364 error_string = MSG_ZLIBERR;
365 goto error;
368 done = TRUE;
370 error:
371 FreeVec(daa_data);
372 FreeVec(namebuf);
373 if (!done) {
374 if (image) {
375 Plugin_CloseImage(Self, image);
376 image = NULL;
377 } else {
378 Close(file);
380 if (error == NO_ERROR) {
381 error = ERROR_OBJECT_WRONG_TYPE;
382 error_string = MSG_EOF;
384 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
386 return image;
389 void DAA_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr) {
390 struct DAAImage *image = image_ptr;
392 if (image) {
393 daa_file_t *fn, *next;
394 if (image->zbase) {
395 if (CheckLib(image->zbase, 1, 6)) InflateEnd(&image->zs);
396 CloseLibrary(image->zbase);
398 FreeVec(image->in_buf);
399 FreeVec(image->out_buf);
400 for (fn = image->files; fn; fn = next) {
401 next = fn->next;
402 Close(fn->file);
403 FreeVec(fn);
405 FreeVec(image->data);
406 FreeVec(image);
410 LONG DAA_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg) {
411 struct DAAImage *image = image_ptr;
412 dg->dg_SectorSize = image->block_size;
413 dg->dg_Heads =
414 dg->dg_TrackSectors =
415 dg->dg_CylSectors = 1;
416 dg->dg_Cylinders =
417 dg->dg_TotalSectors = image->total_blocks;
418 return IOERR_SUCCESS;
421 LONG DAA_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io) {
422 struct DAAImage *image = image_ptr;
423 UBYTE *buffer;
424 UQUAD offset;
425 ULONG block, to_read, to_skip;
426 ULONG size;
427 ULONG out_size = image->out_size;
428 daa_data_t *data;
429 daa_file_t *fn;
430 LONG error = IOERR_SUCCESS;
432 buffer = io->io_Data;
433 offset = ((UQUAD)io->io_Offset)|((UQUAD)io->io_Actual << 32);
434 size = io->io_Length;
435 io->io_Actual = 0;
437 if (offset >= image->total_bytes) return TDERR_SeekError;
438 if (offset + size > image->total_bytes) {
439 error = IOERR_BADLENGTH;
440 size = image->total_bytes - offset;
443 block = offset / out_size;
444 to_skip = offset % out_size;
445 data = image->data + block;
446 while (size) {
447 to_read = min(size, out_size - to_skip);
449 if (image->data_in_buf != data) {
450 UBYTE *in_buf;
451 UQUAD read_offs;
452 ULONG bytes_left, read_size;
454 image->data_in_buf = NULL;
456 image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, data->size);
457 if (!image->in_buf) {
458 return TDERR_NoMem;
461 in_buf = image->in_buf;
462 fn = data->file;
463 bytes_left = data->size;
464 read_offs = data->offset;
465 while (fn) {
466 if (!ChangeFilePosition(fn->file, data->offset, OFFSET_BEGINNING)) {
467 return TDERR_SeekError;
469 read_size = min(bytes_left, fn->size - read_offs);
470 if (Read(fn->file, in_buf, read_size) != read_size) {
471 return IPlugin_DOS2IOErr(IoErr());
473 bytes_left -= read_size;
474 if (bytes_left == 0) break;
475 in_buf += read_size;
476 fn = fn->next;
479 InflateReset(&image->zs);
480 image->zs.next_in = image->in_buf;
481 image->zs.next_out = image->out_buf;
482 image->zs.avail_in = data->size;
483 image->zs.avail_out = out_size;
484 if (Inflate(&image->zs, Z_SYNC_FLUSH) != Z_STREAM_END) {
485 return TDERR_NotSpecified;
488 image->data_in_buf = data;
490 CopyMem(image->out_buf + to_skip, buffer, to_read);
491 to_skip = 0;
493 buffer += to_read;
494 size -= to_read;
495 io->io_Actual += to_read;
496 data++;
498 return error;