2015-06-01 09:35:51 +00:00
|
|
|
package com.bytezone.diskbrowser.applefile;
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
2016-02-24 21:11:14 +00:00
|
|
|
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
|
|
|
public class TextFile extends AbstractFile
|
|
|
|
{
|
2017-02-01 21:15:30 +00:00
|
|
|
private int recordLength; // prodos aux
|
|
|
|
private List<TextBuffer> buffers; // only used if it is a Prodos text file
|
2015-06-01 09:35:51 +00:00
|
|
|
private int eof;
|
2017-02-01 21:15:30 +00:00
|
|
|
private boolean prodosFile;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
|
|
|
public TextFile (String name, byte[] buffer)
|
|
|
|
{
|
|
|
|
super (name, buffer);
|
|
|
|
}
|
|
|
|
|
2017-02-01 21:15:30 +00:00
|
|
|
public TextFile (String name, byte[] buffer, int auxType, int eof)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
|
|
|
this (name, buffer);
|
|
|
|
this.eof = eof;
|
2017-02-01 21:15:30 +00:00
|
|
|
recordLength = auxType;
|
|
|
|
prodosFile = true;
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 21:15:30 +00:00
|
|
|
public TextFile (String name, List<TextBuffer> buffers, int auxType, int eof)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
|
|
|
super (name, null);
|
|
|
|
this.buffers = buffers;
|
|
|
|
this.eof = eof;
|
2017-02-01 21:15:30 +00:00
|
|
|
recordLength = auxType;
|
|
|
|
prodosFile = true;
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getHexDump ()
|
|
|
|
{
|
|
|
|
if (buffers == null)
|
|
|
|
return (super.getHexDump ());
|
|
|
|
|
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
for (TextBuffer tb : buffers)
|
|
|
|
{
|
|
|
|
for (int i = 0, rec = 0; i < tb.buffer.length; i += tb.reclen, rec++)
|
|
|
|
{
|
|
|
|
text.append ("\nRecord #" + (tb.firstRecNo + rec) + "\n");
|
|
|
|
text.append (HexFormatter.format (tb.buffer, i, tb.reclen) + "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getText ()
|
|
|
|
{
|
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
|
|
|
|
text.append ("Name : " + name + "\n");
|
2017-02-01 21:15:30 +00:00
|
|
|
if (prodosFile)
|
2015-06-01 09:35:51 +00:00
|
|
|
{
|
|
|
|
text.append (String.format ("Record length : %,8d%n", recordLength));
|
|
|
|
text.append (String.format ("End of file : %,8d%n", eof));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
text.append (String.format ("End of file : %,8d%n", buffer.length));
|
|
|
|
text.append ("\n");
|
|
|
|
|
|
|
|
// check whether file is spread over multiple buffers
|
|
|
|
if (buffers != null)
|
2017-04-26 08:04:48 +00:00
|
|
|
return treeFileText (text); // calls knownLength()
|
2015-06-01 09:35:51 +00:00
|
|
|
|
|
|
|
// check whether the record length is known
|
|
|
|
if (recordLength == 0)
|
|
|
|
return unknownLength (text);
|
|
|
|
|
2017-04-26 08:04:48 +00:00
|
|
|
text.append ("Offset Record# Text values\n");
|
2017-02-01 21:15:30 +00:00
|
|
|
text.append (
|
|
|
|
"------ ------- -------------------------------------------------------\n");
|
2015-06-01 09:35:51 +00:00
|
|
|
return knownLength (text, 0).toString ();
|
|
|
|
}
|
|
|
|
|
|
|
|
private String treeFileText (StringBuilder text)
|
|
|
|
{
|
2017-04-26 08:04:48 +00:00
|
|
|
text.append (" Offset Record# Text values\n");
|
|
|
|
text.append (
|
|
|
|
"---------- ------- -------------------------------------------------------\n");
|
2015-06-01 09:35:51 +00:00
|
|
|
for (TextBuffer tb : buffers)
|
|
|
|
{
|
2017-04-26 08:04:48 +00:00
|
|
|
buffer = tb.buffer;
|
2017-07-09 09:26:13 +00:00
|
|
|
text = knownLength (text, tb.firstRecNo);
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
|
|
|
|
private StringBuilder knownLength (StringBuilder text, int recNo)
|
|
|
|
{
|
|
|
|
for (int ptr = 0; ptr < buffer.length; ptr += recordLength)
|
|
|
|
{
|
|
|
|
if (buffer[ptr] == 0)
|
|
|
|
{
|
|
|
|
recNo++;
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-09 09:26:13 +00:00
|
|
|
|
2015-06-01 09:35:51 +00:00
|
|
|
int len = buffer.length - ptr;
|
|
|
|
int bytes = len < recordLength ? len : recordLength;
|
|
|
|
|
|
|
|
while (buffer[ptr + bytes - 1] == 0)
|
|
|
|
bytes--;
|
|
|
|
|
2017-04-26 08:04:48 +00:00
|
|
|
if ((buffer[ptr + bytes - 1] & 0x7F) == 0x0D) // ignore CR
|
|
|
|
bytes--;
|
|
|
|
|
2017-07-09 09:26:13 +00:00
|
|
|
String line = HexFormatter.getString (buffer, ptr, bytes);
|
|
|
|
line = line.replaceAll ("\\n", "\n ");
|
|
|
|
text.append (
|
|
|
|
String.format ("%,10d %,8d %s%n", recNo * recordLength, recNo++, line));
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
2017-07-09 09:26:13 +00:00
|
|
|
|
2015-06-01 09:35:51 +00:00
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
private String unknownLength (StringBuilder text)
|
|
|
|
{
|
|
|
|
int nulls = 0;
|
|
|
|
int ptr = 0;
|
|
|
|
int size = buffer.length;
|
|
|
|
int lastVal = 0;
|
|
|
|
boolean newFormat = true;
|
2017-04-26 08:04:48 +00:00
|
|
|
boolean showAllOffsets = true;
|
2015-06-01 09:35:51 +00:00
|
|
|
|
|
|
|
if (newFormat)
|
|
|
|
{
|
2017-04-26 08:04:48 +00:00
|
|
|
text.append (" Offset Text values\n");
|
|
|
|
text.append ("---------- -------------------------------------------------------"
|
2017-02-01 21:15:30 +00:00
|
|
|
+ "-------------------\n");
|
2017-04-26 08:04:48 +00:00
|
|
|
if (buffer.length == 0)
|
2015-06-01 09:35:51 +00:00
|
|
|
return text.toString ();
|
|
|
|
|
2017-04-26 08:04:48 +00:00
|
|
|
if (buffer[0] != 0)
|
|
|
|
text.append (String.format ("%,10d ", ptr));
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 08:04:48 +00:00
|
|
|
int gcd = 0;
|
|
|
|
|
2015-06-01 09:35:51 +00:00
|
|
|
while (ptr < size)
|
|
|
|
{
|
2017-03-17 11:03:56 +00:00
|
|
|
int val = buffer[ptr++] & 0x7F; // strip hi-order bit
|
2015-06-01 09:35:51 +00:00
|
|
|
if (val == 0)
|
|
|
|
++nulls;
|
2017-03-17 11:03:56 +00:00
|
|
|
else if (val == 0x0D) // carriage return
|
2015-06-01 09:35:51 +00:00
|
|
|
text.append ("\n");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (nulls > 0)
|
|
|
|
{
|
|
|
|
if (newFormat)
|
2017-04-26 08:04:48 +00:00
|
|
|
text.append (String.format ("%,10d ", ptr - 1));
|
2015-06-01 09:35:51 +00:00
|
|
|
else
|
|
|
|
text.append ("\nNew record at : " + (ptr - 1) + "\n");
|
|
|
|
nulls = 0;
|
2017-04-26 08:04:48 +00:00
|
|
|
|
|
|
|
gcd = gcd == 0 ? ptr - 1 : gcd (gcd, ptr - 1);
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|
|
|
|
else if (lastVal == 0x0D && newFormat)
|
2017-03-17 11:03:56 +00:00
|
|
|
if (showAllOffsets)
|
2017-04-26 08:04:48 +00:00
|
|
|
text.append (String.format ("%,10d ", ptr - 1));
|
2017-03-17 11:03:56 +00:00
|
|
|
else
|
2017-04-26 08:04:48 +00:00
|
|
|
text.append (" ");
|
2015-06-01 09:35:51 +00:00
|
|
|
|
|
|
|
text.append ((char) val);
|
|
|
|
}
|
|
|
|
lastVal = val;
|
|
|
|
}
|
2017-04-26 08:04:48 +00:00
|
|
|
|
|
|
|
if (gcd > 0)
|
2017-06-22 23:13:37 +00:00
|
|
|
text.append (String.format ("%nGCD: %,d", gcd));
|
2017-04-26 08:04:48 +00:00
|
|
|
else if (text.length () > 0 && text.charAt (text.length () - 1) == '\n')
|
2015-06-01 09:35:51 +00:00
|
|
|
text.deleteCharAt (text.length () - 1);
|
|
|
|
|
|
|
|
return text.toString ();
|
|
|
|
}
|
2017-04-26 08:04:48 +00:00
|
|
|
|
|
|
|
private int gcd (int a, int b)
|
|
|
|
{
|
|
|
|
return a == 0 ? b : gcd (b % a, a);
|
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|