z_au.library -> z1.library
[AROS.git] / workbench / devs / diskimage / plugins / uif.c
blob6767c8376402ae70e42a48068dff34be56a84bd8
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 <zlib.h>
35 # define InflateInit2 inflateInit2
36 # define Inflate inflate
37 # define InflateEnd inflateEnd
38 # define InflateReset inflateReset
39 #else
40 # include <libraries/z.h>
41 # include <proto/z.h>
42 #endif
44 #include <string.h>
45 #include "endian.h"
46 #include "device_locale.h"
47 #include <SDI_compiler.h>
48 #include "rev/diskimage.device_rev.h"
50 PLUGIN_VERSTAG("UIF")
52 extern struct DiskImagePlugin uif_plugin;
54 PLUGIN_TABLE(&uif_plugin)
56 #define HASH_FUNC 20
58 BOOL UIF_Init (struct DiskImagePlugin *Self, const struct PluginData *data);
59 BOOL UIF_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
60 const UBYTE *test, LONG testsize);
61 APTR UIF_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name);
62 void UIF_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr);
63 LONG UIF_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg);
64 LONG UIF_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io);
66 struct DiskImagePlugin uif_plugin = {
67 PLUGIN_NODE(0, "UIF"),
68 PLUGIN_FLAG_FOOTER|PLUGIN_FLAG_M68K,
69 64,
70 ZERO,
71 NULL,
72 UIF_Init,
73 NULL,
74 UIF_CheckImage,
75 UIF_OpenImage,
76 UIF_CloseImage,
77 UIF_Geometry,
78 UIF_Read,
79 NULL,
80 NULL,
81 NULL,
82 NULL,
83 NULL
86 struct Library *SysBase;
87 struct Library *DOSBase;
88 static struct DIPluginIFace *IPlugin;
89 #ifndef __AROS__
90 #define ZBase image->zbase
91 #else
92 struct Library *Z1Base;
93 #endif
95 BOOL UIF_Init (struct DiskImagePlugin *Self, const struct PluginData *data) {
96 SysBase = data->SysBase;
97 DOSBase = data->DOSBase;
98 IPlugin = data->IPlugin;
99 return TRUE;
102 #define BBIS_MAGIC MAKE_ID('b','b','i','s')
103 #define BLHR_MAGIC MAKE_ID('b','l','h','r')
104 #define BSDR_MAGIC MAKE_ID('b','s','d','r')
106 BOOL UIF_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
107 const UBYTE *test, LONG testsize)
109 return testsize >= 64 && rbe32(&test[testsize-64]) == BBIS_MAGIC;
112 #pragma pack(1)
114 typedef struct {
115 ULONG magic;
116 ULONG size;
117 ULONG ver;
118 ULONG num;
119 } blhr_t;
121 typedef struct {
122 UQUAD offset;
123 ULONG in_size;
124 ULONG sector;
125 ULONG out_size;
126 ULONG type;
127 } blhr_data_t;
129 typedef struct {
130 ULONG magic;
131 ULONG pad1;
132 UWORD ver;
133 ULONG image_type;
134 UWORD pad2;
135 ULONG sectors;
136 ULONG sector_size;
137 ULONG pad3;
138 UQUAD blhr;
139 ULONG blhr_bbis_size;
140 UBYTE hash[16];
141 ULONG pad4[2];
142 } bbis_t;
144 #pragma pack()
146 struct UIFHash {
147 blhr_data_t *data;
148 ULONG offset;
151 struct UIFImage {
152 BPTR file;
153 z_stream zs;
154 UBYTE *in_buf, *out_buf;
155 ULONG in_size, out_size;
156 ULONG num;
157 blhr_data_t *data, *data_in_buf;
158 struct UIFHash *hash;
159 ULONG block_size;
160 ULONG total_blocks;
161 UQUAD total_bytes;
162 struct Library *zbase;
165 APTR UIF_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 UIFImage *image = NULL;
171 bbis_t bbis;
172 blhr_t blhr;
173 blhr_data_t *data = NULL;
174 ULONG i;
176 ULONG hash_size;
177 struct UIFHash *hash;
178 UQUAD offset, next_offset;
179 UQUAD hash_offset;
181 if (!ChangeFilePosition(file, -(int)sizeof(bbis), OFFSET_END) ||
182 Read(file, &bbis, sizeof(bbis)) != sizeof(bbis))
184 error = IoErr();
185 goto error;
187 if (rbe32(&bbis.magic) != BBIS_MAGIC) {
188 error = ERROR_OBJECT_WRONG_TYPE;
189 goto error;
192 if (!ChangeFilePosition(file, rle64(&bbis.blhr), OFFSET_BEGINNING) ||
193 Read(file, &blhr, sizeof(blhr)) != sizeof(blhr))
195 error = IoErr();
196 goto error;
198 if (rbe32(&blhr.magic) != BLHR_MAGIC) {
199 error = ERROR_OBJECT_WRONG_TYPE;
200 goto error;
203 image = AllocVec(sizeof(*image), MEMF_CLEAR);
204 if (!image) {
205 error = ERROR_NO_FREE_STORE;
206 goto error;
209 image->file = file;
210 image->num = rle32(&blhr.num);
211 image->block_size = rle32(&bbis.sector_size);
213 #ifdef __AROS__
214 image->zbase = OpenLibrary("z1.library", 1);
215 Z1Base = image->zbase;
216 #else
217 image->zbase = OpenLibrary("z.library", 1);
218 #endif
219 if (!image->zbase || !CheckLib(image->zbase, 1, 6)) {
220 error = ERROR_OBJECT_NOT_FOUND;
221 error_string = MSG_REQVER;
222 error_args[0] = (IPTR)"z.library";
223 error_args[1] = 1;
224 error_args[2] = 6;
225 goto error;
228 image->in_size = rle32(&blhr.size);
229 image->out_size = sizeof(*data) * image->num;
231 image->in_buf = AllocVec(image->in_size, MEMF_ANY);
232 image->data = AllocVec(image->out_size, MEMF_ANY);
233 if (!image->in_buf || !image->data) {
234 error = ERROR_NO_FREE_STORE;
235 goto error;
238 if (Read(file, image->in_buf, image->in_size) != image->in_size) {
239 error = IoErr();
240 goto error;
243 if (InflateInit2(&image->zs, 15) != Z_OK) {
244 error = ERROR_OBJECT_WRONG_TYPE;
245 error_string = MSG_ZLIBERR;
246 goto error;
249 image->zs.next_in = image->in_buf;
250 image->zs.next_out = (UBYTE *)image->data;
251 image->zs.avail_in = image->in_size;
252 image->zs.avail_out = image->out_size;
253 if (Inflate(&image->zs, Z_SYNC_FLUSH) != Z_STREAM_END) {
254 error = ERROR_OBJECT_WRONG_TYPE;
255 error_string = MSG_ZLIBERR;
256 goto error;
259 image->out_size = 0;
260 data = image->data;
261 for (i = 0; i < image->num; i++, data++) {
262 data->offset = rle64(&data->offset);
263 data->in_size = rle32(&data->in_size);
264 data->sector = rle32(&data->sector);
265 data->out_size = rle32(&data->out_size);
266 data->type = rle32(&data->type);
268 image->total_blocks += data->out_size;
269 data->out_size *= image->block_size;
271 switch (data->type) {
272 case 1:
273 case 3:
274 case 5:
275 break;
276 default:
277 error = ERROR_BAD_NUMBER;
278 goto error;
282 image->total_bytes = image->total_blocks * image->block_size;
284 hash_size = ((image->total_bytes >> HASH_FUNC) + 1) << 3;
285 image->hash = hash = AllocVec(hash_size, MEMF_ANY);
286 if (!hash) {
287 error = ERROR_NO_FREE_STORE;
288 goto error;
291 offset =
292 next_offset =
293 hash_offset = 0;
294 data = image->data;
295 for (i = 0; i < image->num; i++, data++) {
296 next_offset += data->out_size;
297 while (next_offset > hash_offset) {
298 hash->data = data;
299 hash->offset = offset / image->block_size;
300 hash++;
301 hash_offset += (1 << HASH_FUNC);
303 offset = next_offset;
306 done = TRUE;
308 error:
309 if (!done) {
310 if (image) {
311 Plugin_CloseImage(Self, image);
312 image = NULL;
313 } else {
314 Close(file);
316 if (error == NO_ERROR) {
317 error = ERROR_OBJECT_WRONG_TYPE;
318 error_string = MSG_EOF;
320 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
322 return image;
325 void UIF_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr) {
326 struct UIFImage *image = image_ptr;
327 if (image) {
328 if (image->zbase) {
329 if (CheckLib(image->zbase, 1, 6)) InflateEnd(&image->zs);
330 CloseLibrary(image->zbase);
332 FreeVec(image->hash);
333 FreeVec(image->data);
334 FreeVec(image->in_buf);
335 FreeVec(image->out_buf);
336 Close(image->file);
337 FreeVec(image);
341 LONG UIF_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg) {
342 struct UIFImage *image = image_ptr;
343 dg->dg_SectorSize = image->block_size;
344 dg->dg_Heads =
345 dg->dg_TrackSectors =
346 dg->dg_CylSectors = 1;
347 dg->dg_Cylinders =
348 dg->dg_TotalSectors = image->total_blocks;
349 return IOERR_SUCCESS;
352 LONG UIF_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io) {
353 struct UIFImage *image = image_ptr;
354 BPTR file = image->file;
355 UBYTE *buffer;
356 UQUAD offset;
357 ULONG size;
358 struct UIFHash *hash;
359 blhr_data_t *data;
360 UQUAD read_offs, next_offs;
361 ULONG to_skip, to_read;
363 buffer = io->io_Data;
364 offset = ((UQUAD)io->io_Offset)|((UQUAD)io->io_Actual << 32);
365 size = io->io_Length;
366 io->io_Actual = 0;
368 if (offset >= image->total_bytes) return TDERR_SeekError;
370 hash = &image->hash[offset >> HASH_FUNC];
372 data = hash->data;
373 read_offs = next_offs = hash->offset * image->block_size;
374 for (;;) {
375 next_offs += data->out_size;
376 if (next_offs > offset) break;
377 read_offs = next_offs;
378 data++;
381 to_skip = offset - read_offs;
382 while (size) {
383 if (read_offs == image->total_bytes) return IOERR_BADLENGTH;
385 if (data->in_size > image->in_size) {
386 FreeVec(image->in_buf);
387 image->in_buf = AllocVec(image->in_size = data->in_size, MEMF_ANY);
388 if (!image->in_buf) {
389 image->in_size = 0;
390 return TDERR_NoMem;
393 if (data->out_size > image->out_size) {
394 FreeVec(image->out_buf);
395 image->out_buf = AllocVec(image->out_size = data->out_size, MEMF_ANY);
396 if (!image->out_buf) {
397 image->out_size = 0;
398 return TDERR_NoMem;
402 if (image->data_in_buf != data) {
403 image->data_in_buf = NULL;
404 if (!ChangeFilePosition(file, data->offset, OFFSET_BEGINNING) ||
405 Read(file, image->in_buf, data->in_size) != data->in_size)
407 return IPlugin_DOS2IOErr(IoErr());
411 to_read = min(data->out_size - to_skip, size);
412 switch (data->type) {
413 case 1:
414 if (data->in_size != data->out_size) {
415 return TDERR_NotSpecified;
417 CopyMem(image->in_buf + to_skip, buffer, to_read);
418 image->data_in_buf = data;
419 break;
420 case 3:
421 memset(buffer, 0, to_read);
422 break;
423 case 5:
424 if (image->data_in_buf != data) {
425 InflateReset(&image->zs);
426 image->zs.next_in = image->in_buf;
427 image->zs.next_out = image->out_buf;
428 image->zs.avail_in = data->in_size;
429 image->zs.avail_out = data->out_size;
430 if (Inflate(&image->zs, Z_SYNC_FLUSH) != Z_STREAM_END) {
431 return TDERR_NotSpecified;
433 image->data_in_buf = data;
435 CopyMem(image->out_buf + to_skip, buffer, to_read);
436 break;
439 to_skip = 0;
440 buffer += to_read;
441 size -= to_read;
442 io->io_Actual += to_read;
444 read_offs += data->out_size;
445 data++;
447 return IOERR_SUCCESS;