dmolony-DiskBrowser/src/com/bytezone/diskbrowser/infocom/ZString.java

166 lines
4.5 KiB
Java
Executable File

package com.bytezone.diskbrowser.infocom;
// -----------------------------------------------------------------------------------//
class ZString
// -----------------------------------------------------------------------------------//
{
private static String[] letters =
{ " abcdefghijklmnopqrstuvwxyz", " ABCDEFGHIJKLMNOPQRSTUVWXYZ",
" 0123456789.,!?_#\'\"/\\-:()" };
String value;
Header header;
int startPtr;
int length;
// ---------------------------------------------------------------------------------//
ZString (Header header, int offset)
// ---------------------------------------------------------------------------------//
{
ZStringBuilder text = new ZStringBuilder ();
this.header = header;
this.startPtr = offset;
while (true)
{
if (offset >= header.buffer.length - 1)
{
System.out.println ("********" + text.toString ());
break;
}
// get the next two bytes
int val = header.getWord (offset);
// process each zChar as a 5-bit value
text.processZChar ((byte) ((val >>> 10) & 0x1F));
text.processZChar ((byte) ((val >>> 5) & 0x1F));
text.processZChar ((byte) (val & 0x1F));
if ((val & 0x8000) != 0) // bit 15 = finished flag
{
length = offset - startPtr + 2;
value = text.toString ();
break;
}
offset += 2;
}
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return value;
}
// ---------------------------------------------------------------------------------//
private class ZStringBuilder
// ---------------------------------------------------------------------------------//
{
int alphabet;
boolean shift;
int shiftAlphabet;
int synonym;
int buildingLevel;
int builtLetter;
StringBuilder text = new StringBuilder ();
private void processZChar (byte zchar)
{
// A flag to indicate that we are building a character not in the alphabet. The
// value indicates which half of the character the current zchar goes into. Once
// both halves are full, we use the ascii value in builtLetter.
if (buildingLevel > 0)
{
builtLetter = (short) ((builtLetter << 5) | zchar);
if (++buildingLevel == 3)
{
text.append ((char) builtLetter);
buildingLevel = 0;
}
return;
}
// A flag to indicate that we need to insert an abbreviation. The synonym value
// (1-3) indicates which abbreviation block to use, and the current zchar is the
// offset within that block.
if (synonym > 0)
{
text.append (header.getAbbreviation ((synonym - 1) * 32 + zchar));
synonym = 0;
return;
}
if ((shift && shiftAlphabet == 2) || (!shift && alphabet == 2))
{
if (zchar == 6)
{
buildingLevel = 1;
builtLetter = 0;
shift = false;
return;
}
if (zchar == 7)
{
text.append ("\n");
shift = false;
return;
}
}
// zChar values 0-5 have special meanings, and 6-7 are special only in alphabet #2.
// Otherwise it's just a straight lookup into the current alphabet.
switch (zchar)
{
case 0:
text.append (" ");
shift = false;
return;
case 1:
synonym = zchar;
return;
case 2:
case 3:
if (header.version >= 3)
{
synonym = zchar;
return;
}
// version 1 or 2
shiftAlphabet = (alphabet + zchar - 1) % 3;
shift = true;
return;
case 4:
case 5:
if (header.version >= 3) // shift key
{
shiftAlphabet = zchar - 3;
shift = true;
}
else // shift lock key
alphabet = (alphabet + zchar - 3) % 3;
return;
default:
if (shift)
{
text.append (letters[shiftAlphabet].charAt (zchar));
shift = false;
}
else
text.append (letters[alphabet].charAt (zchar));
return;
}
}
@Override
public String toString ()
{
return text.toString ();
}
}
}