Improve IFF file detection and parsing

This commit is contained in:
Peter Dell 2023-02-26 16:17:59 +01:00
parent 1c9e603ba5
commit a2026b1fa5
2 changed files with 38 additions and 11 deletions

View File

@ -41,6 +41,7 @@ import com.wudsn.ide.hex.parser.AtariDiskImageKFileParser;
import com.wudsn.ide.hex.parser.AtariMADSParser;
import com.wudsn.ide.hex.parser.AtariParser;
import com.wudsn.ide.hex.parser.AtariSDXParser;
import com.wudsn.ide.hex.parser.IFFParser;
final class HexEditorParserComponent {
@ -256,16 +257,22 @@ final class HexEditorParserComponent {
// IFF files always have an even number of bytes
if (fileContent.getLength() > 8 && (fileContent.getLength() & 0x1) == 0) {
possibleFileContentModes.add(HexEditorFileContentMode.IFF_FILE);
char[] id = new char[4];
int offset = 0;
id[0] = (char) fileContent.getByte(0);
id[1] = (char) fileContent.getByte(1);
id[2] = (char) fileContent.getByte(2);
id[3] = (char) fileContent.getByte(3);
String chunk = String.copyValueOf(id);
boolean iff = chunk.equals("FORM") || chunk.equals("LIST") || chunk.equals("CAT ");
if (result.equals(HexEditorFileContentMode.BINARY) && iff) {
result = HexEditorFileContentMode.IFF_FILE;
String chunkName = String.copyValueOf(id);
offset += 4;
var chunkLength = fileContent.getDoubleWordBigEndian(4);
offset += 4;
if (IFFParser.isValidChunkName(chunkName) && offset + chunkLength <= fileContent.getLength()) {
possibleFileContentModes.add(HexEditorFileContentMode.IFF_FILE);
boolean iff = chunkName.equals("FORM") || chunkName.equals("LIST") || chunkName.equals("CAT ");
if (result.equals(HexEditorFileContentMode.BINARY) && iff) {
result = HexEditorFileContentMode.IFF_FILE;
}
}
}
return result;

View File

@ -30,6 +30,22 @@ import com.wudsn.ide.hex.Texts;
public final class IFFParser extends HexEditorParser {
public static boolean isValidChunkName(String chunkName) {
if (chunkName == null) {
throw new IllegalArgumentException("Parameter 'chunkName' must not be null.");
}
if (chunkName.length() != 4) {
return false;
}
for (int i = 0; i < chunkName.length(); i++) {
char c = chunkName.charAt(i);
if (c < 'A' || c > 'Z') {
return false;
}
}
return true;
}
@Override
public final boolean parse(StyledString contentBuilder) {
if (contentBuilder == null) {
@ -45,19 +61,23 @@ public final class IFFParser extends HexEditorParser {
private boolean parse(StyledString contentBuilder, long offset, long fileContentLength,
HexEditorContentOutlineTreeObject treeObject) {
boolean error;
String chunkName = null;
error = (fileContentLength - offset) < 8;
if (!error) {
while ((fileContentLength - offset) >= 8 && !error) {
long headerLength = 8;
String chunkName = getChunkName(offset);
long chunkLength = fileContent.getDoubleWordBigEndian(offset + 4);
chunkName = getChunkName(offset);
if (!isValidChunkName(chunkName)) {
error = true; // Non ASCII chunk name
break;
}
var chunkLength = fileContent.getDoubleWordBigEndian(offset + 4);
String headerText;
String formTypeName = "";
boolean hasInnerChunks = false;
if (chunkName.equals("FORM")) {
if (chunkLength >= 4) {
formTypeName = getChunkName(offset + 8);
formTypeName = getChunkName(offset);
headerText = TextUtility.format(Texts.HEX_EDITOR_IFF_FORM_CHUNK, chunkName, formTypeName,
HexUtility.getLongValueHexString(chunkLength),
NumberUtility.getLongValueDecimalString(chunkLength));
@ -75,6 +95,7 @@ public final class IFFParser extends HexEditorParser {
headerText = TextUtility.format(Texts.HEX_EDITOR_IFF_CHUNK, chunkName,
HexUtility.getLongValueHexString(chunkLength),
NumberUtility.getLongValueDecimalString(chunkLength));
}
if (!error) {
@ -98,11 +119,10 @@ public final class IFFParser extends HexEditorParser {
if ((offset & 0x1) == 1) {
offset++;
}
}
}
}
if (error) {
printBlockWithError(contentBuilder, Texts.HEX_EDITOR_IFF_FILE_ERROR, fileContentLength, offset);
}