1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
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>
36 # define InflateInit2 inflateInit2
37 # define Inflate inflate
38 # define InflateEnd inflateEnd
39 # define InflateReset inflateReset
41 # include <libraries/z.h>
46 #include "device_locale.h"
48 #include <SDI_compiler.h>
49 #include "rev/diskimage.device_rev.h"
53 extern struct DiskImagePlugin daa_plugin
;
55 PLUGIN_TABLE(&daa_plugin
)
57 typedef struct daa_file_s
{
58 struct daa_file_s
*next
;
74 UBYTE
*in_buf
, *out_buf
;
75 ULONG in_size
, out_size
;
76 daa_data_t
*data_in_buf
;
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"),
111 struct Library
*SysBase
;
112 struct Library
*DOSBase
;
113 static struct Library
*UtilityBase
;
114 static struct DIPluginIFace
*IPlugin
;
116 #define ZBase image->zbase
118 struct Library
*Z1Base
;
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
;
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"));
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
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
) {
170 LONG error
= NO_ERROR
;
171 LONG error_string
= NO_ERROR_STRING
;
172 IPTR error_args
[4] = {0};
173 struct DAAImage
*image
= NULL
;
178 LONG multi
= FALSE
, multinum
= 0;
180 STRPTR namebuf
= NULL
, extbuf
= NULL
;
181 CONST_STRPTR fmt
= NULL
;
182 ULONG daa_size
, daas
, i
;
183 UBYTE
*daa_data
= NULL
, *src
;
186 if (FRead(file
, &daa
, 1, sizeof(daa
)) != sizeof(daa
)) {
190 if (!strcmp(daa
.sign
, "DAA VOL")) {
191 error
= ERROR_OBJECT_WRONG_TYPE
;
192 error_string
= MSG_WRONGDAA
;
195 if (strcmp(daa
.sign
, "DAA") ||
196 rle32(&daa
.b100
) != 0x100 ||
199 error
= ERROR_OBJECT_WRONG_TYPE
;
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)
218 error
= ERROR_OBJECT_WRONG_TYPE
;
222 if (!ChangeFilePosition(file
, len
-8, OFFSET_CURRENT
)) {
229 image
= AllocVec(sizeof(*image
), MEMF_CLEAR
);
231 error
= ERROR_NO_FREE_STORE
;
236 fn
= AllocVec(sizeof(*fn
), MEMF_CLEAR
);
238 error
= ERROR_NO_FREE_STORE
;
242 fn
->size
= GetFileSize(file
);
243 fn
->offset
= rle32(&daa
.data_offset
);
244 if (fn
->size
== (UQUAD
)-1) {
250 image
->zbase
= OpenLibrary("z1.library", 1);
251 Z1Base
= image
->zbase
;
253 image
->zbase
= OpenLibrary("z.library", 1);
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";
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
271 if ((p
= find_ext(name
, "01.daa"))) { // Three-digit numbering at end of name
274 } else { // Defaults to two-digit numbering in the extension.
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.
281 namebuf
= AllocVec(len
+ 16, MEMF_ANY
);
283 error
= ERROR_NO_FREE_STORE
;
286 memcpy(namebuf
, name
, len
); // Copy the basename.
287 extbuf
= namebuf
+ len
;
288 // Select pattern for the multi-volume numbering determined above:
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
;
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
;
311 if (!ChangeFilePosition(file
, size_offset
- offset
, OFFSET_CURRENT
) ||
312 FRead(file
, daa_data
, 1, daa_size
) != daa_size
)
320 for (i
= 0; i
< daas
; i
++) {
321 while (offset
>= fn
->size
) {
325 error
= ERROR_OBJECT_WRONG_TYPE
;
329 fn
->next
= AllocVec(sizeof(*fn
), MEMF_CLEAR
);
330 if (!(fn
= fn
->next
)) {
331 error
= ERROR_NO_FREE_STORE
;
335 SNPrintf(extbuf
, 16, fmt
, multinum
++);
336 fn
->file
= file
= Open(namebuf
, MODE_OLDFILE
);
338 (fn
->size
= GetFileSize(file
)) == (UQUAD
)-1 ||
339 Read(file
, &daa
, sizeof(daa
)) != sizeof(daa
))
344 if (strcmp(daa
.sign
, "DAA VOL")) {
345 error
= ERROR_OBJECT_WRONG_TYPE
;
349 fn
->offset
= rle32(&daa
.size_offset
);
350 offset
+= fn
->offset
;
351 if (!ChangeFilePosition(file
, fn
->offset
, OFFSET_BEGINNING
)) {
357 len
= (src
[0] << 16)|(src
[2] << 8)|(src
[1]);
362 data
->offset
= offset
;
367 if (InflateInit2(&image
->zs
, -15) != Z_OK
) {
368 error
= ERROR_OBJECT_WRONG_TYPE
;
369 error_string
= MSG_ZLIBERR
;
380 Plugin_CloseImage(Self
, image
);
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
);
394 void DAA_CloseImage (struct DiskImagePlugin
*Self
, APTR image_ptr
) {
395 struct DAAImage
*image
= image_ptr
;
398 daa_file_t
*fn
, *next
;
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
) {
410 FreeVec(image
->data
);
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
;
419 dg
->dg_TrackSectors
=
420 dg
->dg_CylSectors
= 1;
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
;
430 ULONG block
, to_read
, to_skip
;
432 ULONG out_size
= image
->out_size
;
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
;
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
;
452 to_read
= min(size
, out_size
- to_skip
);
454 if (image
->data_in_buf
!= data
) {
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
) {
466 in_buf
= image
->in_buf
;
468 bytes_left
= data
->size
;
469 read_offs
= data
->offset
;
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;
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
);
500 io
->io_Actual
+= to_read
;