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

View File

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