dmolony-DiskBrowser/src/com/bytezone/diskbrowser/applefile/ExoBuffer.java

329 lines
8.2 KiB
Java
Raw Normal View History

2020-06-23 04:23:53 +00:00
package com.bytezone.diskbrowser.applefile;
2020-06-24 02:22:40 +00:00
import com.bytezone.diskbrowser.utilities.Utility;
2020-06-23 04:23:53 +00:00
// pack::: ~/exomizer-3.0.2/src/exomizer mem -q -P23 -lnone LODE148@0x4000 -o LODE148c
// unpack: ~/exomizer-3.0.2/src/exomizer raw -d -b -P23 LODE148c,0,-2 -o LODE148x
// -----------------------------------------------------------------------------------//
public class ExoBuffer
2020-06-24 02:22:40 +00:00
// -----------------------------------------------------------------------------------//
2020-06-23 04:23:53 +00:00
{
2020-06-24 02:22:40 +00:00
private static final int PFLAG_BITS_ORDER_BE = 1;
private static final int PFLAG_BITS_COPY_GT_7 = 2;
private static final int PFLAG_IMPL_1LITERAL = 4;
private static final int PFLAG_BITS_ALIGN_START = 8;
private static final int PFLAG_4_OFFSET_TABLES = 16;
2020-06-23 04:23:53 +00:00
2020-06-23 23:08:11 +00:00
private byte[] inBuffer;
2020-06-24 21:28:16 +00:00
private byte[] outBuffer;
2020-06-23 21:31:29 +00:00
2020-06-23 23:08:11 +00:00
private int inPos;
private int outPos;
2020-06-26 22:40:40 +00:00
private int srcPtr;
2020-06-23 04:23:53 +00:00
2020-06-23 23:08:11 +00:00
private int bitBuffer;
private int flags;
2020-06-23 21:31:29 +00:00
2020-06-23 23:08:11 +00:00
private int tableBit[] = new int[8];
private int tableOff[] = new int[8];
private int tableBi[] = new int[100];
private int tableLo[] = new int[100];
private int tableHi[] = new int[100];
2020-06-23 21:31:29 +00:00
2020-10-28 05:42:48 +00:00
private static boolean debug = false;
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
public ExoBuffer (byte[] inBuffer)
// ---------------------------------------------------------------------------------//
{
2020-06-23 21:31:29 +00:00
this.inBuffer = inBuffer;
2020-06-24 21:33:15 +00:00
Utility.reverse (inBuffer);
2020-06-23 04:23:53 +00:00
switch (Utility.getShortBigEndian (inBuffer, 0))
2020-06-23 05:50:54 +00:00
{
case 0x6000:
2020-06-24 21:33:15 +00:00
outBuffer = new byte[0x2000]; // HGR
2020-06-24 21:28:16 +00:00
break;
2020-10-28 05:42:48 +00:00
case 0x8000:
2020-06-24 21:33:15 +00:00
outBuffer = new byte[0x4000]; // DHGR
2020-06-24 21:28:16 +00:00
break;
2020-10-28 05:42:48 +00:00
case 0xA000:
2020-06-24 21:33:15 +00:00
outBuffer = new byte[0x8000]; // SHR
2020-06-24 21:28:16 +00:00
break;
2020-10-28 05:42:48 +00:00
case 0x5FF8: // this is not working correctly - see CLODE019
return;
default:
System.out.printf ("Invalid buffer size: %04X%n",
Utility.getShortBigEndian (inBuffer, 0));
2020-06-23 05:50:54 +00:00
}
2020-06-23 23:08:11 +00:00
2020-06-24 21:28:16 +00:00
decrunch ();
2020-06-24 02:22:40 +00:00
Utility.reverse (outBuffer);
2020-06-23 04:23:53 +00:00
}
2020-06-23 05:50:54 +00:00
// ---------------------------------------------------------------------------------//
2020-06-24 02:22:40 +00:00
public byte[] getExpandedBuffer ()
2020-06-23 05:50:54 +00:00
// ---------------------------------------------------------------------------------//
2020-06-23 04:23:53 +00:00
{
2020-06-24 02:22:40 +00:00
return outBuffer;
2020-06-23 04:23:53 +00:00
}
// ---------------------------------------------------------------------------------//
2020-06-24 02:22:40 +00:00
public static boolean isExomizer (byte[] buffer, int auxType)
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
2020-06-24 21:28:16 +00:00
if (auxType != 0x1FF8 && auxType != 0x3FF8)
2020-10-28 05:42:48 +00:00
{
if (debug)
System.out.println ("wrong auxType");
2020-06-24 21:28:16 +00:00
return false;
2020-10-28 05:42:48 +00:00
}
2020-06-24 21:28:16 +00:00
int address = Utility.getShort (buffer, buffer.length - 2);
2020-06-24 21:28:16 +00:00
2020-06-25 04:50:29 +00:00
if (address != 0x6000 && address != 0x8000 && address != 0xA000)
2020-10-28 05:42:48 +00:00
{
if (debug)
System.out.printf ("wrong address: %04X%n", address);
2020-06-24 21:28:16 +00:00
return false;
2020-10-28 05:42:48 +00:00
}
2020-06-24 02:22:40 +00:00
2020-09-13 01:39:54 +00:00
return true;
2020-06-23 04:23:53 +00:00
}
// ---------------------------------------------------------------------------------//
2020-06-24 21:28:16 +00:00
private int bitBufRotate (int carryIn)
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
int carryOut;
2020-06-23 23:08:11 +00:00
if ((flags & PFLAG_BITS_ORDER_BE) != 0)
2020-06-23 04:23:53 +00:00
{
2020-06-24 02:22:40 +00:00
carryOut = (bitBuffer & 0x80) >>> 7;
2020-06-23 21:31:29 +00:00
bitBuffer = (bitBuffer << 1) & 0xFF;
2020-06-23 04:23:53 +00:00
2020-06-24 21:28:16 +00:00
if (carryIn != 0)
2020-06-23 21:31:29 +00:00
bitBuffer |= 0x01;
2020-06-23 04:23:53 +00:00
}
else
{
2020-06-23 21:31:29 +00:00
carryOut = bitBuffer & 0x01;
bitBuffer = (bitBuffer >>> 1) & 0xFF;
2020-06-23 04:23:53 +00:00
2020-06-24 21:28:16 +00:00
if (carryIn != 0)
2020-06-23 21:31:29 +00:00
bitBuffer |= 0x80;
2020-06-23 04:23:53 +00:00
}
return carryOut;
}
// ---------------------------------------------------------------------------------//
2020-06-23 21:31:29 +00:00
private int getByte ()
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
2020-06-23 23:08:11 +00:00
return inBuffer[inPos++] & 0xFF;
2020-06-23 04:23:53 +00:00
}
// ---------------------------------------------------------------------------------//
2020-06-23 21:31:29 +00:00
private int getBits (int count)
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
int byteCopy = 0;
int value = 0;
2020-06-23 23:08:11 +00:00
if ((flags & PFLAG_BITS_COPY_GT_7) != 0)
2020-06-23 04:23:53 +00:00
while (count > 7)
{
byteCopy = count >>> 3;
2020-06-26 22:40:40 +00:00
count &= 0x07;
2020-06-23 04:23:53 +00:00
}
while (count-- > 0)
{
2020-06-23 21:31:29 +00:00
int carry = bitBufRotate (0);
2020-06-23 04:23:53 +00:00
2020-06-23 21:31:29 +00:00
if (bitBuffer == 0)
2020-06-23 04:23:53 +00:00
{
2020-06-23 21:31:29 +00:00
bitBuffer = getByte ();
carry = bitBufRotate (1);
2020-06-23 04:23:53 +00:00
}
2020-06-24 02:22:40 +00:00
value = (value << 1) | carry;
2020-06-23 04:23:53 +00:00
}
while (byteCopy-- > 0)
2020-06-26 22:40:40 +00:00
value = (value << 8) | getByte ();
2020-06-23 04:23:53 +00:00
return value;
}
// ---------------------------------------------------------------------------------//
2020-06-23 21:31:29 +00:00
private void tableInit ()
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
int end;
int a = 0;
int b = 0;
2020-06-23 21:31:29 +00:00
tableBit[0] = 2;
tableBit[1] = 4;
tableBit[2] = 4;
2020-06-23 04:23:53 +00:00
2020-06-23 23:08:11 +00:00
if ((flags & PFLAG_4_OFFSET_TABLES) != 0)
2020-06-23 04:23:53 +00:00
{
end = 68;
2020-06-23 21:31:29 +00:00
tableBit[3] = 4;
2020-06-23 04:23:53 +00:00
2020-06-23 21:31:29 +00:00
tableOff[0] = 64;
tableOff[1] = 48;
tableOff[2] = 32;
tableOff[3] = 16;
2020-06-23 04:23:53 +00:00
}
else
{
end = 52;
2020-06-23 21:31:29 +00:00
tableOff[0] = 48;
tableOff[1] = 32;
tableOff[2] = 16;
2020-06-23 04:23:53 +00:00
}
for (int i = 0; i < end; i++)
{
if ((i & 0x0F) != 0)
a += (1 << b);
else
a = 1;
2020-06-23 21:31:29 +00:00
tableLo[i] = a & 0xFF;
tableHi[i] = a >>> 8;
2020-06-23 04:23:53 +00:00
2020-06-23 23:08:11 +00:00
if ((flags & PFLAG_BITS_COPY_GT_7) != 0)
2020-06-23 04:23:53 +00:00
{
2020-06-23 21:31:29 +00:00
b = getBits (3);
b |= getBits (1) << 3;
2020-06-23 04:23:53 +00:00
}
else
2020-06-23 21:31:29 +00:00
b = getBits (4);
2020-06-23 04:23:53 +00:00
2020-06-23 21:31:29 +00:00
tableBi[i] = b;
2020-06-23 04:23:53 +00:00
}
2020-06-26 22:40:40 +00:00
if (false)
tableDump ();
2020-06-23 04:23:53 +00:00
}
// ---------------------------------------------------------------------------------//
2020-06-23 21:31:29 +00:00
private void tableDump ()
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
for (int i = 0; i < 16; i++)
2020-06-23 21:31:29 +00:00
System.out.printf ("%X", tableBi[i]);
2020-06-23 04:23:53 +00:00
for (int j = 0; j < 3; j++)
{
System.out.printf (",");
2020-06-23 21:31:29 +00:00
int start = tableOff[j];
int end = start + (1 << tableBit[j]);
2020-06-23 04:23:53 +00:00
for (int i = start; i < end; i++)
2020-06-23 21:31:29 +00:00
System.out.printf ("%X", tableBi[i]);
2020-06-23 04:23:53 +00:00
}
System.out.println ();
}
// ---------------------------------------------------------------------------------//
2020-06-24 21:28:16 +00:00
private void decrunch ()
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
2020-06-26 22:40:40 +00:00
inPos = 2; // skip address
2020-06-24 02:22:40 +00:00
outPos = 0;
2020-06-26 22:40:40 +00:00
flags = 23; // hard-coded for Total Replay
2020-06-24 02:22:40 +00:00
if ((flags & PFLAG_BITS_ALIGN_START) != 0)
bitBuffer = 0;
else
bitBuffer = getByte ();
tableInit ();
2020-06-23 04:23:53 +00:00
int len;
2020-06-23 23:22:00 +00:00
boolean literal;
2020-06-23 23:08:11 +00:00
int threshold = (flags & PFLAG_4_OFFSET_TABLES) != 0 ? 4 : 3;
2020-06-23 04:23:53 +00:00
2020-06-23 23:08:11 +00:00
if ((flags & PFLAG_IMPL_1LITERAL) != 0)
2020-06-23 04:23:53 +00:00
{
len = 1;
2020-06-23 23:22:00 +00:00
literal = true;
2020-06-26 22:40:40 +00:00
copy (len, literal);
2020-06-23 04:23:53 +00:00
}
while (true)
{
2020-06-26 22:40:40 +00:00
if (getBits (1) == 1)
2020-06-23 04:23:53 +00:00
{
len = 1;
2020-06-23 23:22:00 +00:00
literal = true;
2020-06-23 04:23:53 +00:00
}
2020-06-23 22:41:47 +00:00
else
2020-06-23 04:23:53 +00:00
{
2020-06-26 22:40:40 +00:00
int val = getGammaCode (); // count zero bits
2020-06-23 22:41:47 +00:00
if (val == 16)
break;
if (val == 17)
{
len = getBits (16);
2020-06-23 23:22:00 +00:00
literal = true;
2020-06-23 22:41:47 +00:00
}
else
{
len = getCooked (val);
2020-06-23 23:22:00 +00:00
literal = false;
2020-06-23 23:08:11 +00:00
2020-06-23 22:41:47 +00:00
int i = (len > threshold ? threshold : len) - 1;
srcPtr = outPos - getCooked (tableOff[i] + getBits (tableBit[i]));
}
2020-06-23 04:23:53 +00:00
}
2020-06-26 22:40:40 +00:00
copy (len, literal);
2020-06-23 04:23:53 +00:00
}
2020-06-24 21:28:16 +00:00
assert outPos == outBuffer.length;
2020-06-23 04:23:53 +00:00
}
2020-06-23 23:08:11 +00:00
// ---------------------------------------------------------------------------------//
private int getGammaCode ()
// ---------------------------------------------------------------------------------//
{
int gammaCode = 0;
while (getBits (1) == 0)
++gammaCode;
return gammaCode;
}
// ---------------------------------------------------------------------------------//
private int getCooked (int index)
// ---------------------------------------------------------------------------------//
{
2020-06-26 22:40:40 +00:00
return ((tableHi[index] << 8) | tableLo[index]) + getBits (tableBi[index]);
2020-06-23 23:08:11 +00:00
}
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
2020-06-26 22:40:40 +00:00
private void copy (int len, boolean literal)
2020-06-23 04:23:53 +00:00
// ---------------------------------------------------------------------------------//
{
2020-06-26 22:40:40 +00:00
assert len > 0;
while (len-- > 0)
2020-06-23 04:23:53 +00:00
{
2020-06-26 22:40:40 +00:00
int val = literal ? getByte () : outBuffer[srcPtr++];
2020-06-23 21:31:29 +00:00
outBuffer[outPos++] = (byte) (val & 0xFF);
2020-06-26 22:40:40 +00:00
}
2020-06-23 04:23:53 +00:00
}
}