revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / plugins / daa.c
blob60d3da64d122e0e3dddce0716467122445ed95c6
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()
154 /* find_ext - a supoort routine that checks a filename for the given extension:
155 ** If the extension is present, the return value is the pointer to the start of
156 ** the extension, which is the same as the end of the base name.
157 ** If not, then the return code is NULL.
159 static CONST_STRPTR find_ext (CONST_STRPTR fname, CONST_STRPTR ext) {
160 LONG len = strlen(fname);
161 LONG extlen = strlen(ext);
162 CONST_STRPTR ret = fname+len-extlen;
164 return (len >= extlen && !Stricmp(ret, ext) ? ret : NULL);
168 APTR DAA_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name) {
169 LONG done = FALSE;
170 LONG error = NO_ERROR;
171 LONG error_string = NO_ERROR_STRING;
172 IPTR error_args[4] = {0};
173 struct DAAImage *image = NULL;
174 daa_t daa;
175 UQUAD offset;
176 ULONG size_offset;
177 ULONG type, len;
178 LONG multi = FALSE, multinum = 0;
179 daa_file_t *fn;
180 STRPTR namebuf = NULL, extbuf = NULL;
181 CONST_STRPTR fmt = NULL;
182 ULONG daa_size, daas, i;
183 UBYTE *daa_data = NULL, *src;
184 daa_data_t *data;
186 if (FRead(file, &daa, 1, sizeof(daa)) != sizeof(daa)) {
187 error = IoErr();
188 goto error;
190 if (!strcmp(daa.sign, "DAA VOL")) {
191 error = ERROR_OBJECT_WRONG_TYPE;
192 error_string = MSG_WRONGDAA;
193 goto error;
195 if (strcmp(daa.sign, "DAA") ||
196 rle32(&daa.b100) != 0x100 ||
197 rle32(&daa.b1) != 1)
199 error = ERROR_OBJECT_WRONG_TYPE;
200 goto error;
203 offset = sizeof(daa);
204 size_offset = rle32(&daa.size_offset);
205 while (offset < size_offset) {
206 if (FRead(file, &type, 1, 4) != 4 ||
207 FRead(file, &len, 1, 4) != 4)
209 error = IoErr();
210 goto error;
213 switch (type) {
214 case 1:
215 multi = TRUE;
216 break;
217 case 3:
218 error = ERROR_OBJECT_WRONG_TYPE;
219 goto error;
222 if (!ChangeFilePosition(file, len-8, OFFSET_CURRENT)) {
223 error = IoErr();
224 goto error;
226 offset += len;
229 image = AllocVec(sizeof(*image), MEMF_CLEAR);
230 if (!image) {
231 error = ERROR_NO_FREE_STORE;
232 goto error;
235 image->files =
236 fn = AllocVec(sizeof(*fn), MEMF_CLEAR);
237 if (!fn) {
238 error = ERROR_NO_FREE_STORE;
239 goto error;
241 fn->file = file;
242 fn->size = GetFileSize(file);
243 fn->offset = rle32(&daa.data_offset);
244 if (fn->size == (UQUAD)-1) {
245 error = IoErr();
246 goto error;
249 #ifdef __AROS__
250 image->zbase = OpenLibrary("z1.library", 1);
251 Z1Base = image->zbase;
252 #else
253 image->zbase = OpenLibrary("z.library", 1);
254 #endif
255 if (!image->zbase || !CheckLib(image->zbase, 1, 6)) {
256 error = ERROR_OBJECT_NOT_FOUND;
257 error_string = MSG_REQVER;
258 error_args[0] = (IPTR)"z.library";
259 error_args[1] = 1;
260 error_args[2] = 6;
261 goto error;
264 if (multi || fn->size != rle64(&daa.filesize)) {
265 // Determine the type of numbering in the labels of the multiple volumes:
266 CONST_STRPTR p; // End of basename
267 if ((p = find_ext(name, "001.daa"))) { // Three-digit numbering at end of name
268 multi = 1;
269 multinum = 2;
270 } else
271 if ((p = find_ext(name, "01.daa"))) { // Three-digit numbering at end of name
272 multi = 2;
273 multinum = 2;
274 } else { // Defaults to two-digit numbering in the extension.
275 multi = 3;
276 multinum = 0;
277 p = strrchr(name, '.'); // Set end of basename to start of whatever extension.
278 if (!p) p = name + strlen(name); // If no extension, set to end of the name.
280 len = p - name;
281 namebuf = AllocVec(len + 16, MEMF_ANY);
282 if (!namebuf) {
283 error = ERROR_NO_FREE_STORE;
284 goto error;
286 memcpy(namebuf, name, len); // Copy the basename.
287 extbuf = namebuf + len;
288 // Select pattern for the multi-volume numbering determined above:
289 switch (multi) {
290 case 1: fmt = "%03ld.daa"; break;
291 case 2: fmt = "%02ld.daa"; break;
292 default: fmt = ".d%02ld"; break;
296 daa_size = rle32(&daa.data_offset) - size_offset;
297 daas = daa_size / 3;
298 image->out_size = rle32(&daa.chunksize);
299 image->block_size = 2048;
300 image->total_bytes = daas * image->out_size;
301 image->total_blocks = image->total_bytes >> 11;
303 daa_data = AllocVec(daa_size, MEMF_ANY);
304 image->data = data = AllocVec(daas * sizeof(*image->data), MEMF_ANY);
305 image->out_buf = AllocVec(image->out_size, MEMF_ANY);
306 if (!daa_data || !data || !image->out_buf) {
307 error = ERROR_NO_FREE_STORE;
308 goto error;
311 if (!ChangeFilePosition(file, size_offset - offset, OFFSET_CURRENT) ||
312 FRead(file, daa_data, 1, daa_size) != daa_size)
314 error = IoErr();
315 goto error;
318 offset = fn->offset;
319 src = daa_data;
320 for (i = 0; i < daas; i++) {
321 while (offset >= fn->size) {
322 offset -= fn->size;
324 if (!multi) {
325 error = ERROR_OBJECT_WRONG_TYPE;
326 goto error;
329 fn->next = AllocVec(sizeof(*fn), MEMF_CLEAR);
330 if (!(fn = fn->next)) {
331 error = ERROR_NO_FREE_STORE;
332 goto error;
335 SNPrintf(extbuf, 16, fmt, multinum++);
336 fn->file = file = Open(namebuf, MODE_OLDFILE);
337 if (!file ||
338 (fn->size = GetFileSize(file)) == (UQUAD)-1 ||
339 Read(file, &daa, sizeof(daa)) != sizeof(daa))
341 error = IoErr();
342 goto error;
344 if (strcmp(daa.sign, "DAA VOL")) {
345 error = ERROR_OBJECT_WRONG_TYPE;
346 goto error;
349 fn->offset = rle32(&daa.size_offset);
350 offset += fn->offset;
351 if (!ChangeFilePosition(file, fn->offset, OFFSET_BEGINNING)) {
352 error = IoErr();
353 goto error;
357 len = (src[0] << 16)|(src[2] << 8)|(src[1]);
358 src += 3;
360 data->file = fn;
361 data->size = len;
362 data->offset = offset;
363 offset += len;
364 data++;
367 if (InflateInit2(&image->zs, -15) != Z_OK) {
368 error = ERROR_OBJECT_WRONG_TYPE;
369 error_string = MSG_ZLIBERR;
370 goto error;
373 done = TRUE;
375 error:
376 FreeVec(daa_data);
377 FreeVec(namebuf);
378 if (!done) {
379 if (image) {
380 Plugin_CloseImage(Self, image);
381 image = NULL;
382 } else {
383 Close(file);
385 if (error == NO_ERROR) {
386 error = ERROR_OBJECT_WRONG_TYPE;
387 error_string = MSG_EOF;
389 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
391 return image;
394 void DAA_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr) {
395 struct DAAImage *image = image_ptr;
397 if (image) {
398 daa_file_t *fn, *next;
399 if (image->zbase) {
400 if (CheckLib(image->zbase, 1, 6)) InflateEnd(&image->zs);
401 CloseLibrary(image->zbase);
403 FreeVec(image->in_buf);
404 FreeVec(image->out_buf);
405 for (fn = image->files; fn; fn = next) {
406 next = fn->next;
407 Close(fn->file);
408 FreeVec(fn);
410 FreeVec(image->data);
411 FreeVec(image);
415 LONG DAA_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg) {
416 struct DAAImage *image = image_ptr;
417 dg->dg_SectorSize = image->block_size;
418 dg->dg_Heads =
419 dg->dg_TrackSectors =
420 dg->dg_CylSectors = 1;
421 dg->dg_Cylinders =
422 dg->dg_TotalSectors = image->total_blocks;
423 return IOERR_SUCCESS;
426 LONG DAA_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io) {
427 struct DAAImage *image = image_ptr;
428 UBYTE *buffer;
429 UQUAD offset;
430 ULONG block, to_read, to_skip;
431 ULONG size;
432 ULONG out_size = image->out_size;
433 daa_data_t *data;
434 daa_file_t *fn;
435 LONG error = IOERR_SUCCESS;
437 buffer = io->io_Data;
438 offset = ((UQUAD)io->io_Offset)|((UQUAD)io->io_Actual << 32);
439 size = io->io_Length;
440 io->io_Actual = 0;
442 if (offset >= image->total_bytes) return TDERR_SeekError;
443 if (offset + size > image->total_bytes) {
444 error = IOERR_BADLENGTH;
445 size = image->total_bytes - offset;
448 block = offset / out_size;
449 to_skip = offset % out_size;
450 data = image->data + block;
451 while (size) {
452 to_read = min(size, out_size - to_skip);
454 if (image->data_in_buf != data) {
455 UBYTE *in_buf;
456 UQUAD read_offs;
457 ULONG bytes_left, read_size;
459 image->data_in_buf = NULL;
461 image->in_buf = ReAllocBuf(image->in_buf, &image->in_size, data->size);
462 if (!image->in_buf) {
463 return TDERR_NoMem;
466 in_buf = image->in_buf;
467 fn = data->file;
468 bytes_left = data->size;
469 read_offs = data->offset;
470 while (fn) {
471 if (!ChangeFilePosition(fn->file, data->offset, OFFSET_BEGINNING)) {
472 return TDERR_SeekError;
474 read_size = min(bytes_left, fn->size - read_offs);
475 if (Read(fn->file, in_buf, read_size) != read_size) {
476 return IPlugin_DOS2IOErr(IoErr());
478 bytes_left -= read_size;
479 if (bytes_left == 0) break;
480 in_buf += read_size;
481 fn = fn->next;
484 InflateReset(&image->zs);
485 image->zs.next_in = image->in_buf;
486 image->zs.next_out = image->out_buf;
487 image->zs.avail_in = data->size;
488 image->zs.avail_out = out_size;
489 if (Inflate(&image->zs, Z_SYNC_FLUSH) != Z_STREAM_END) {
490 return TDERR_NotSpecified;
493 image->data_in_buf = data;
495 CopyMem(image->out_buf + to_skip, buffer, to_read);
496 to_skip = 0;
498 buffer += to_read;
499 size -= to_read;
500 io->io_Actual += to_read;
501 data++;
503 return error;