1308 lines
36 KiB
JavaScript
1308 lines
36 KiB
JavaScript
/*-------------------------------------------------------------------------
|
|
| SAE - Scripted Amiga Emulator
|
|
| https://github.com/naTmeg/ScriptedAmigaEmulator
|
|
|
|
|
| Copyright (C) 2012-2016 Rupert Hausberger
|
|
|
|
|
| This program is free software; you can redistribute it and/or
|
|
| modify it under the terms of the GNU General Public License
|
|
| as published by the Free Software Foundation; either version 2
|
|
| of the License, or (at your option) any later version.
|
|
|
|
|
| This program is distributed in the hope that it will be useful,
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| GNU General Public License for more details.
|
|
|
|
|
| Notes: ported from WinUAE 3.2.x
|
|
|
|
|
| xDMS v1.3 - Portable DMS archive unpacker - Public Domain
|
|
| Written by Andre Rodrigues de la Rocha <adlroc@usa.net>
|
|
|
|
|
| Handles the processing of a single DMS archive
|
|
-------------------------------------------------------------------------*/
|
|
|
|
function SAEO_DMS() {
|
|
const DMS_LOG = 0 ? true : false;
|
|
|
|
/* Functions return codes */
|
|
const NO_PROBLEM = 0;
|
|
const DMS_FILE_END = 1;
|
|
const ERR_NOMEMORY = 2;
|
|
const ERR_CANTOPENIN = 3;
|
|
const ERR_CANTOPENOUT = 4;
|
|
const ERR_NOTDMS = 5;
|
|
const ERR_SREAD = 6;
|
|
const ERR_HCRC = 7;
|
|
const ERR_NOTTRACK = 8;
|
|
const ERR_BIGTRACK = 9;
|
|
const ERR_THCRC = 10;
|
|
const ERR_TDCRC = 11;
|
|
const ERR_CSUM = 12;
|
|
const ERR_CANTWRITE = 13;
|
|
const ERR_BADDECR = 14;
|
|
const ERR_UNKNMODE = 15;
|
|
const ERR_NOPASSWD = 16;
|
|
const ERR_BADPASSWD = 17;
|
|
const ERR_FMS = 18;
|
|
const ERR_GZIP = 19;
|
|
const ERR_READDISK = 20;
|
|
|
|
/* Command to execute */
|
|
const CMD_VIEW = 1;
|
|
const CMD_VIEWFULL = 2;
|
|
const CMD_SHOWDIZ = 3;
|
|
const CMD_SHOWBANNER = 4;
|
|
const CMD_TEST = 5;
|
|
const CMD_UNPACK = 6;
|
|
const CMD_UNPKGZ = 7;
|
|
const CMD_EXTRACT = 8;
|
|
|
|
const OPT_VERBOSE = 1;
|
|
const OPT_QUIET = 2;
|
|
|
|
/*---------------------------------*/
|
|
/* support */
|
|
|
|
const d_code = [
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
|
0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
|
|
0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
|
0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
|
|
0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
|
|
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
|
|
0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
|
|
0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
|
|
0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
|
|
0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
|
|
0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
|
|
0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
|
|
0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
|
|
0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
|
|
0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
|
|
0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
|
|
];
|
|
const d_len = [
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
|
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
|
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
|
|
];
|
|
|
|
const LOC_QUICK = 0;
|
|
const LOC_MEDIUM = 1;
|
|
const LOC_HEAVY = 2;
|
|
const LOC_DEEP = 3;
|
|
var dms_loc = new Uint16Array(4); //OWN
|
|
|
|
const dms_mask_bits = [
|
|
0x000000,0x000001,0x000003,0x000007,0x00000f,0x00001f,
|
|
0x00003f,0x00007f,0x0000ff,0x0001ff,0x0003ff,0x0007ff,
|
|
0x000fff,0x001fff,0x003fff,0x007fff,0x00ffff,0x01ffff,
|
|
0x03ffff,0x07ffff,0x0fffff,0x1fffff,0x3fffff,0x7fffff,
|
|
0xffffff
|
|
];
|
|
var dms_indata = null;
|
|
var dms_indata_pos = 0; //OWN
|
|
var dms_bitcount = 0;
|
|
var dms_bitbuf = 0; //u32
|
|
|
|
function GETBITS(n) {
|
|
return (dms_bitbuf >>> (dms_bitcount - n)) & 0xffff;
|
|
}
|
|
function DROPBITS(n) {
|
|
dms_bitcount -= n;
|
|
dms_bitbuf = dms_bitbuf & dms_mask_bits[dms_bitcount];
|
|
while (dms_bitcount < 16) {
|
|
dms_bitbuf = ((dms_bitbuf << 8) | dms_indata[dms_indata_pos++]) >>> 0;
|
|
dms_bitcount += 8;
|
|
}
|
|
}
|
|
|
|
function initbitbuf(id) {
|
|
dms_bitbuf = 0;
|
|
dms_bitcount = 0;
|
|
dms_indata = id;
|
|
dms_indata_pos = 0;
|
|
DROPBITS(0);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* Run Length Encoding */
|
|
|
|
function Unpack_RLE(src, dst, origsize) {
|
|
var srco = 0, dsto = 0;
|
|
var n = 0; //u16
|
|
var a = 0, b = 0;
|
|
|
|
while (dsto < origsize){
|
|
if ((a = src[srco++]) != 0x90)
|
|
dst[dsto++] = a;
|
|
else if (!(b = src[srco++]))
|
|
dst[dsto++] = a;
|
|
else {
|
|
a = src[srco++];
|
|
if (b == 0xff) {
|
|
n = src[srco++];
|
|
n = (n << 8) + src[srco++];
|
|
} else
|
|
n = b;
|
|
if (dsto + n > origsize) return 1;
|
|
//memset(dst,a,n);
|
|
SAEF_memset(dst,dsto, a, n);
|
|
dsto += n;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* Quick */
|
|
|
|
const QBITMASK = 0xff;
|
|
|
|
function Unpack_QUICK(src, dst, origsize){
|
|
var dsto = 0;
|
|
var i = 0, j = 0;
|
|
|
|
initbitbuf(src);
|
|
while (dsto < origsize) {
|
|
if (GETBITS(1) != 0) {
|
|
DROPBITS(1);
|
|
dst[dsto++] = dms_text[dms_loc[LOC_QUICK]++ & QBITMASK] = GETBITS(8) & 0xff; DROPBITS(8);
|
|
} else {
|
|
DROPBITS(1);
|
|
j = GETBITS(2) + 2; DROPBITS(2);
|
|
i = dms_loc[LOC_QUICK] - GETBITS(8) - 1; DROPBITS(8);
|
|
while (j--) {
|
|
dst[dsto++] = dms_text[dms_loc[LOC_QUICK]++ & QBITMASK] = dms_text[i++ & QBITMASK];
|
|
}
|
|
}
|
|
}
|
|
dms_loc[LOC_QUICK] = dms_loc[LOC_QUICK] + 5 & QBITMASK;
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* Medium */
|
|
|
|
const MBITMASK = 0x3fff;
|
|
|
|
function Unpack_MEDIUM(src, dst, origsize) {
|
|
var dsto = 0;
|
|
var i = 0, j = 0, c = 0;
|
|
|
|
initbitbuf(src);
|
|
while (dsto < origsize) {
|
|
if (GETBITS(1) != 0) {
|
|
DROPBITS(1);
|
|
dst[dsto++] = dms_text[dms_loc[LOC_MEDIUM]++ & MBITMASK] = GETBITS(8) & 0xff;
|
|
DROPBITS(8);
|
|
} else {
|
|
DROPBITS(1);
|
|
c = GETBITS(8); DROPBITS(8);
|
|
j = d_code[c] + 3;
|
|
u = d_len[c];
|
|
c = ((c << u) | GETBITS(u)) & 0xff; DROPBITS(u);
|
|
u = d_len[c];
|
|
c = (d_code[c] << 8) | (((c << u) | GETBITS(u)) & 0xff); DROPBITS(u);
|
|
i = dms_loc[LOC_MEDIUM] - c - 1;
|
|
|
|
while (j--) dst[dsto++] = dms_text[dms_loc[LOC_MEDIUM]++ & MBITMASK] = dms_text[i++ & MBITMASK];
|
|
|
|
}
|
|
}
|
|
dms_loc[LOC_MEDIUM] = dms_loc[LOC_MEDIUM] + 66 & MBITMASK;
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* Deep, Lempel-Ziv-DynamicHuffman decompression */
|
|
|
|
const DBITMASK = 0x3fff; /* uses 16Kb dictionary */
|
|
|
|
const F = 60; /* lookahead buffer size */
|
|
const THRESHOLD = 2;
|
|
const N_CHAR = 256 - THRESHOLD + F; /* kinds of characters (character code = 0..N_CHAR-1) */
|
|
|
|
const T = N_CHAR * 2 - 1; /* size of table */
|
|
const R = T - 1; /* position of root */
|
|
const MAX_FREQ = 0x8000; /* updates tree when the */
|
|
|
|
var freq = new Uint16Array(T + 1); /* frequency table */
|
|
/* pointers to parent nodes, except for the */
|
|
/* elements [T..T + N_CHAR - 1] which are used to get */
|
|
/* the positions of leaves corresponding to the codes. */
|
|
var prnt = new Uint16Array(T + N_CHAR);
|
|
var son = new Uint16Array(T); /* pointers to child nodes (son[], son[] + 1) */
|
|
|
|
var dms_init_deep_tabs = true;
|
|
|
|
|
|
function Init_DEEP_Tabs(){
|
|
for (var i = 0; i < N_CHAR; i++) {
|
|
freq[i] = 1;
|
|
son[i] = i + T;
|
|
prnt[i + T] = i;
|
|
}
|
|
i = 0;
|
|
var j = N_CHAR;
|
|
while (j <= R) {
|
|
freq[j] = freq[i] + freq[i + 1];
|
|
son[j] = i;
|
|
prnt[i] = prnt[i + 1] = j;
|
|
i += 2; j++;
|
|
}
|
|
freq[T] = 0xffff;
|
|
prnt[R] = 0;
|
|
|
|
dms_init_deep_tabs = false;
|
|
}
|
|
|
|
/* reconstruction of tree */
|
|
function reconst(){
|
|
var i = 0, j = 0, k = 0, f = 0, l = 0, m = 0;
|
|
|
|
/* collect leaf nodes in the first half of the table */
|
|
/* and replace the freq by (freq + 1) / 2. */
|
|
for (i = 0; i < T; i++) {
|
|
if (son[i] >= T) {
|
|
freq[j] = (freq[i] + 1) >> 1;
|
|
son[j] = son[i];
|
|
j++;
|
|
}
|
|
}
|
|
/* begin constructing tree by connecting sons */
|
|
for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
|
|
k = i + 1;
|
|
f = freq[j] = freq[i] + freq[k];
|
|
for (k = j - 1; f < freq[k]; k--);
|
|
k++;
|
|
//l = (j - k) << 1;
|
|
l = j - k;
|
|
//memmove(&freq[k + 1], &freq[k], (size_t)l);
|
|
for (m = l; m >= 0; m--) freq[k + m + 1] = freq[k + m];
|
|
freq[k] = f;
|
|
//memmove(&son[k + 1], &son[k], (size_t)l);
|
|
for (m = l; m >= 0; m--) son[k + m + 1] = son[k + m];
|
|
son[k] = i;
|
|
}
|
|
/* connect prnt */
|
|
for (i = 0; i < T; i++) {
|
|
if ((k = son[i]) >= T) {
|
|
prnt[k] = i;
|
|
} else {
|
|
prnt[k] = prnt[k + 1] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* increment frequency of given code by one, and update tree */
|
|
function update(c){
|
|
var i = 0, j = 0, k = 0, l = 0;
|
|
|
|
if (freq[R] == MAX_FREQ)
|
|
reconst();
|
|
|
|
c = prnt[c + T];
|
|
do {
|
|
k = ++freq[c];
|
|
|
|
/* if the order is disturbed, exchange nodes */
|
|
if (k > freq[l = c + 1]) {
|
|
while (k > freq[++l]);
|
|
l--;
|
|
freq[c] = freq[l];
|
|
freq[l] = k;
|
|
|
|
i = son[c];
|
|
prnt[i] = l;
|
|
if (i < T) prnt[i + 1] = l;
|
|
|
|
j = son[l];
|
|
son[l] = i;
|
|
|
|
prnt[j] = c;
|
|
if (j < T) prnt[j + 1] = c;
|
|
son[c] = j;
|
|
|
|
c = l;
|
|
}
|
|
} while ((c = prnt[c]) != 0); /* repeat up to root */
|
|
}
|
|
|
|
function DecodeChar(){
|
|
var c = son[R];
|
|
/* travel from root to leaf, */
|
|
/* choosing the smaller child node (son[]) if the read bit is 0, */
|
|
/* the bigger (son[]+1} if 1 */
|
|
while (c < T) {
|
|
c = son[c + GETBITS(1)];
|
|
DROPBITS(1);
|
|
}
|
|
c -= T;
|
|
update(c);
|
|
return c;
|
|
}
|
|
|
|
function DecodePosition(){
|
|
var i = GETBITS(8); DROPBITS(8);
|
|
var c = d_code[i] << 8;
|
|
var j = d_len[i];
|
|
i = ((i << j) | GETBITS(j)) & 0xff; DROPBITS(j);
|
|
return c | i;
|
|
}
|
|
|
|
function Unpack_DEEP(src, dst, origsize){
|
|
var dsto = 0;
|
|
var i = 0, j = 0, c = 0;
|
|
|
|
initbitbuf(src);
|
|
if (dms_init_deep_tabs)
|
|
Init_DEEP_Tabs();
|
|
|
|
while (dsto < origsize) {
|
|
c = DecodeChar();
|
|
if (c < 256) {
|
|
dst[dsto++] = dms_text[dms_loc[LOC_DEEP]++ & DBITMASK] = c & 0xff;
|
|
} else {
|
|
j = c - 255 + THRESHOLD;
|
|
i = dms_loc[LOC_DEEP] - DecodePosition() - 1;
|
|
while (j--) dst[dsto++] = dms_text[dms_loc[LOC_DEEP]++ & DBITMASK] = dms_text[i++ & DBITMASK];
|
|
}
|
|
}
|
|
dms_loc[LOC_DEEP] = dms_loc[LOC_DEEP] + 60 & DBITMASK;
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* Heavy, Lempel-Ziv-Huffman decompression */
|
|
|
|
const NC = 510;
|
|
const NPT = 20;
|
|
const N1 = 510;
|
|
const OFFSET = 253;
|
|
|
|
var c_len = new Uint8Array(NC);
|
|
var c_table = new Uint16Array(4096);
|
|
var pt_len = new Uint8Array(NPT);
|
|
var pt_table = new Uint16Array(256);
|
|
|
|
var dms_left = new Uint16Array(2 * NC - 1);
|
|
var dms_right = new Uint16Array(2 * NC - 1 + 9);
|
|
var dms_lastlen = 0, dms_np = 0; //u16
|
|
|
|
function dms_make_table(nchar, bitlen, tablebits, table) {
|
|
var c = 0; //s16
|
|
var n = 0, tblsiz = 0, len = 0, depth = 0, maxdepth = 0, avail = 0; //u16
|
|
var codeword = 0, bit = 0, tbl = null, err = 0; //u16
|
|
var blen = null; //u8 *
|
|
|
|
function mktbl() {
|
|
var i = 0;
|
|
|
|
if (err) return 0;
|
|
|
|
if (len == depth) {
|
|
while (++c < n)
|
|
if (blen[c] == len) {
|
|
i = codeword;
|
|
codeword += bit;
|
|
if (codeword > tblsiz) {
|
|
err = 1;
|
|
return 0;
|
|
}
|
|
while (i < codeword) tbl[i++] = c;
|
|
return c;
|
|
}
|
|
c = -1;
|
|
len++;
|
|
bit >>= 1;
|
|
}
|
|
depth++;
|
|
if (depth < maxdepth) {
|
|
mktbl();
|
|
mktbl();
|
|
} else if (depth > 32) {
|
|
err = 2;
|
|
return 0;
|
|
} else {
|
|
if ((i = avail++) >= 2 * n - 1) {
|
|
err = 3;
|
|
return 0;
|
|
}
|
|
dms_left[i] = mktbl();
|
|
dms_right[i] = mktbl();
|
|
if (codeword >= tblsiz) {
|
|
err = 4;
|
|
return 0;
|
|
}
|
|
if (depth == maxdepth) tbl[codeword++] = i;
|
|
}
|
|
depth--;
|
|
return i;
|
|
}
|
|
|
|
n = avail = nchar;
|
|
blen = bitlen;
|
|
tbl = table;
|
|
tblsiz = 1 << tablebits;
|
|
bit = tblsiz >> 1;
|
|
maxdepth = tablebits + 1;
|
|
depth = len = 1;
|
|
c = -1;
|
|
codeword = 0;
|
|
err = 0;
|
|
mktbl(); // left subtree
|
|
if (err) return err;
|
|
mktbl(); // right subtree
|
|
if (err) return err;
|
|
if (codeword != tblsiz) return 5;
|
|
return 0;
|
|
}
|
|
|
|
function read_tree_c() {
|
|
var n = GETBITS(9);
|
|
DROPBITS(9);
|
|
if (n > 0) {
|
|
for (var i = 0; i < n; i++) {
|
|
c_len[i] = GETBITS(5) & 0xff;
|
|
DROPBITS(5);
|
|
}
|
|
for (i = n; i < 510; i++) c_len[i] = 0;
|
|
if (dms_make_table(510, c_len, 12, c_table)) return 1;
|
|
} else {
|
|
n = GETBITS(9);
|
|
DROPBITS(9);
|
|
for (var i = 0; i < 510; i++) c_len[i] = 0;
|
|
for (i = 0; i < 4096; i++) c_table[i] = n;
|
|
}
|
|
return 0;
|
|
}
|
|
function read_tree_p() {
|
|
var n = GETBITS(5);
|
|
DROPBITS(5);
|
|
if (n > 0){
|
|
for (var i = 0; i < n; i++) {
|
|
pt_len[i] = GETBITS(4) & 0xff;
|
|
DROPBITS(4);
|
|
}
|
|
for (i = n; i < dms_np; i++) pt_len[i] = 0;
|
|
if (dms_make_table(dms_np, pt_len, 8, pt_table)) return 1;
|
|
} else {
|
|
n = GETBITS(5);
|
|
DROPBITS(5);
|
|
for (var i = 0; i < dms_np; i++) pt_len[i] = 0;
|
|
for (i = 0; i < 256; i++) pt_table[i] = n;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function decode_c(){
|
|
var j = c_table[GETBITS(12)];
|
|
if (j < N1) {
|
|
DROPBITS(c_len[j]);
|
|
} else {
|
|
DROPBITS(12);
|
|
var i = GETBITS(16);
|
|
var m = 0x8000;
|
|
do {
|
|
if (i & m) j = dms_right[j];
|
|
else j = dms_left [j];
|
|
m >>= 1;
|
|
} while (j >= N1);
|
|
DROPBITS(c_len[j] - 12);
|
|
}
|
|
return j;
|
|
}
|
|
function decode_p(){
|
|
var j = pt_table[GETBITS(8)];
|
|
if (j < dms_np) {
|
|
DROPBITS(pt_len[j]);
|
|
} else {
|
|
DROPBITS(8);
|
|
var i = GETBITS(16);
|
|
var m = 0x8000;
|
|
do {
|
|
if (i & m) j = dms_right[j];
|
|
else j = dms_left [j];
|
|
m >>= 1;
|
|
} while (j >= dms_np);
|
|
DROPBITS(pt_len[j] - 8);
|
|
}
|
|
if (j != dms_np-1) {
|
|
if (j > 0) {
|
|
j = GETBITS(i = j-1) | (1 << (j-1));
|
|
DROPBITS(i);
|
|
}
|
|
dms_lastlen = j;
|
|
}
|
|
return dms_lastlen;
|
|
}
|
|
|
|
function Unpack_HEAVY(src, dst, flags, origsize){
|
|
/* Heavy 1 uses a 4Kb dictionary, Heavy 2 uses 8Kb */
|
|
if (flags & 8) {
|
|
dms_np = 15;
|
|
var bitmask = 0x1fff;
|
|
} else {
|
|
dms_np = 14;
|
|
var bitmask = 0x0fff;
|
|
}
|
|
initbitbuf(src);
|
|
|
|
if (flags & 2) {
|
|
if (read_tree_c()) return 1;
|
|
if (read_tree_p()) return 2;
|
|
}
|
|
|
|
var dsto = 0;
|
|
while (dsto < origsize) {
|
|
var c = decode_c();
|
|
if (c < 256) {
|
|
dst[dsto++] = dms_text[dms_loc[LOC_HEAVY]++ & bitmask] = c;
|
|
} else {
|
|
var j = c - OFFSET;
|
|
var i = dms_loc[LOC_HEAVY] - decode_p() - 1;
|
|
while (j--) dst[dsto++] = dms_text[dms_loc[LOC_HEAVY]++ & bitmask] = dms_text[i++ & bitmask];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function Init_Decrunchers() {
|
|
dms_loc[LOC_QUICK] = 251;
|
|
|
|
dms_loc[LOC_MEDIUM] = 0x3fbe;
|
|
|
|
dms_loc[LOC_HEAVY] = 0;
|
|
dms_lastlen = 0;
|
|
dms_np = 0;
|
|
|
|
dms_loc[LOC_DEEP] = 0x3fc4;
|
|
dms_init_deep_tabs = true;
|
|
|
|
//memset(dms_text,0,0x3fc8);
|
|
SAEF_memset(dms_text,0, 0, 0x3fc8);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
const HEADLEN = 56;
|
|
const THLEN = 20;
|
|
const TRACK_BUFFER_LEN = 32000;
|
|
const TEMP_BUFFER_LEN = 32000;
|
|
|
|
const DMSFLAG_ENCRYPTED = 2;
|
|
const DMSFLAG_HD = 16;
|
|
|
|
const DMS_MAX_EXTRA = 10;
|
|
|
|
const modes = ["NOCOMP", "SIMPLE", "QUICK ", "MEDIUM", "DEEP ", "HEAVY1", "HEAVY2"];
|
|
|
|
var PWDCRC = 0; //u16
|
|
var passfound = 0, passretries = 0;
|
|
|
|
var dms_text = null; //u8 *
|
|
|
|
/*---------------------------------*/
|
|
|
|
function ctime(t){
|
|
var a = new Date(t * 1000);
|
|
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
|
var year = a.getFullYear();
|
|
var month = months[a.getMonth()];
|
|
var date = a.getDate();
|
|
var hour = a.getHours();
|
|
var min = a.getMinutes();
|
|
var sec = a.getSeconds();
|
|
return date + ' ' + month + ' ' + year + ' ' + sprintf("%02d:%02d:%02d", hour, min, sec);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function log_error(track) {
|
|
SAEF_warn("DMS() Ignored error on track %d!\n", track);
|
|
}
|
|
|
|
function printbandiz(m, len) {
|
|
/*UCHAR *i, *j;
|
|
i = j = m;
|
|
while (i < m + len) {
|
|
if (*i == 10) {
|
|
*i = 0;
|
|
TCHAR *u = au ((char*)j);
|
|
SAEF_log("%s\n",u);
|
|
xfree(u);
|
|
j = i + 1;
|
|
}
|
|
i++;
|
|
}*/
|
|
if (DMS_LOG)
|
|
SAEF_log(SAEF_Array2String(m, 0, len));
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function dms_Calc_CheckSum(mem, size){
|
|
var u = 0; //u16
|
|
var p = 0;
|
|
while (size--) {
|
|
u += mem[p++];
|
|
if (u > 0xffff) u -= 0x10000;
|
|
}
|
|
return u; //(u & 0xffff);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
const CRCTab = [
|
|
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
|
|
0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
|
|
0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
|
|
0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
|
|
0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
|
|
0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
|
|
0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
|
|
0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
|
|
0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
|
|
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
|
|
0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
|
|
0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
|
|
0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
|
|
0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
|
|
0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
|
|
0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
|
|
0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
|
|
0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
|
|
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
|
|
0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
|
|
0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
|
|
0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
|
|
0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
|
|
0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
|
|
0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
|
|
0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
|
|
0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
|
|
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
|
|
0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
|
|
0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
|
|
0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
|
|
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
|
|
];
|
|
function dms_CreateCRC(mem,memo, size) {
|
|
var CRC = 0;
|
|
|
|
while (size--)
|
|
CRC = CRCTab[(CRC ^ mem[memo++]) & 255] ^ ((CRC >> 8) & 255);
|
|
|
|
return CRC;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function addextra(name, extra, p, size) {
|
|
if (extra === null)
|
|
return;
|
|
for (var i = 0; i < DMS_MAX_EXTRA; i++) {
|
|
if (extra[i] === null)
|
|
break;
|
|
}
|
|
if (i == DMS_MAX_EXTRA)
|
|
return;
|
|
var zf = SAEF_ZFile_fopen_empty(null, name, size);
|
|
if (zf === null)
|
|
return;
|
|
SAEF_ZFile_fwrite(p,0, size, 1, zf);
|
|
SAEF_ZFile_fseek(zf, 0, SEEK_SET);
|
|
extra[i] = zf;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
/* DMS uses a lame encryption */
|
|
function dms_decrypt(p, len, src){
|
|
var srco = 0, po = 0;
|
|
var t = 0; //u16
|
|
|
|
while (len--) {
|
|
t = src[srco++];
|
|
p[po++] = t ^ (PWDCRC & 0xff);
|
|
PWDCRC = ((PWDCRC >> 1) + t) & 0xffff;
|
|
}
|
|
}
|
|
|
|
function Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags){
|
|
switch (cmode){
|
|
case 0:
|
|
/* No Compression */
|
|
b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen);
|
|
break;
|
|
case 1:
|
|
/* Simple Compression */
|
|
if (Unpack_RLE(b1, b2, unpklen)) return ERR_BADDECR;
|
|
break;
|
|
case 2:
|
|
/* Quick Compression */
|
|
if (Unpack_QUICK(b1, b2, pklen2)) return ERR_BADDECR;
|
|
if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR;
|
|
b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen);
|
|
break;
|
|
case 3:
|
|
/* Medium Compression */
|
|
if (Unpack_MEDIUM(b1, b2, pklen2)) return ERR_BADDECR;
|
|
if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR;
|
|
b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen);
|
|
break;
|
|
case 4:
|
|
/* Deep Compression */
|
|
if (Unpack_DEEP(b1, b2, pklen2)) return ERR_BADDECR;
|
|
if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR;
|
|
b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen);
|
|
break;
|
|
case 5:
|
|
case 6:
|
|
/* Heavy Compression */
|
|
if (cmode == 5) {
|
|
/* Heavy 1 */
|
|
if (Unpack_HEAVY(b1,b2,flags & 7,pklen2)) return ERR_BADDECR;
|
|
} else {
|
|
/* Heavy 2 */
|
|
if (Unpack_HEAVY(b1,b2,flags | 8,pklen2)) return ERR_BADDECR;
|
|
}
|
|
if (flags & 4) {
|
|
//memset(b1, 0, unpklen);
|
|
SAEF_memset(b1,0, 0, unpklen);
|
|
/* Unpack with RLE only if this flag is set */
|
|
if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR;
|
|
b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen);
|
|
}
|
|
break;
|
|
default:
|
|
return ERR_UNKNMODE;
|
|
}
|
|
if (!(flags & 1))
|
|
Init_Decrunchers();
|
|
|
|
return NO_PROBLEM;
|
|
}
|
|
|
|
var pass = 0;
|
|
function Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum1, enc) {
|
|
//static USHORT pass;
|
|
var r = 0, err = NO_PROBLEM;
|
|
var prevpass = 0;
|
|
|
|
if (passfound) {
|
|
if (number != 80)
|
|
dms_decrypt(b1, pklen1, b1);
|
|
r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags);
|
|
if (r == NO_PROBLEM) {
|
|
if (usum1 == dms_Calc_CheckSum(b2, unpklen))
|
|
return NO_PROBLEM;
|
|
}
|
|
log_error(number);
|
|
if (passretries <= 0)
|
|
return ERR_CSUM;
|
|
}
|
|
|
|
passretries--;
|
|
var pwrounds = 0;
|
|
var maybeencrypted = 0;
|
|
//UCHAR *tmp = (unsigned char*)malloc (pklen1);
|
|
var tmp = new Uint8Array(pklen1);
|
|
tmp.set(b1.subarray(0, pklen1)); //memcpy(tmp, b1, pklen1);
|
|
//memset(b2, 0, unpklen);
|
|
SAEF_memset(b2,0, 0, unpklen);
|
|
for (;;) {
|
|
r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags);
|
|
if (r == NO_PROBLEM) {
|
|
if (usum1 == dms_Calc_CheckSum(b2, unpklen)) {
|
|
passfound = maybeencrypted;
|
|
if (passfound)
|
|
SAEF_log("DMS() decryption key = 0x%04X\n", prevpass);
|
|
err = NO_PROBLEM;
|
|
pass = prevpass;
|
|
break;
|
|
}
|
|
}
|
|
if (number == 80 || !enc) {
|
|
err = ERR_CSUM;
|
|
break;
|
|
}
|
|
maybeencrypted = 1;
|
|
prevpass = pass;
|
|
PWDCRC = pass;
|
|
pass++;
|
|
dms_decrypt(b1, pklen1, tmp);
|
|
pwrounds++;
|
|
if (pwrounds == 65536) {
|
|
err = ERR_CSUM;
|
|
passfound = 0;
|
|
break;
|
|
}
|
|
}
|
|
//free(tmp);
|
|
return err;
|
|
}
|
|
|
|
function Process_Track(fi, fo, b1, b2, cmd, opt, dmsflags, extra){
|
|
var crcerr = 0;
|
|
|
|
var l = SAEF_ZFile_fread(b1,0, 1, THLEN, fi);
|
|
if (l != THLEN) {
|
|
if (l == 0)
|
|
return DMS_FILE_END;
|
|
else
|
|
return ERR_SREAD;
|
|
}
|
|
|
|
/* "TR" identifies a Track Header */
|
|
if ((b1[0] != 84) || (b1[1] != 82))
|
|
return ERR_NOTTRACK;
|
|
|
|
/* Track Header CRC */
|
|
var hcrc = ((b1[THLEN-2] << 8) | b1[THLEN-1]);
|
|
|
|
if (dms_CreateCRC(b1,0, THLEN-2) != hcrc)
|
|
return ERR_THCRC;
|
|
|
|
var number = (b1[2] << 8) | b1[3]; /* Number of track */
|
|
var pklen1 = (b1[6] << 8) | b1[7]; /* Length of packed track data as in archive */
|
|
var pklen2 = (b1[8] << 8) | b1[9]; /* Length of data after first unpacking */
|
|
var unpklen = (b1[10] << 8) | b1[11]; /* Length of data after subsequent rle unpacking */
|
|
var flags = b1[12]; /* control flags */
|
|
var cmode = b1[13]; /* compression mode used */
|
|
var usum = (b1[14] << 8) | b1[15]; /* Track Data CheckSum AFTER unpacking */
|
|
var dcrc = (b1[16] << 8) | b1[17]; /* Track Data CRC BEFORE unpacking */
|
|
|
|
//if (DMS_LOG) SAEF_log("DMS() track=%d\n", number);
|
|
|
|
if (DMS_LOG) {
|
|
var out = "";
|
|
if (number == 80)
|
|
out += " FileID ";
|
|
else if (number == 0xffff)
|
|
out += " Banner ";
|
|
else if ((number == 0) && (unpklen == 1024))
|
|
out += " FakeBB ";
|
|
else
|
|
out += sprintf(" %2d ", number);
|
|
|
|
out += sprintf("%5d %5d %s %04X %04X %04X %0d", pklen1, unpklen, modes[cmode], usum, hcrc, dcrc, flags);
|
|
SAEF_log(out);
|
|
}
|
|
|
|
if ((pklen1 > TRACK_BUFFER_LEN) || (pklen2 > TRACK_BUFFER_LEN) || (unpklen > TRACK_BUFFER_LEN))
|
|
return ERR_BIGTRACK;
|
|
|
|
if (SAEF_ZFile_fread(b1,0, 1, pklen1, fi) != pklen1)
|
|
return ERR_SREAD;
|
|
|
|
if (dms_CreateCRC(b1,0, pklen1) != dcrc) {
|
|
log_error(number);
|
|
crcerr = 1;
|
|
}
|
|
/* track 80 is FILEID.DIZ, track 0xffff (-1) is Banner */
|
|
/* and track 0 with 1024 bytes only is a fake boot block with more advertising */
|
|
/* FILE_ID.DIZ is never encrypted */
|
|
|
|
//if (pwd && (number!=80)) dms_decrypt(b1,pklen1); ORG
|
|
|
|
var normaltrack = false;
|
|
if ((cmd == CMD_UNPACK) && (number < 80) && (unpklen > 2048)) {
|
|
//memset(b2, 0, unpklen);
|
|
SAEF_memset(b2,0, 0, unpklen);
|
|
if (!crcerr)
|
|
Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED);
|
|
|
|
if (number == 0 && SAEF_ZFile_ftell(fo) == 512 * 22) {
|
|
// did we have another cylinder 0 already?
|
|
SAEF_ZFile_fseek(fo, 0, SEEK_SET);
|
|
//uae_u8 *p = xcalloc (uae_u8, 512 * 22);
|
|
var p = new Uint8Array(512 * 22);
|
|
SAEF_ZFile_fread(p,0, 512 * 22, 1, fo);
|
|
addextra("BigFakeBootBlock", extra, p, 512 * 22);
|
|
//xfree(p);
|
|
delete p;
|
|
}
|
|
SAEF_ZFile_fseek(fo, number * 512 * 22 * ((dmsflags & DMSFLAG_HD) ? 2 : 1), SEEK_SET);
|
|
if (SAEF_ZFile_fwrite(b2,0, 1, unpklen, fo) != unpklen)
|
|
return ERR_CANTWRITE;
|
|
normaltrack = true;
|
|
} else if (number == 0 && unpklen == 1024) {
|
|
b2.set(0, 0, unpklen); //memset(b2, 0, unpklen);
|
|
if (!crcerr)
|
|
Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED);
|
|
addextra("FakeBootBlock", extra, b2, unpklen);
|
|
}
|
|
|
|
if (crcerr)
|
|
return NO_PROBLEM;
|
|
|
|
if (number == 0xffff) {
|
|
Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED);
|
|
if (extra)
|
|
addextra("Banner", extra, b2, unpklen);
|
|
|
|
printbandiz(b2, unpklen);
|
|
}
|
|
|
|
if (number == 80) {
|
|
Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED);
|
|
if (extra)
|
|
addextra("FILEID.DIZ", extra, b2, unpklen);
|
|
|
|
printbandiz(b2, unpklen);
|
|
}
|
|
|
|
if (!normaltrack)
|
|
Init_Decrunchers();
|
|
|
|
return NO_PROBLEM;
|
|
}
|
|
|
|
function DMS_Process_File(fi, fo, cmd, opt, PCRC, pwd, part, extra) {
|
|
passfound = 0;
|
|
passretries = 2;
|
|
/*UCHAR *b1 = xcalloc(UCHAR,TRACK_BUFFER_LEN);
|
|
if (!b1) return ERR_NOMEMORY;
|
|
UCHAR *b2 = xcalloc(UCHAR,TRACK_BUFFER_LEN);
|
|
if (!b2) {
|
|
free(b1);
|
|
return ERR_NOMEMORY;
|
|
}
|
|
dms_text = xcalloc(UCHAR,TEMP_BUFFER_LEN);
|
|
if (!dms_text) {
|
|
free(b1);
|
|
free(b2);
|
|
return ERR_NOMEMORY;
|
|
}*/
|
|
b1 = new Uint8Array(TRACK_BUFFER_LEN);
|
|
b2 = new Uint8Array(TRACK_BUFFER_LEN);
|
|
dms_text = new Uint8Array(TEMP_BUFFER_LEN);
|
|
|
|
if (SAEF_ZFile_fread(b1,0, 1, HEADLEN, fi) != HEADLEN) {
|
|
/*free(b1);
|
|
free(b2);
|
|
free(dms_text);*/
|
|
dms_text = null;
|
|
return ERR_SREAD;
|
|
}
|
|
|
|
/* Check the first 4 bytes of file to see if it is "DMS!" */
|
|
//if ((b1[0] != 'D') || (b1[1] != 'M') || (b1[2] != 'S') || (b1[3] != '!')) {
|
|
if (!(b1[0] == 68 && b1[1] == 77 && b1[2] == 83 && b1[3] == 33)) { /* DMS! */
|
|
/*free(b1);
|
|
free(b2);
|
|
free(dms_text);*/
|
|
dms_text = null;
|
|
return ERR_NOTDMS;
|
|
}
|
|
|
|
/* Header CRC */
|
|
var hcrc = (b1[HEADLEN - 2] << 8) | b1[HEADLEN - 1];
|
|
if (hcrc != dms_CreateCRC(b1,4, HEADLEN - 6)) {
|
|
/*free(b1);
|
|
free(b2);
|
|
free(dms_text);*/
|
|
dms_text = null;
|
|
return ERR_HCRC;
|
|
}
|
|
|
|
var geninfo = (b1[10] << 8) | b1[11]; /* General info about archive */
|
|
var date = (((b1[12]) << 24) | ((b1[13]) << 16) | ((b1[14]) << 8) | b1[15]) >>> 0; /* date in standard UNIX/ANSI format */
|
|
var low = (b1[16] << 8) | b1[17]; /* Lowest track in archive. May be incorrect if archive is "appended" */
|
|
var high = (b1[18] << 8) | b1[19]; /* Highest track in archive. May be incorrect if archive is "appended" */
|
|
|
|
if (part && low < 30) {
|
|
/*free(b1);
|
|
free(b2);
|
|
free(dms_text);*/
|
|
dms_text = null;
|
|
return DMS_FILE_END;
|
|
}
|
|
|
|
var pkfsize = (((b1[21]) << 16) | ((b1[22]) << 8) | b1[23]) >>> 0; /* Length of total packed data as in archive */
|
|
var unpkfsize = (((b1[25]) << 16) | ((b1[26]) << 8) | b1[27]) >>> 0; /* Length of unpacked data. Usually 901120 bytes */
|
|
|
|
var c_version = (b1[46] << 8) | b1[47]; /* version of DMS used to generate it */
|
|
var disktype = (b1[50] << 8) | b1[51]; /* Type of compressed disk */
|
|
var cmode = (b1[52] << 8) | b1[53]; /* Compression mode mostly used in this archive */
|
|
|
|
PWDCRC = PCRC;
|
|
|
|
if (DMS_LOG) {
|
|
var pv = Math.floor(c_version / 100);
|
|
SAEF_log(" Created with DMS version %d.%02d %s\n", pv, c_version - pv * 100, (geninfo & 0x80) ? "Registered" : "Evaluation");
|
|
SAEF_log(" Creation date : %s", ctime(date));
|
|
SAEF_log(" Lowest track in archive : %d\n", low);
|
|
SAEF_log(" Highest track in archive : %d\n", high);
|
|
SAEF_log(" Packed data size : %d\n", pkfsize);
|
|
SAEF_log(" Unpacked data size : %d\n", unpkfsize);
|
|
|
|
var out = " Disk type of archive : ";
|
|
/* The original DMS from SDS software (DMS up to 1.11) used other values */
|
|
/* in disk type to indicate formats as MS-DOS, AMax and Mac, but it was */
|
|
/* not suported for compression. It was for future expansion and was never */
|
|
/* used. The newer versions of DMS made by ParCon Software changed it to */
|
|
/* add support for new Amiga disk types. */
|
|
switch (disktype) {
|
|
case 0:
|
|
case 1:
|
|
/* Can also be a non-dos disk */
|
|
out += "AmigaOS 1.0 OFS\n";
|
|
break;
|
|
case 2:
|
|
out += "AmigaOS 2.0 FFS\n";
|
|
break;
|
|
case 3:
|
|
out += "AmigaOS 3.0 OFS / International\n";
|
|
break;
|
|
case 4:
|
|
out += "AmigaOS 3.0 FFS / International\n";
|
|
break;
|
|
case 5:
|
|
out += "AmigaOS 3.0 OFS / Dir Cache\n";
|
|
break;
|
|
case 6:
|
|
out += "AmigaOS 3.0 FFS / Dir Cache\n";
|
|
break;
|
|
case 7:
|
|
out += "FMS Amiga System File\n";
|
|
break;
|
|
default:
|
|
out += "Unknown\n";
|
|
}
|
|
SAEF_log(out);
|
|
|
|
out = " Compression mode used : ";
|
|
if (cmode > 6)
|
|
out += "Unknown !\n";
|
|
else
|
|
out += modes[cmode] + "\n";
|
|
SAEF_log(out);
|
|
|
|
out = " General info : ";
|
|
if ((geninfo == 0) || (geninfo == 0x80)) out += "None";
|
|
if (geninfo & 1) out += "NoZero ";
|
|
if (geninfo & 2) out += "Encrypted ";
|
|
if (geninfo & 4) out += "Appends ";
|
|
if (geninfo & 8) out += "Banner ";
|
|
if (geninfo & 16) out += "HD ";
|
|
if (geninfo & 32) out += "MS-DOS ";
|
|
if (geninfo & 64) out += "DMS_DEV_Fixed ";
|
|
if (geninfo & 256) out += "FILEID.DIZ";
|
|
out += "\n";
|
|
SAEF_log(out);
|
|
|
|
SAEF_log(" Info Header CRC : %04X\n\n", hcrc);
|
|
}
|
|
|
|
if (disktype == 7) {
|
|
/* It's not a DMS compressed disk image, but a FMS archive */
|
|
/*free(b1);
|
|
free(b2);
|
|
free(dms_text);*/
|
|
dms_text = null;
|
|
return ERR_FMS;
|
|
}
|
|
|
|
if (DMS_LOG) {
|
|
SAEF_log(" Track Plength Ulength Cmode USUM HCRC DCRC Cflag\n");
|
|
SAEF_log(" ------ ------- ------- ------ ---- ---- ---- -----\n");
|
|
}
|
|
|
|
// if (((cmd==CMD_UNPACK) || (cmd==CMD_SHOWBANNER)) && (geninfo & 2) && (!pwd))
|
|
// return ERR_NOPASSWD;
|
|
|
|
var ret = NO_PROBLEM;
|
|
|
|
Init_Decrunchers();
|
|
|
|
if (cmd != CMD_VIEW) {
|
|
if (cmd == CMD_SHOWBANNER) /* Banner is in the first track */
|
|
ret = Process_Track(fi, null, b1, b2, cmd, opt, geninfo, extra);
|
|
else {
|
|
Init_Decrunchers();
|
|
for (;;) {
|
|
ret = Process_Track(fi, fo, b1, b2, cmd, opt, geninfo, extra);
|
|
if (ret == DMS_FILE_END)
|
|
break;
|
|
if (ret == NO_PROBLEM)
|
|
continue;
|
|
break;
|
|
/*#if 0
|
|
int ok = 0;
|
|
while (!ok) {
|
|
uae_u8 b1[THLEN];
|
|
|
|
if (SAEF_ZFile_fread(b1,1,THLEN,fi) != 1) {
|
|
SAEF_log(_T("DMS() unexpected end of file\n"));
|
|
break;
|
|
}
|
|
SAEF_log(_T("DMS() corrupted track, searching for next track header..\n"));
|
|
if (b1[0] == 'T' && b1[1] == 'R') {
|
|
USHORT hcrc = (USHORT)((b1[THLEN-2] << 8) | b1[THLEN-1]);
|
|
if (CreateCRC(b1,(ULONG)(THLEN-2)) == hcrc) {
|
|
SAEF_log(_T("DMS() found checksum correct track header, retrying..\n"));
|
|
SAEF_ZFile_fseek (fi, SEEK_CUR, -THLEN);
|
|
ok = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!ok)
|
|
SAEF_ZFile_fseek (fi, SEEK_CUR, -(THLEN - 1));
|
|
}
|
|
#endif*/
|
|
}
|
|
}
|
|
}
|
|
if ((cmd == CMD_VIEWFULL) || (cmd == CMD_SHOWDIZ) || (cmd == CMD_SHOWBANNER))
|
|
SAEF_log("\n");
|
|
|
|
if (ret == DMS_FILE_END)
|
|
ret = NO_PROBLEM;
|
|
|
|
/* Used to give an error message, but I have seen some DMS */
|
|
/* files with texts or zeros at the end of the valid data */
|
|
/* So, when we find something that is not a track header, */
|
|
/* we suppose that the valid data is over. And say it's ok. */
|
|
if (ret == ERR_NOTTRACK)
|
|
ret = NO_PROBLEM;
|
|
|
|
/*free(b1);
|
|
free(b2);
|
|
free(dms_text);*/
|
|
dms_text = null;
|
|
return ret;
|
|
}
|
|
|
|
this.DMS2ADF = function(z, index, retcode) {
|
|
if (typeof index == "undefined") index = 0;
|
|
if (typeof retcode == "undefined") retcode = null;
|
|
//static int recursive;
|
|
var orgname = SAEF_ZFile_getname(z);
|
|
var newname = "";
|
|
var zextra = new Array(DMS_MAX_EXTRA); //zfile *
|
|
for (var vi = 0; vi < DMS_MAX_EXTRA; vi++)
|
|
zextra[vi] = null;
|
|
|
|
//if (checkwrite(z, retcode)) return null;
|
|
//if (recursive) return null;
|
|
|
|
var ext = orgname.lastIndexOf('.');
|
|
if (ext != -1) {
|
|
newname = orgname.substr(0, ext);
|
|
newname += ".ADF";
|
|
} else
|
|
newname = orgname + ".ADF";
|
|
|
|
var zo = SAEF_ZFile_fopen_empty(z, newname, 1760 * 512);
|
|
if (zo === null)
|
|
return null;
|
|
|
|
pass = 0;
|
|
var ret = DMS_Process_File(z, zo, CMD_UNPACK, OPT_VERBOSE, 0, null, false, zextra);
|
|
if (ret == NO_PROBLEM) { // || ret == DMS_FILE_END) {
|
|
/*var off = SAEF_ZFile_ftell(zo);
|
|
if (off >= Math.floor(1760 * 512 / 3) && off <= Math.floor(1760 * 512 * 3 / 4)) { // possible split dms?
|
|
if (_tcslen (orgname) > 5) {
|
|
TCHAR *s = orgname + _tcslen (orgname) - 5;
|
|
if (!_tcsicmp (s, _T("a.dms"))) {
|
|
TCHAR *fn2 = my_strdup (orgname);
|
|
struct zfile *z2;
|
|
fn2[_tcslen (fn2) - 5]++;
|
|
recursive++;
|
|
z2 = SAEF_ZFile_fopen(fn2, _T("rb"), z->zfdmask);
|
|
recursive--;
|
|
if (z2) {
|
|
ret = DMS_Process_File(z2, zo, CMD_UNPACK, OPT_VERBOSE, 0, null, true, null);
|
|
SAEF_ZFile_fclose (z2);
|
|
}
|
|
xfree (fn2);
|
|
}
|
|
}
|
|
}*/
|
|
|
|
SAEF_ZFile_fseek(zo, 0, SEEK_SET);
|
|
if (index > 0) {
|
|
SAEF_ZFile_fclose(zo);
|
|
zo = null;
|
|
for (var i = 0; i < DMS_MAX_EXTRA && zextra[i]; i++);
|
|
if (index > i) {
|
|
//goto end;
|
|
for (i = 0; i < DMS_MAX_EXTRA; i++)
|
|
SAEF_ZFile_fclose(zextra[i]);
|
|
return zo;
|
|
}
|
|
zo = zextra[index - 1];
|
|
zextra[index - 1] = null;
|
|
}
|
|
|
|
//if (retcode !== null) *retcode = 1;
|
|
|
|
SAEF_ZFile_fclose(z);
|
|
z = null;
|
|
|
|
SAEF_log("DMS() converted '%s' to '%s'", orgname, newname);
|
|
} else {
|
|
SAEF_ZFile_fclose(zo);
|
|
zo = null;
|
|
|
|
//SAEF_warn("DMS() error converting '%s' (%d)", orgname, ret);
|
|
alert(sprintf("Can't convert '%s' to ADF. (error %d)", orgname, ret));
|
|
}
|
|
//end:
|
|
for (var i = 0; i < DMS_MAX_EXTRA; i++)
|
|
SAEF_ZFile_fclose(zextra[i]);
|
|
|
|
return zo;
|
|
}
|
|
}
|