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_MAXSTRLEN 4096
32 #define DD_MAXTABLE 4096
37 u16 oldcode
, oldest
, newest
;
38 u16 older
[DD_MAXTABLE
], newer
[DD_MAXTABLE
];
39 u16 charlink
[DD_MAXTABLE
]; // parent?
40 int usecount
[DD_MAXTABLE
]; // How many other codes depend on this code?
42 u8 valfirst
[DD_MAXTABLE
];
43 u8 value
[DD_MAXTABLE
];
49 struct de_dfilter_in_params
*dcmpri
;
50 struct de_dfilter_out_params
*dcmpro
;
51 struct de_dfilter_results
*dres
;
58 u8 valbuf
[DD_MAXTABLE
];
59 char msg
[DD_MAXSTRLEN
];
62 //*******************************************************************
63 static void dd_tmsg(struct dd_Ctl
*Ctl
, const char *fmt
, ...)
64 de_gnuc_attribute ((format (printf
, 2, 3)));
66 static void dd_tmsg(struct dd_Ctl
*Ctl
, const char *fmt
, ...)
70 if (Ctl
->c
->debug_level
<3) return;
73 de_vsnprintf(Ctl
->msg
, sizeof(Ctl
->msg
), fmt
, ap
);
76 de_dbg(Ctl
->c
, "%s", Ctl
->msg
);
79 //*******************************************************************
83 static void dd_dumpstate(struct dd_Ctl
*Ctl
, struct dd_codet
* ct
)
87 FILE *f
; // copy of dmpf->fp; do not close
90 de_snprintf(filename
, sizeof(filename
), "ddump%07"I64_FMT
".tmp", Ctl
->code_counter
);
91 dmpf
= dbuf_create_unmanaged_file(Ctl
->c
, filename
, DE_OVERWRITEMODE_DEFAULT
, 0);
94 fprintf(f
, "codes processed: %u\n", (UI
)Ctl
->code_counter
);
95 fprintf(f
, "code olde newe clin uc siz\n");
96 for(i
=0; i
<4096; i
++) {
97 fprintf(f
, "%4u %4u %4u %4u %2u %4u", (UI
)i
,
98 (UI
)ct
->older
[i
], (UI
)ct
->newer
[i
],
104 fprintf(f
, " %02x", (UI
)ct
->value
[i
]);
106 else if(ct
->size
[i
]==2) {
107 fprintf(f
, " %02x %02x", (UI
)ct
->valfirst
[i
], (UI
)ct
->value
[i
]);
109 else if(ct
->size
[i
]>2) {
110 fprintf(f
, " %02x...%02x", (UI
)ct
->valfirst
[i
], (UI
)ct
->value
[i
]);
113 if(i
==(size_t)ct
->oldcode
) fprintf(f
, " OLDCODE");
114 if(i
==(size_t)ct
->oldest
) fprintf(f
, " oldest");
115 if(i
==(size_t)ct
->newest
) fprintf(f
, " newest");
125 //*******************************************************************
126 static void dd_ValidateLinkChains (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
131 if(Ctl
->c
->debug_level
<3) return;
132 tnewer
= ct
->newer
[tcode
];
133 tolder
= ct
->older
[tcode
];
134 if (tcode
== ct
->newest
) {
140 if (ct
->older
[tnewer
] != tcode
) {
144 if (tcode
== ct
->oldest
) {
150 if (ct
->newer
[tolder
] != tcode
) {
156 dd_tmsg(Ctl
, "Link validation error (%u). tcode: %4x, older: %4x, newer: %4x",
157 errcode
, tcode
, tolder
, ct
->newer
[tolder
]);
161 //*******************************************************************
162 static void dd_OutputString(struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
165 size_t valbuf_pos
= DD_MAXTABLE
;
168 if(ct
->size
[tcode
]<1 || ct
->size
[tcode
]>DD_MAXTABLE
-256) {
173 for(i
=0; i
<(size_t)ct
->size
[tcode
]; i
++) {
174 if(curcode
>=DD_MAXTABLE
|| curcode
<1) {
179 if(ct
->size
[curcode
] != ct
->size
[tcode
]-i
) {
185 Ctl
->valbuf
[valbuf_pos
] = ct
->value
[curcode
];
187 // Traverse the tree, back toward the root codes.
188 curcode
= ct
->charlink
[curcode
];
191 dbuf_write(Ctl
->dcmpro
->f
, &Ctl
->valbuf
[valbuf_pos
], ct
->size
[tcode
]);
192 Ctl
->nbytes_written
+= (i64
)ct
->size
[tcode
];
198 //*******************************************************************
199 static u16
dd_GetNextcode (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
)
203 if(Ctl
->inf_pos
>= Ctl
->inf_endpos
) {
209 code
= (u16
)dbuf_getbyte_p(Ctl
->dcmpri
->f
, &Ctl
->inf_pos
) << 4;
210 ct
->hold
= (u16
)dbuf_getbyte_p(Ctl
->dcmpri
->f
, &Ctl
->inf_pos
);
211 code
|= (ct
->hold
>> 4);
214 code
= (ct
->hold
& 0x0f) << 8;
215 code
|= (u16
)dbuf_getbyte_p(Ctl
->dcmpri
->f
, &Ctl
->inf_pos
);
222 //*******************************************************************
223 static struct dd_codet
* dd_DInit (struct dd_Ctl
*Ctl
)
225 struct dd_codet
* ct
;
228 ct
= (struct dd_codet
*) de_malloc(Ctl
->c
, sizeof(struct dd_codet
));
229 for (code
= 1; code
<= 256; code
++) {
230 ct
->valfirst
[code
] = (u8
)(code
-1);
231 ct
->value
[code
] = (u8
)(code
-1);
233 // Maybe this is set to 1 just to prevent it from ever getting down
234 // to 0. So it doesn't get re-used.
235 ct
->usecount
[code
] = 1;
237 for (code
= 257; code
<= 4095; code
++) {
239 ct
->newer
[code
] = code
+ 1;
242 ct
->older
[code
] = code
- 1;
253 static void dd_DFree(struct dd_Ctl
*Ctl
, struct dd_codet
*ct
)
259 //*******************************************************************
260 static void dd_AddMRU (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
262 if (ct
->usecount
[tcode
] != 0) {
263 dd_tmsg(Ctl
, "Usecount not zero in AddMRU, code: %4x", tcode
);
265 ct
->newer
[ct
->newest
] = tcode
;
266 ct
->older
[tcode
] = ct
->newest
;
267 ct
->newer
[tcode
] = 0;
271 //*******************************************************************
272 static void dd_UnlinkCode (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
276 dd_ValidateLinkChains(Ctl
, ct
, ct
->oldest
);
277 tnewer
= ct
->newer
[tcode
];
278 tolder
= ct
->older
[tcode
];
279 if (tcode
== ct
->newest
)
282 ct
->older
[tnewer
] = tolder
;
283 if (tcode
== ct
->oldest
)
286 ct
->newer
[tolder
] = tnewer
;
287 ct
->older
[tcode
] = ct
->newer
[tcode
] = 0;
290 //*******************************************************************
291 static u16
dd_GetLRU (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
)
295 dd_ValidateLinkChains(Ctl
, ct
, ct
->oldest
);
297 if (ct
->usecount
[tcode
] != 0) {
298 dd_tmsg(Ctl
, "Usecount not zero in GetLRU, code: %4x", tcode
);
300 xcode
= ct
->charlink
[tcode
];
301 dd_UnlinkCode (Ctl
, ct
, tcode
);
304 ct
->usecount
[xcode
] --;
305 if (ct
->usecount
[xcode
] == 0) {
306 dd_AddMRU (Ctl
, ct
, xcode
);
313 //*******************************************************************
314 static void dd_ReserveEntry (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 tcode
)
316 if (ct
->usecount
[tcode
] > 0) {
317 ct
->usecount
[tcode
] ++;
320 dd_UnlinkCode(Ctl
, ct
, tcode
);
321 ct
->usecount
[tcode
] = 1;
325 //*******************************************************************
326 static void dd_BuildEntry (struct dd_Ctl
*Ctl
, struct dd_codet
* ct
, u16 newcode
)
333 lruentry
= dd_GetLRU(Ctl
, ct
);
334 old_codesize
= ct
->size
[ct
->oldcode
];
339 new_codesize
= old_codesize
+ 1;
340 if(new_codesize
> DD_MAXTABLE
) {
345 if (newcode
!= lruentry
) {
352 ct
->valfirst
[lruentry
] = ct
->valfirst
[ct
->oldcode
];
353 ct
->value
[lruentry
] = ct
->valfirst
[tcode
];
355 ct
->size
[lruentry
] = new_codesize
;
356 ct
->charlink
[lruentry
] = ct
->oldcode
;
357 dd_ReserveEntry(Ctl
, ct
, ct
->oldcode
);
358 ct
->usecount
[lruentry
] = 0;
359 dd_AddMRU (Ctl
, ct
, lruentry
);
363 de_free(Ctl
->c
, codestr
);
367 //*******************************************************************
368 static void dd_Decompress (struct dd_Ctl
*Ctl
)
370 struct dd_codet
* ct
;
376 newcode
= dd_GetNextcode(Ctl
, ct
);
377 if(Ctl
->c
->debug_level
>=3) {
378 de_dbg(Ctl
->c
, "%"I64_FMT
" [i%"I64_FMT
"/o%"I64_FMT
"] code=%u oc=%u",
380 Ctl
->inf_pos
, Ctl
->nbytes_written
,
381 (UI
)newcode
, (UI
)ct
->oldcode
);
383 if(newcode
==0 || Ctl
->eof_flag
|| Ctl
->err_flag
) break;
385 dd_BuildEntry(Ctl
, ct
, newcode
);
386 if(Ctl
->err_flag
) break;
387 dd_OutputString(Ctl
, ct
, newcode
);
388 ct
->oldcode
= newcode
;
393 de_dfilter_set_errorf(Ctl
->c
, Ctl
->dres
, Ctl
->modname
, "Bad compressed data");
398 static void dskdcmps_run(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
399 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
)
401 struct dd_Ctl
*Ctl
= NULL
;
403 Ctl
= de_malloc(c
, sizeof(struct dd_Ctl
));
405 Ctl
->modname
= "ibmlzw";
406 Ctl
->dcmpri
= dcmpri
;
407 Ctl
->dcmpro
= dcmpro
;
409 Ctl
->inf_pos
= dcmpri
->pos
;
410 Ctl
->inf_endpos
= dcmpri
->pos
+ dcmpri
->len
;