revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / plugins / dms.c
blob177f238dc49b1f14322e1ecb94139e83709b1da2
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 <xdms.h>
32 #include <string.h>
33 #include "device_locale.h"
34 #include "endian.h"
35 #include <SDI_compiler.h>
36 #include "rev/diskimage.device_rev.h"
38 PLUGIN_VERSTAG("DMS")
40 extern struct DiskImagePlugin dms_plugin;
42 PLUGIN_TABLE(&dms_plugin)
44 BOOL DMS_Init (struct DiskImagePlugin *Self, const struct PluginData *data);
45 BOOL DMS_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
46 const UBYTE *test, LONG testsize);
47 APTR DMS_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name);
49 struct DiskImagePlugin dms_plugin = {
50 PLUGIN_NODE(0, "DMS"),
51 PLUGIN_FLAG_M68K,
53 ZERO,
54 NULL,
55 DMS_Init,
56 NULL,
57 DMS_CheckImage,
58 DMS_OpenImage,
59 NULL,
60 NULL,
61 NULL,
62 NULL,
63 NULL,
64 NULL,
65 NULL,
66 NULL
69 static struct Library *SysBase;
70 static struct Library *DOSBase;
71 static struct DIPluginIFace *IPlugin;
73 BOOL DMS_Init (struct DiskImagePlugin *Self, const struct PluginData *data) {
74 SysBase = data->SysBase;
75 DOSBase = data->DOSBase;
76 IPlugin = data->IPlugin;
77 return TRUE;
80 #define DMS_MAGIC MAKE_ID('D','M','S','!')
82 BOOL DMS_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
83 const UBYTE *test, LONG testsize)
85 return testsize >= sizeof(ULONG) && rbe32(test) == DMS_MAGIC;
88 #define TRACK_BUFFER_SIZE (32*1024)
89 #define TEMP_BUFFER_SIZE (32*1024)
91 #define HEADLEN 56
92 #define THLEN 20
94 #define ERR_BADDECR 1
95 #define ERR_UNKNMODE 2
97 static LONG process_track (struct xdms_data *xdms, BPTR in, BPTR out, UBYTE *b1, UBYTE *b2, UWORD pwd,
98 UBYTE *eof, LONG *error_string);
99 static UWORD unpack_track (struct xdms_data *xdms, UBYTE *b1, UBYTE *b2, UWORD pklen2, UWORD unpklen,
100 UWORD cmode, UBYTE flags);
101 static void dms_decrypt (struct xdms_data *xdms, UBYTE *p, UWORD len);
103 APTR DMS_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file,
104 CONST_STRPTR name)
106 LONG done = FALSE;
107 LONG error = NO_ERROR;
108 LONG error_string = NO_ERROR_STRING;
109 IPTR error_args[4] = {0};
110 APTR image = NULL;
111 UBYTE *b1, *b2;
112 UWORD geninfo, hcrc, disktype;
113 BPTR outfile = ZERO;
114 UBYTE eof;
115 UWORD pwd = 0;
116 BPTR tmpdir;
117 CONST_STRPTR tmpname;
118 struct xdms_data *xdms;
119 UBYTE *text;
121 b1 = AllocVec(TRACK_BUFFER_SIZE, MEMF_ANY);
122 b2 = AllocVec(TRACK_BUFFER_SIZE, MEMF_ANY);
123 xdms = AllocVec(sizeof(struct xdms_data), MEMF_CLEAR);
124 text = AllocVec(TEMP_BUFFER_SIZE, MEMF_ANY);
125 if (!b1 || !b2 || !xdms || !text) {
126 error = ERROR_NO_FREE_STORE;
127 goto error;
129 xdms->text = text;
131 if (FRead(file, b1, 1, HEADLEN) != HEADLEN) {
132 error = IoErr();
133 goto error;
135 hcrc = rbe16(&b1[HEADLEN-2]);
136 if (hcrc != CreateCRC(b1+4, HEADLEN-6)) {
137 error = ERROR_BAD_NUMBER;
138 error_string = MSG_BADCRC;
139 goto error;
142 geninfo = rbe16(&b1[10]);
143 disktype = rbe16(&b1[50]);
145 if (disktype == 7) {
146 error = ERROR_OBJECT_WRONG_TYPE;
147 goto error;
149 if (geninfo & 2) {
150 STRPTR passwd;
151 pwd = 1;
152 passwd = IPlugin_RequestPassword(unit);
153 if (!passwd) {
154 error = ERROR_NO_FREE_STORE;
155 goto error;
157 if (passwd[0]) {
158 xdms->PWDCRC = CreateCRC(passwd, strlen(passwd));
159 FreeVec(passwd);
160 } else {
161 FreeVec(passwd);
162 error = ERROR_REQUIRED_ARG_MISSING;
163 error_string = MSG_NOPASSWD;
164 goto error;
168 error = IPlugin_CreateTempFile(unit, "adf", &tmpdir, &tmpname);
169 if (error) {
170 goto error;
172 outfile = IPlugin_OpenTempFile(unit, MODE_NEWFILE);
173 if (!outfile) {
174 error = IoErr();
175 goto error;
178 Init_Decrunchers(xdms);
180 eof = 0;
181 while (error == NO_ERROR && !eof)
182 error = process_track(xdms, file, outfile, b1, b2, pwd, &eof, &error_string);
183 if (error != NO_ERROR) goto error;
185 done = TRUE;
187 Close(outfile);
188 outfile = IPlugin_OpenTempFile(unit, MODE_OLDFILE);
189 if (!outfile) {
190 error = IoErr();
191 goto error;
194 done = TRUE;
195 tmpdir = CurrentDir(tmpdir);
196 image = IPlugin_OpenImage(unit, outfile, tmpname);
197 outfile = ZERO;
198 CurrentDir(tmpdir);
200 error:
201 FreeVec(b1);
202 FreeVec(b2);
203 FreeVec(xdms);
204 FreeVec(text);
205 Close(file);
206 Close(outfile);
207 if (!done) {
208 if (error == NO_ERROR) {
209 error = ERROR_OBJECT_WRONG_TYPE;
210 error_string = MSG_EOF;
212 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
214 return image;
217 static LONG process_track (struct xdms_data *xdms, BPTR in, BPTR out, UBYTE *b1, UBYTE *b2, UWORD pwd,
218 UBYTE *eof, LONG *error_string)
220 LONG error;
221 UWORD l, hcrc, dcrc, number, pklen1, pklen2, unpklen, usum;
222 UBYTE flags, cmode;
224 l = FRead(in, b1, 1, THLEN);
225 if (l != THLEN) {
226 *eof = 1;
227 if (l == 0) {
228 return NO_ERROR;
230 error = IoErr();
231 if (!error) {
232 error = ERROR_OBJECT_WRONG_TYPE;
233 *error_string = MSG_EOF;
235 return error;
238 if (b1[0] != 'T' || b1[1] != 'R') {
239 *eof = 1;
240 return NO_ERROR;
243 hcrc = rbe16(&b1[THLEN-2]);
244 if (hcrc != CreateCRC(b1, THLEN-2)) {
245 error = ERROR_BAD_NUMBER;
246 *error_string = MSG_BADCRC;
247 return error;
250 number = rbe16(&b1[2]);
251 pklen1 = rbe16(&b1[6]);
252 pklen2 = rbe16(&b1[8]);
253 unpklen = rbe16(&b1[10]);
254 flags = b1[12];
255 cmode = b1[13];
256 usum = rbe16(&b1[14]);
257 dcrc = rbe16(&b1[16]);
259 if (pklen1 > TRACK_BUFFER_SIZE || pklen2 > TRACK_BUFFER_SIZE ||
260 unpklen > TRACK_BUFFER_SIZE)
262 return ERROR_BUFFER_OVERFLOW;
265 if (FRead(in, b1, 1, pklen1) != pklen1) {
266 *eof = 1;
267 error = IoErr();
268 if (!error) {
269 error = ERROR_OBJECT_WRONG_TYPE;
270 *error_string = MSG_EOF;
272 return error;
275 if (dcrc != CreateCRC(b1, pklen1)) {
276 error = ERROR_BAD_NUMBER;
277 *error_string = MSG_BADCRC;
278 return error;
281 if (pwd && number != 80) dms_decrypt(xdms, b1, pklen1);
283 if (number < 80 && unpklen > 2048) {
284 error = unpack_track(xdms, b1, b2, pklen2, unpklen, cmode, flags);
285 switch (error) {
286 case ERR_BADDECR:
287 error = ERROR_BAD_NUMBER;
288 *error_string = MSG_BADDATA;
289 return error;
290 case ERR_UNKNMODE:
291 error = ERROR_BAD_NUMBER;
292 *error_string = MSG_UNKNCOMPMETHOD;
293 return error;
296 if (usum != Calc_CheckSum(b2, unpklen)) {
297 error = ERROR_BAD_NUMBER;
298 *error_string = MSG_BADCHECKSUM;
299 return error;
302 if (Write(out, b2, unpklen) != unpklen) {
303 return IoErr();
307 return NO_ERROR;
310 static UWORD unpack_track (struct xdms_data *xdms, UBYTE *b1, UBYTE *b2, UWORD pklen2, UWORD unpklen, UWORD cmode,
311 UBYTE flags)
313 switch (cmode) {
314 case 1:
315 if (Unpack_RLE(xdms, b1, b2, unpklen)) return ERR_BADDECR;
316 break;
317 case 2:
318 if (Unpack_QUICK(xdms, b1, b2, pklen2)) return ERR_BADDECR;
319 if (Unpack_RLE(xdms, b2, b1, unpklen)) return ERR_BADDECR;
320 case 0:
321 memcpy(b2, b1, unpklen);
322 break;
323 case 3:
324 if (Unpack_MEDIUM(xdms, b1, b2, pklen2)) return ERR_BADDECR;
325 if (Unpack_RLE(xdms, b2, b1, unpklen)) return ERR_BADDECR;
326 memcpy(b2, b1, unpklen);
327 break;
328 case 4:
329 if (Unpack_DEEP(xdms, b1, b2, pklen2)) return ERR_BADDECR;
330 if (Unpack_RLE(xdms, b2, b1, unpklen)) return ERR_BADDECR;
331 memcpy(b2, b1, unpklen);
332 break;
333 case 5:
334 case 6:
335 if (Unpack_HEAVY(xdms, b1, b2, (cmode == 5) ? (flags & 7) : (flags | 8), pklen2))
336 return ERR_BADDECR;
337 if (flags & 4) {
338 if (Unpack_RLE(xdms, b2, b1, unpklen)) return ERR_BADDECR;
339 memcpy(b2, b1, unpklen);
341 break;
342 default:
343 return ERR_UNKNMODE;
346 if (!(flags & 1)) Init_Decrunchers(xdms);
348 return NO_ERROR;
351 static void dms_decrypt (struct xdms_data *xdms, UBYTE *p, UWORD len) {
352 UWORD t;
353 while (len--) {
354 t = *p;
355 *p++ ^= (UBYTE)xdms->PWDCRC;
356 xdms->PWDCRC = (UWORD)((xdms->PWDCRC >> 1) + t);