1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-10-25 10:24:27 +00:00
6502bench/SourceGen/SGTestData/2022-extension-scripts.cs
Andy McFadden 28eafef27c Expand the set of things SetInlineDataFormat accepts
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.
2019-10-05 19:51:34 -07:00

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);
}
}
}
}