1 // See readme-dskdcmps.txt for more information about this file.
2 // Modifications for Deark are Copyright (C) 2021 Jason Summers, and have the
3 // same terms of use as the main part of Deark.
4 // Alternatively, at your option, the modifications for Deark may be treated
7 // Intro from the original software:
9 //*******************************************************************
11 // program - dskdcmps.c
12 // purpose - test decompression of dsk files
15 // LZW decompression - no warranties expressed or implied
16 // Note that this code was mainly a test to see if it could
17 // be done, and to understand how dsk files were compressed
18 // and if in turn they could be decompressed without creating
19 // diskettes (the entire reason for dskxtrct).
21 // Also note that there is some of confusion over the status of the
22 // patent for the LZW decompression algorithm. You use this code
25 //*******************************************************************
27 //#define PgmTitle "dskdcmps"
28 //#define PgmVersion "1.0 (08/01/2000)"
31 #define dd_max(a,b) (((a) > (b)) ? (a) : (b))
32 #define dd_strlen(a) ((int)de_strlen(a))
33 #define DD_MAXSTRLEN 4096
34 #define DD_MAXTABLE 4096
39 u16 oldcode
, oldest
, newest
;
40 u16 older
[DD_MAXTABLE
], newer
[DD_MAXTABLE
];
41 u16 charlink
[DD_MAXTABLE
], charlast
[DD_MAXTABLE
], charfirst
[DD_MAXTABLE
];
42 int used
[DD_MAXTABLE
], usecount
[DD_MAXTABLE
];
43 int size
[DD_MAXTABLE
];
44 u8
*code
[DD_MAXTABLE
]; // Points to .size[] malloc'd bytes
49 struct de_dfilter_in_params
*dcmpri
;
50 struct de_dfilter_out_params
*dcmpro
;
51 struct de_dfilter_results
*dres
;
57 char msg
[DD_MAXSTRLEN
];
59 char work
[DD_MAXSTRLEN
], work2
[DD_MAXSTRLEN
], work3
[DD_MAXSTRLEN
];
63 //*******************************************************************
64 static void dd_tmsg(struct dd_Ctl
*Ctl
, int tracelevel
, const char *fmt
, ...)
65 de_gnuc_attribute ((format (printf
, 3, 4)));
67 static void dd_tmsg(struct dd_Ctl
*Ctl
, int level
, const char *fmt
, ...)
71 if (level
> Ctl
->TraceLevel
)
75 de_vsnprintf(Ctl
->msg
, sizeof(Ctl
->msg
), fmt
, ap
);
78 de_dbg(Ctl
->c
, "%s", Ctl
->msg
);
81 //*******************************************************************
83 static char *dd_right (char *target
, char *source
, int len
)
92 slen
= dd_strlen(source
);
93 for (i
= dd_max(0, slen
- len
), tpos
= 0; i
< slen
; i
++)
94 target
[tpos
++] = source
[i
];
101 //*******************************************************************
102 static void dd_PrintEntry (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
104 dd_tmsg(Ctl
, 1, "Entry code: %4x, usecount: %4x, clink: %4x, clast: %4x, cfirst: %4x",
105 tcode
, ct
->usecount
[tcode
], ct
->charlink
[tcode
], ct
->charlast
[tcode
],
106 ct
->charfirst
[tcode
]);
107 dd_tmsg(Ctl
, 1, "older: %4x, newer: %4x, used: %4d, size: %4d",
108 ct
->older
[tcode
], ct
->newer
[tcode
], ct
->used
[tcode
], ct
->size
[tcode
]);
111 //*******************************************************************
112 static void dd_ValidateLinkChains (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
116 if(Ctl
->TraceLevel
<1) return;
117 tnewer
= ct
->newer
[tcode
];
118 tolder
= ct
->older
[tcode
];
119 if (tcode
== ct
->newest
) {
121 dd_tmsg(Ctl
, 1, "Newer code not zero. tcode: %4x, newer: %4x, older: %4x",
122 tcode
, tnewer
, ct
->older
[tnewer
]);
126 if (ct
->older
[tnewer
] != tcode
) {
127 dd_tmsg(Ctl
, 1, "Older code not linked. tcode: %4x, newer: %4x, older: %4x",
128 tcode
, tnewer
, ct
->older
[tnewer
]);
131 if (tcode
== ct
->oldest
) {
133 dd_tmsg(Ctl
, 1, "Older code not zero. tcode: %4x, older: %4x, newer: %4x",
134 tcode
, tolder
, ct
->newer
[tolder
]);
138 if (ct
->newer
[tolder
] != tcode
) {
139 dd_tmsg(Ctl
, 1, "Newer code not linked. tcode: %4x, older: %4x, newer: %4x",
140 tcode
, tolder
, ct
->newer
[tolder
]);
145 //*******************************************************************
146 static void dd_OutputString(struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
148 dbuf_write(Ctl
->dcmpro
->f
, (const u8
*)ct
->code
[tcode
], ct
->size
[tcode
]);
151 //*******************************************************************
152 static u16
dd_GetNextcode (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
)
156 if(Ctl
->inf_pos
>= Ctl
->inf_endpos
) {
162 code
= (u16
)dbuf_getbyte_p(Ctl
->dcmpri
->f
, &Ctl
->inf_pos
) << 4;
163 ct
->hold
= (u16
)dbuf_getbyte_p(Ctl
->dcmpri
->f
, &Ctl
->inf_pos
);
164 code
|= (ct
->hold
>> 4);
167 code
= (ct
->hold
& 0x0f) << 8;
168 code
|= (u16
)dbuf_getbyte_p(Ctl
->dcmpri
->f
, &Ctl
->inf_pos
);
175 //*******************************************************************
176 static struct dd_codet
* dd_DInit (struct dd_Ctl
*Ctl
)
178 struct dd_codet
* ct
;
181 ct
= (struct dd_codet
*) de_malloc(Ctl
->c
, sizeof(struct dd_codet
));
182 for (code
= 1; code
<= 256; code
++) {
183 ct
->charlast
[code
] = code
;
184 ct
->charfirst
[code
] = code
;
185 ct
->code
[code
] = (u8
*) de_malloc(Ctl
->c
, 1);
186 ct
->code
[code
][0] = (u8
)(code
-1);
188 ct
->usecount
[code
] = 1;
190 for (code
= 257; code
<= 4095; code
++) {
192 ct
->newer
[code
] = code
+ 1;
195 ct
->older
[code
] = code
- 1;
206 static void dd_DFree(struct dd_Ctl
*Ctl
, struct dd_codet
*ct
)
211 for(i
=0; i
<DD_MAXTABLE
; i
++) {
212 if (ct
->code
[i
] != NULL
) {
213 de_free(Ctl
->c
, ct
->code
[i
]);
221 //*******************************************************************
222 static void dd_AddMRU (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
224 if (ct
->usecount
[tcode
] != 0) {
225 dd_tmsg(Ctl
, 1, "Usecount not zero in AddMRU, code: %4x", tcode
);
226 dd_PrintEntry(Ctl
, ct
, tcode
);
228 ct
->newer
[ct
->newest
] = tcode
;
229 ct
->older
[tcode
] = ct
->newest
;
230 ct
->newer
[tcode
] = 0;
234 //*******************************************************************
235 static void dd_UnlinkCode (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
239 dd_ValidateLinkChains(Ctl
, ct
, ct
->oldest
);
240 tnewer
= ct
->newer
[tcode
];
241 tolder
= ct
->older
[tcode
];
242 if (tcode
== ct
->newest
)
245 ct
->older
[tnewer
] = tolder
;
246 if (tcode
== ct
->oldest
)
249 ct
->newer
[tolder
] = tnewer
;
250 ct
->older
[tcode
] = ct
->newer
[tcode
] = 0;
253 //*******************************************************************
254 static u16
dd_GetLRU (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
)
258 dd_ValidateLinkChains(Ctl
, ct
, ct
->oldest
);
260 if (ct
->usecount
[tcode
] != 0) {
261 dd_tmsg(Ctl
, 1, "Usecount not zero in GetLRU, code: %4x", tcode
);
262 dd_PrintEntry(Ctl
, ct
, tcode
);
264 xcode
= ct
->charlink
[tcode
];
265 dd_UnlinkCode (Ctl
, ct
, tcode
);
268 ct
->usecount
[xcode
] --;
269 if (ct
->usecount
[xcode
] == 0) {
270 dd_AddMRU (Ctl
, ct
, xcode
);
274 if (ct
->code
[tcode
] != NULL
) {
275 de_free(Ctl
->c
, ct
->code
[tcode
]);
276 ct
->code
[tcode
] = NULL
;
284 //*******************************************************************
285 static void dd_ReserveEntry (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
287 if (ct
->usecount
[tcode
] > 0) {
288 ct
->usecount
[tcode
] ++;
291 dd_UnlinkCode(Ctl
, ct
, tcode
);
292 ct
->usecount
[tcode
] = 1;
296 //*******************************************************************
297 static void dd_BuildEntry (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 newcode
)
304 lruentry
= dd_GetLRU(Ctl
, ct
);
305 old_codesize
= ct
->size
[ct
->oldcode
];
306 if(old_codesize
<1 || !ct
->code
[ct
->oldcode
]) {
310 new_codesize
= old_codesize
+ 1;
311 if(new_codesize
> DD_MAXTABLE
) {
315 // TODO?: This makes a huge total number of memory allocations (though only
316 // about 4096 will be active at any given time). Mabye it should be rewritten
318 codestr
= (u8
*) de_malloc(Ctl
->c
, new_codesize
);
319 de_memcpy(codestr
, ct
->code
[ct
->oldcode
], (size_t)old_codesize
);
320 if (newcode
!= lruentry
) {
326 if(!ct
->code
[tcode
]) {
330 codestr
[new_codesize
- 1] = ct
->code
[tcode
][0];
331 ct
->code
[lruentry
] = codestr
;
333 ct
->size
[lruentry
] = new_codesize
;
334 ct
->charlink
[lruentry
] = ct
->oldcode
;
335 ct
->charfirst
[lruentry
] = ct
->charfirst
[ct
->charlink
[lruentry
]];
336 ct
->charlast
[lruentry
] = tcode
;
337 dd_ReserveEntry(Ctl
, ct
, ct
->oldcode
);
338 dd_AddMRU (Ctl
, ct
, lruentry
);
341 if(Ctl
->TraceLevel
<1) return;
343 de_strlcpy(Ctl
->work
, "", sizeof(Ctl
->work
));
344 for (test
= 0; test
< new_codesize
; test
++) {
345 de_snprintf(Ctl
->work2
, sizeof(Ctl
->work2
), "%2x", codestr
[test
]);
346 dd_right(Ctl
->work3
, Ctl
->work2
, 2);
347 strcat(Ctl
->work
, Ctl
->work3
);
349 dd_tmsg(Ctl
, 1, "offset: %4x, newcode: %4x. nused: %4x, lru: %4x, lused: %4x, size: %4d, str: %s",
350 (UI
)Ctl
->inf_pos
, newcode
, ct
->used
[newcode
], lruentry
, ct
->used
[lruentry
], new_codesize
, Ctl
->work
);
355 de_free(Ctl
->c
, codestr
);
359 //*******************************************************************
360 static void dd_Decompress (struct dd_Ctl
*Ctl
)
362 struct dd_codet
* ct
;
368 newcode
= dd_GetNextcode(Ctl
, ct
);
369 if(newcode
==0 || Ctl
->eof_flag
|| Ctl
->err_flag
) break;
371 dd_BuildEntry(Ctl
, ct
, newcode
);
372 if(Ctl
->err_flag
) break;
373 dd_OutputString(Ctl
, ct
, newcode
);
374 ct
->oldcode
= newcode
;
378 de_dfilter_set_errorf(Ctl
->c
, Ctl
->dres
, "dskdcmprs", "Bad compressed data");
383 static void dskdcmps_run(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
384 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
)
386 struct dd_Ctl
*Ctl
= NULL
;
388 Ctl
= de_malloc(c
, sizeof(struct dd_Ctl
));
390 Ctl
->dcmpri
= dcmpri
;
391 Ctl
->dcmpro
= dcmpro
;
393 Ctl
->inf_pos
= dcmpri
->pos
;
394 Ctl
->inf_endpos
= dcmpri
->pos
+ dcmpri
->len
;
396 if(c
->debug_level
>=3) {