mirror of
https://github.com/fadden/6502bench.git
synced 2024-10-25 10:24:27 +00:00
28eafef27c
Extension scripts (a/k/a "plugins") can now apply any data format supported by FormatDescriptor to inline data. In particular, it can now handle variable-length inline strings. The code analyzer verifies the string structure (e.g. null-terminated strings have exactly one null byte, at the very end). Added PluginException to carry an exception back to the plugin code, for occasions when they're doing something so wrong that we just want to smack them. Added test 2022-extension-scripts to exercise the feature.
147 lines
6.1 KiB
C#
147 lines
6.1 KiB
C#
// Copyright 2019 faddenSoft. All Rights Reserved.
|
|
// See the LICENSE.txt file for distribution terms (Apache 2.0).
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using PluginCommon;
|
|
|
|
namespace RuntimeData.Test2022 {
|
|
public class Test2022 : MarshalByRefObject, IPlugin, IPlugin_InlineJsr, IPlugin_InlineJsl {
|
|
private IApplication mAppRef;
|
|
private byte[] mFileData;
|
|
|
|
private int mInline8StringAddr; // jsr
|
|
private int mInlineRev8StringAddr; // jsr
|
|
private int mInlineNullStringAddr; // jsr
|
|
private int mInlineL1StringAddr; // jsl
|
|
private int mInlineL2StringAddr; // jsl
|
|
private int mInlineDciStringAddr; // jsl
|
|
|
|
public string Identifier {
|
|
get {
|
|
return "Test 2022-extension-scripts";
|
|
}
|
|
}
|
|
|
|
public void Prepare(IApplication appRef, byte[] fileData, List<PlSymbol> plSymbols) {
|
|
mAppRef = appRef;
|
|
mFileData = fileData;
|
|
|
|
mAppRef.DebugLog("Test2022(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
|
|
|
foreach (PlSymbol sym in plSymbols) {
|
|
switch (sym.Label) {
|
|
case "PrintInline8String":
|
|
mInline8StringAddr = sym.Value;
|
|
break;
|
|
case "PrintInlineRev8String":
|
|
mInlineRev8StringAddr = sym.Value;
|
|
break;
|
|
case "PrintInlineNullString":
|
|
mInlineNullStringAddr = sym.Value;
|
|
break;
|
|
case "PrintInlineL1String":
|
|
mInlineL1StringAddr = sym.Value;
|
|
break;
|
|
case "PrintInlineL2String":
|
|
mInlineL2StringAddr = sym.Value;
|
|
break;
|
|
case "PrintInlineDciString":
|
|
mInlineDciStringAddr = sym.Value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void CheckJsr(int offset, out bool noContinue) {
|
|
noContinue = false;
|
|
int target = Util.GetWord(mFileData, offset + 1, 2, false);
|
|
if (target == mInline8StringAddr) {
|
|
if (offset + 3 + 8 > mFileData.Length) {
|
|
mAppRef.DebugLog("8string ran off end at +" +
|
|
(offset + 3).ToString("x6"));
|
|
return;
|
|
}
|
|
mAppRef.SetInlineDataFormat(offset + 3, 8,
|
|
DataType.StringGeneric, DataSubType.Ascii, null);
|
|
} else if (target == mInlineRev8StringAddr) {
|
|
if (offset + 3 + 8 > mFileData.Length) {
|
|
mAppRef.DebugLog("rev8string ran off end at +" +
|
|
(offset + 3).ToString("x6"));
|
|
return;
|
|
}
|
|
mAppRef.SetInlineDataFormat(offset + 3, 8,
|
|
DataType.StringReverse, DataSubType.Ascii, null);
|
|
} else if (target == mInlineNullStringAddr) {
|
|
// look for the terminating null byte
|
|
int nullOff = offset + 3;
|
|
while (nullOff < mFileData.Length) {
|
|
if (mFileData[nullOff] == 0) {
|
|
break;
|
|
}
|
|
nullOff++;
|
|
}
|
|
if (nullOff == mFileData.Length) {
|
|
mAppRef.DebugLog("Unable to find end of null-terminated string at +" +
|
|
(offset+3).ToString("x6"));
|
|
return;
|
|
}
|
|
mAppRef.SetInlineDataFormat(offset + 3, nullOff - (offset + 3) + 1,
|
|
DataType.StringNullTerm, DataSubType.Ascii, null);
|
|
}
|
|
}
|
|
|
|
public void CheckJsl(int offset, out bool noContinue) {
|
|
noContinue = false;
|
|
int target = Util.GetWord(mFileData, offset + 1, 3, false);
|
|
if (target == mInlineL1StringAddr) {
|
|
// 0 1 2 3 4 5
|
|
// 22 00 10 01 01 66
|
|
int len = mFileData[offset + 4]; // 1-byte len in first byte past 4-byte JSL
|
|
if (offset + 5 + len > mFileData.Length) {
|
|
// ran off the end
|
|
mAppRef.DebugLog("L1 string ran off end of file at +" +
|
|
(offset + 4).ToString("x6"));
|
|
return;
|
|
}
|
|
mAppRef.SetInlineDataFormat(offset + 4, len + 1,
|
|
DataType.StringL8, DataSubType.Ascii, null);
|
|
} else if (target == mInlineL2StringAddr) {
|
|
int len = Util.GetWord(mFileData, offset + 4, 2, false);
|
|
if (offset + 6 + len > mFileData.Length) {
|
|
// ran off the end
|
|
mAppRef.DebugLog("L2 string ran off end of file at +" +
|
|
(offset+4).ToString("x6"));
|
|
return;
|
|
}
|
|
mAppRef.SetInlineDataFormat(offset + 4, len + 2,
|
|
DataType.StringL16, DataSubType.Ascii, null);
|
|
} else {
|
|
// look for the first byte whose high bit doesn't match the first byte's bit
|
|
// 0 1 2 3 4 5
|
|
// 22 00 30 01 66 c1
|
|
if (offset + 3 + 2 >= mFileData.Length) {
|
|
// need at least two bytes
|
|
return;
|
|
}
|
|
byte firstBit = (byte) (mFileData[offset + 4] & 0x80);
|
|
int endOff = offset + 5;
|
|
while (endOff < mFileData.Length) {
|
|
if ((mFileData[endOff] & 0x80) != firstBit) {
|
|
break;
|
|
}
|
|
endOff++;
|
|
}
|
|
if (endOff == mFileData.Length) {
|
|
mAppRef.DebugLog("Unable to find end of DCI string at +" +
|
|
(offset+4).ToString("x6"));
|
|
return;
|
|
}
|
|
mAppRef.SetInlineDataFormat(offset + 4, endOff - (offset + 4) + 1,
|
|
DataType.StringDci, DataSubType.Ascii, null);
|
|
}
|
|
}
|
|
}
|
|
}
|