diff --git a/PluginCommon/Interfaces.cs b/PluginCommon/Interfaces.cs index 119767a..b78f6b7 100644 --- a/PluginCommon/Interfaces.cs +++ b/PluginCommon/Interfaces.cs @@ -126,7 +126,7 @@ namespace PluginCommon { Unknown = 0, NumericLE, NumericBE, - String, + StringGeneric, Dense, Fill } diff --git a/SourceGen/AsmGen/AsmAcme.cs b/SourceGen/AsmGen/AsmAcme.cs index 2f8b88e..bfcb8a9 100644 --- a/SourceGen/AsmGen/AsmAcme.cs +++ b/SourceGen/AsmGen/AsmAcme.cs @@ -122,7 +122,6 @@ namespace SourceGen.AsmGen { //StrLen8 //StrLen16 //StrDci - //StrDciReverse }; @@ -388,7 +387,12 @@ namespace SourceGen.AsmGen { opcodeStr = operandStr = null; OutputDenseHex(offset, length, labelStr, commentStr); break; - case FormatDescriptor.Type.String: + case FormatDescriptor.Type.StringGeneric: + case FormatDescriptor.Type.StringReverse: + case FormatDescriptor.Type.StringNullTerm: + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: + case FormatDescriptor.Type.StringDci: multiLine = true; opcodeStr = operandStr = null; OutputString(offset, labelStr, commentStr); @@ -532,7 +536,7 @@ namespace SourceGen.AsmGen { Anattrib attr = Project.GetAnattrib(offset); FormatDescriptor dfd = attr.DataDescriptor; Debug.Assert(dfd != null); - Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String); + Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); bool highAscii = false; @@ -541,36 +545,31 @@ namespace SourceGen.AsmGen { bool showLeading = false; bool showTrailing = false; - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.Dci: + case FormatDescriptor.Type.StringDci: highAscii = (data[offset] & 0x80) != 0; trailingBytes = 1; showTrailing = true; break; - case FormatDescriptor.SubType.Reverse: + case FormatDescriptor.Type.StringReverse: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.DciReverse: - highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0; - leadingBytes = 1; - showLeading = true; - break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: highAscii = (data[offset] & 0x80) != 0; trailingBytes = 1; showTrailing = true; break; - case FormatDescriptor.SubType.L8String: + case FormatDescriptor.Type.StringL8: if (dfd.Length > 1) { highAscii = (data[offset + 1] & 0x80) != 0; } leadingBytes = 1; showLeading = true; break; - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL16: if (dfd.Length > 2) { highAscii = (data[offset + 2] & 0x80) != 0; } @@ -598,18 +597,17 @@ namespace SourceGen.AsmGen { string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric); - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: // TODO(someday): something fancy with encodings to handle high-ASCII text? break; - case FormatDescriptor.SubType.Dci: - case FormatDescriptor.SubType.Reverse: - case FormatDescriptor.SubType.DciReverse: + case FormatDescriptor.Type.StringDci: + case FormatDescriptor.Type.StringReverse: // Fully configured above. break; - case FormatDescriptor.SubType.CString: - case FormatDescriptor.SubType.L8String: - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringNullTerm: + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: // Implement as macro? break; default: diff --git a/SourceGen/AsmGen/AsmCc65.cs b/SourceGen/AsmGen/AsmCc65.cs index 09dcbfc..8db7b0b 100644 --- a/SourceGen/AsmGen/AsmCc65.cs +++ b/SourceGen/AsmGen/AsmCc65.cs @@ -119,7 +119,6 @@ namespace SourceGen.AsmGen { //StrLen8 // macro with .strlen? //StrLen16 //StrDci - //StrDciReverse }; @@ -414,7 +413,12 @@ namespace SourceGen.AsmGen { opcodeStr = operandStr = null; OutputDenseHex(offset, length, labelStr, commentStr); break; - case FormatDescriptor.Type.String: + case FormatDescriptor.Type.StringGeneric: + case FormatDescriptor.Type.StringReverse: + case FormatDescriptor.Type.StringNullTerm: + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: + case FormatDescriptor.Type.StringDci: multiLine = true; opcodeStr = operandStr = null; OutputString(offset, labelStr, commentStr); @@ -586,7 +590,7 @@ namespace SourceGen.AsmGen { Anattrib attr = Project.GetAnattrib(offset); FormatDescriptor dfd = attr.DataDescriptor; Debug.Assert(dfd != null); - Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String); + Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); bool highAscii = false; @@ -595,36 +599,31 @@ namespace SourceGen.AsmGen { bool showLeading = false; bool showTrailing = false; - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.Dci: + case FormatDescriptor.Type.StringDci: highAscii = (data[offset] & 0x80) != 0; trailingBytes = 1; showTrailing = true; break; - case FormatDescriptor.SubType.Reverse: + case FormatDescriptor.Type.StringReverse: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.DciReverse: - highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0; - leadingBytes = 1; - showLeading = true; - break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: highAscii = (data[offset] & 0x80) != 0; trailingBytes = 1; showTrailing = true; break; - case FormatDescriptor.SubType.L8String: + case FormatDescriptor.Type.StringL8: if (dfd.Length > 1) { highAscii = (data[offset + 1] & 0x80) != 0; } leadingBytes = 1; showLeading = true; break; - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL16: if (dfd.Length > 2) { highAscii = (data[offset + 2] & 0x80) != 0; } @@ -652,8 +651,8 @@ namespace SourceGen.AsmGen { string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric); - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: // Special case for simple short high-ASCII strings. These have no // leading or trailing bytes. We can improve this a bit by handling // arbitrarily long strings by simply breaking them across lines. @@ -673,19 +672,18 @@ namespace SourceGen.AsmGen { highAscii = false; } break; - case FormatDescriptor.SubType.Dci: - case FormatDescriptor.SubType.Reverse: - case FormatDescriptor.SubType.DciReverse: + case FormatDescriptor.Type.StringDci: + case FormatDescriptor.Type.StringReverse: // Full configured above. break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: if (gath.NumLinesOutput == 1 && !gath.HasDelimiter) { opcodeStr = sDataOpNames.StrNullTerm; showTrailing = false; } break; - case FormatDescriptor.SubType.L8String: - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: // Implement macros? break; default: diff --git a/SourceGen/AsmGen/AsmMerlin32.cs b/SourceGen/AsmGen/AsmMerlin32.cs index a785056..c308979 100644 --- a/SourceGen/AsmGen/AsmMerlin32.cs +++ b/SourceGen/AsmGen/AsmMerlin32.cs @@ -118,7 +118,6 @@ namespace SourceGen.AsmGen { StrLen16Hi = "strl", StrDci = "dci", StrDciHi = "dci", - //StrDciReverse }; @@ -294,7 +293,12 @@ namespace SourceGen.AsmGen { opcodeStr = operandStr = null; OutputDenseHex(offset, length, labelStr, commentStr); break; - case FormatDescriptor.Type.String: + case FormatDescriptor.Type.StringGeneric: + case FormatDescriptor.Type.StringReverse: + case FormatDescriptor.Type.StringNullTerm: + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: + case FormatDescriptor.Type.StringDci: multiLine = true; opcodeStr = operandStr = null; OutputString(offset, labelStr, commentStr); @@ -460,9 +464,6 @@ namespace SourceGen.AsmGen { // backward order. Also, Merlin doesn't allow hex to be embedded in a REV // operation, so we can't use REV if the string contains a delimiter. // - // DciReverse is deprecated, but we can handle it as a Reverse string with a - // trailing byte on a following line. - // // For aesthetic purposes, zero-length CString, L8String, and L16String // should be output as DFB/DW zeroes rather than an empty string -- makes // it easier to read. @@ -472,7 +473,7 @@ namespace SourceGen.AsmGen { Anattrib attr = Project.GetAnattrib(offset); FormatDescriptor dfd = attr.DataDescriptor; Debug.Assert(dfd != null); - Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String); + Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); bool highAscii = false; @@ -483,22 +484,18 @@ namespace SourceGen.AsmGen { bool showTrailing = false; RevMode revMode = RevMode.Forward; - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.Dci: + case FormatDescriptor.Type.StringDci: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.Reverse: + case FormatDescriptor.Type.StringReverse: highAscii = (data[offset] & 0x80) != 0; revMode = RevMode.Reverse; break; - case FormatDescriptor.SubType.DciReverse: - highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0; - revMode = RevMode.Reverse; - break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: highAscii = (data[offset] & 0x80) != 0; if (dfd.Length == 1) { showZeroes = 1; // empty null-terminated string @@ -506,7 +503,7 @@ namespace SourceGen.AsmGen { trailingBytes = 1; showTrailing = true; break; - case FormatDescriptor.SubType.L8String: + case FormatDescriptor.Type.StringL8: if (dfd.Length > 1) { highAscii = (data[offset + 1] & 0x80) != 0; } else { @@ -514,7 +511,7 @@ namespace SourceGen.AsmGen { } leadingBytes = 1; break; - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL16: if (dfd.Length > 2) { highAscii = (data[offset + 2] & 0x80) != 0; } else { @@ -555,11 +552,11 @@ namespace SourceGen.AsmGen { string opcodeStr; - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric; break; - case FormatDescriptor.SubType.Dci: + case FormatDescriptor.Type.StringDci: if (gath.NumLinesOutput == 1) { opcodeStr = highAscii ? sDataOpNames.StrDciHi : sDataOpNames.StrDci; } else { @@ -568,7 +565,7 @@ namespace SourceGen.AsmGen { showTrailing = true; } break; - case FormatDescriptor.SubType.Reverse: + case FormatDescriptor.Type.StringReverse: if (gath.HasDelimiter) { // can't include escaped delimiters in REV opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric; @@ -581,18 +578,11 @@ namespace SourceGen.AsmGen { Debug.Assert(revMode == RevMode.Reverse); } break; - case FormatDescriptor.SubType.DciReverse: - // Mostly punt -- output as ASCII with special handling for first byte. - opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric; - revMode = RevMode.Forward; - leadingBytes = 1; - showLeading = true; - break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: //opcodeStr = sDataOpNames.StrNullTerm[highAscii ? 1 : 0]; opcodeStr = highAscii ? sDataOpNames.StrGenericHi : sDataOpNames.StrGeneric; break; - case FormatDescriptor.SubType.L8String: + case FormatDescriptor.Type.StringL8: if (gath.NumLinesOutput == 1) { opcodeStr = highAscii ? sDataOpNames.StrLen8Hi : sDataOpNames.StrLen8; } else { @@ -601,7 +591,7 @@ namespace SourceGen.AsmGen { showLeading = true; } break; - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL16: if (gath.NumLinesOutput == 1) { opcodeStr = highAscii ? sDataOpNames.StrLen16Hi : sDataOpNames.StrLen16; } else { diff --git a/SourceGen/AsmGen/AsmTass64.cs b/SourceGen/AsmGen/AsmTass64.cs index 9f671db..1bc7fe2 100644 --- a/SourceGen/AsmGen/AsmTass64.cs +++ b/SourceGen/AsmGen/AsmTass64.cs @@ -129,7 +129,6 @@ namespace SourceGen.AsmGen { StrLen8 = ".ptext", //StrLen16 //StrDci - //StrDciReverse }; private const string HERE_PSEUDO_OP = ".here"; @@ -360,7 +359,12 @@ namespace SourceGen.AsmGen { opcodeStr = operandStr = null; OutputDenseHex(offset, length, labelStr, commentStr); break; - case FormatDescriptor.Type.String: + case FormatDescriptor.Type.StringGeneric: + case FormatDescriptor.Type.StringReverse: + case FormatDescriptor.Type.StringNullTerm: + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: + case FormatDescriptor.Type.StringDci: multiLine = true; opcodeStr = operandStr = null; OutputString(offset, labelStr, commentStr); @@ -525,7 +529,7 @@ namespace SourceGen.AsmGen { Anattrib attr = Project.GetAnattrib(offset); FormatDescriptor dfd = attr.DataDescriptor; Debug.Assert(dfd != null); - Debug.Assert(dfd.FormatType == FormatDescriptor.Type.String); + Debug.Assert(dfd.IsString); Debug.Assert(dfd.Length > 0); bool highAscii = false; @@ -534,36 +538,31 @@ namespace SourceGen.AsmGen { bool showLeading = false; bool showTrailing = false; - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.Dci: + case FormatDescriptor.Type.StringDci: highAscii = (data[offset] & 0x80) != 0; trailingBytes = 1; showTrailing = true; break; - case FormatDescriptor.SubType.Reverse: + case FormatDescriptor.Type.StringReverse: highAscii = (data[offset] & 0x80) != 0; break; - case FormatDescriptor.SubType.DciReverse: - highAscii = (data[offset + dfd.Length - 1] & 0x80) != 0; - leadingBytes = 1; - showLeading = true; - break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: highAscii = (data[offset] & 0x80) != 0; trailingBytes = 1; showTrailing = true; break; - case FormatDescriptor.SubType.L8String: + case FormatDescriptor.Type.StringL8: if (dfd.Length > 1) { highAscii = (data[offset + 1] & 0x80) != 0; } leadingBytes = 1; showLeading = true; break; - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL16: if (dfd.Length > 2) { highAscii = (data[offset + 2] & 0x80) != 0; } @@ -591,28 +590,27 @@ namespace SourceGen.AsmGen { string opcodeStr = formatter.FormatPseudoOp(sDataOpNames.StrGeneric); - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: // TODO(someday): something fancy with encodings to handle high-ASCII text? break; - case FormatDescriptor.SubType.Dci: - case FormatDescriptor.SubType.Reverse: - case FormatDescriptor.SubType.DciReverse: + case FormatDescriptor.Type.StringDci: + case FormatDescriptor.Type.StringReverse: // Fully configured above. break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: if (gath.NumLinesOutput == 1 && !gath.HasDelimiter) { opcodeStr = sDataOpNames.StrNullTerm; showTrailing = false; } break; - case FormatDescriptor.SubType.L8String: + case FormatDescriptor.Type.StringL8: if (gath.NumLinesOutput == 1 && !gath.HasDelimiter) { opcodeStr = sDataOpNames.StrLen8; showLeading = false; } break; - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL16: // Implement as macro? break; default: diff --git a/SourceGen/CodeAnalysis.cs b/SourceGen/CodeAnalysis.cs index f83cd61..eec8f2b 100644 --- a/SourceGen/CodeAnalysis.cs +++ b/SourceGen/CodeAnalysis.cs @@ -1047,7 +1047,7 @@ namespace SourceGen { return FormatDescriptor.Type.NumericBE; case DataType.Dense: return FormatDescriptor.Type.Dense; - case DataType.String: + case DataType.StringGeneric: case DataType.Fill: default: // not appropriate for operands, or inline data (?) @@ -1068,8 +1068,6 @@ namespace SourceGen { return FormatDescriptor.SubType.Decimal; case DataSubType.Binary: return FormatDescriptor.SubType.Binary; - case DataSubType.Ascii: - return FormatDescriptor.SubType.Ascii; case DataSubType.Address: return FormatDescriptor.SubType.Address; case DataSubType.Symbol: diff --git a/SourceGen/DataAnalysis.cs b/SourceGen/DataAnalysis.cs index f324b22..617169b 100644 --- a/SourceGen/DataAnalysis.cs +++ b/SourceGen/DataAnalysis.cs @@ -737,7 +737,7 @@ namespace SourceGen { if (asciiLen >= minStringChars) { LogV(start, "ASCII string, len=" + asciiLen + " bytes"); mAnattribs[start].DataDescriptor = FormatDescriptor.Create(asciiLen, - FormatDescriptor.Type.String, FormatDescriptor.SubType.None); + FormatDescriptor.Type.StringGeneric, FormatDescriptor.SubType.Ascii); start += asciiLen; continue; } diff --git a/SourceGen/FormatDescriptor.cs b/SourceGen/FormatDescriptor.cs index 61e2450..f7b6d63 100644 --- a/SourceGen/FormatDescriptor.cs +++ b/SourceGen/FormatDescriptor.cs @@ -34,27 +34,35 @@ namespace SourceGen { /// public class FormatDescriptor { /// - /// General data type. + /// General data type. Generally corresponds to the pseudo-opcode. /// /// The UI only allows big-endian values in certain situations. Internally we want /// to be orthogonal in case the policy changes. /// public enum Type : byte { Unknown = 0, - REMOVE, // special type, only used by operand editor - Default, // means "unformatted", same effect as not having a FormatDescriptor - NumericLE, // 1-4 byte number, little-endian - NumericBE, // 1-4 byte number, big-endian - String, // character string - Dense, // raw data, represented as compactly as possible - Fill // fill memory with a value + REMOVE, // special type, only used by operand editor + Default, // means "unformatted", same as not having a FormatDescriptor + + NumericLE, // 1-4 byte number, little-endian + NumericBE, // 1-4 byte number, big-endian + + StringGeneric, // character string + StringReverse, // character string, in reverse order + StringNullTerm, // C-style null-terminated string + StringL8, // string with 8-bit length prefix + StringL16, // string with 16-bit length prefix + StringDci, // string terminated by flipped high bit (Dextral Char Inverted) + + Dense, // raw data, represented as compactly as possible + Fill // fill memory with a value } /// - /// Additional data type detail. + /// Additional data type detail. Generally affects the operand. /// - /// Some things are extracted from the data itself, e.g. we don't need to specify if - /// a string is high- or low-ASCII, or what value to use for Fill. + /// Some things are extracted from the data itself, e.g. we don't need to specify + /// what value to use for Fill. /// public enum SubType : byte { None = 0, @@ -63,22 +71,18 @@ namespace SourceGen { Hex, Decimal, Binary, - Ascii, // aspirational; falls back on hex if data not suited - Address, // wants to be an address, but no symbol defined - Symbol, // symbolic ref; replace with Expression, someday? + Address, // wants to be an address, but no symbol defined + Symbol, // symbolic ref; replace with Expression, someday? - // String; default is straight text - Reverse, // plain ASCII in reverse order - CString, // null-terminated - L8String, // 8-bit length prefix - L16String, // 16-bit length prefix - Dci, // Dextral Character Inverted - DciReverse, // DCI with string backwards [deprecated -- no asm supports this] + // Strings and NumericLE/BE (single character) + Ascii, // ASCII (with or without the high bit set) + C64Petscii, // C64 PETSCII + C64Screen, // C64 screen code // Dense; no sub-types // Fill; default is non-ignore - Ignore // TODO(someday): use this for "don't care" sections + Ignore // TODO(someday): use this for "don't care" sections } private const int MAX_NUMERIC_LEN = 4; @@ -264,6 +268,25 @@ namespace SourceGen { } } + /// + /// True if the FormatDescriptor is a string type. + /// + public bool IsString { + get { + switch (FormatType) { + case Type.StringGeneric: + case Type.StringReverse: + case Type.StringNullTerm: + case Type.StringL8: + case Type.StringL16: + case Type.StringDci: + return true; + default: + return false; + } + } + } + /// /// True if the FormatDescriptor has a symbol or is Numeric/Address. /// @@ -320,6 +343,48 @@ namespace SourceGen { /// public string ToUiString() { // NOTE: this should be made easier to localize + + if (IsString) { + string descr; + switch (FormatSubType) { + case SubType.Ascii: + descr = "ASCII"; + break; + case SubType.C64Petscii: + descr = "C64 PETSCII"; + break; + case SubType.C64Screen: + descr = "C64 Screen"; + break; + default: + descr = "???"; + break; + } + switch (FormatType) { + case Type.StringGeneric: + descr += " string"; + break; + case Type.StringReverse: + descr += " string (reverse)"; + break; + case Type.StringNullTerm: + descr += " string (null term)"; + break; + case Type.StringL8: + descr += " string (1-byte len)"; + break; + case Type.StringL16: + descr += " string (2-byte len)"; + break; + case Type.StringDci: + descr += " string (DCI)"; + break; + default: + descr += " ???"; + break; + } + } + switch (FormatSubType) { case SubType.None: switch (FormatType) { @@ -328,13 +393,12 @@ namespace SourceGen { return "Numeric (little-endian)"; case Type.NumericBE: return "Numeric (big-endian)"; - case Type.String: - return "String (generic)"; case Type.Dense: return "Dense"; case Type.Fill: return "Fill"; default: + // strings handled earlier return "???"; } case SubType.Hex: @@ -343,25 +407,16 @@ namespace SourceGen { return "Numeric, Decimal"; case SubType.Binary: return "Numeric, Binary"; - case SubType.Ascii: - return "ASCII"; case SubType.Address: return "Address"; case SubType.Symbol: return "Symbol \"" + SymbolRef.Label + "\""; - - case SubType.Reverse: - return "String (reverse)"; - case SubType.CString: - return "String (null-term)"; - case SubType.L8String: - return "String (1-byte len)"; - case SubType.L16String: - return "String (2-byte len)"; - case SubType.Dci: - return "String (DCI)"; - case SubType.DciReverse: - return "String (RevDCI)"; + case SubType.Ascii: + return "ASCII"; + case SubType.C64Petscii: + return "C64 PETSCII"; + case SubType.C64Screen: + return "C64 Screen"; default: return "???"; diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs index 2f3f4e1..aa7bcf1 100644 --- a/SourceGen/ProjectFile.cs +++ b/SourceGen/ProjectFile.cs @@ -52,7 +52,7 @@ namespace SourceGen { // ignore stuff that's in one side but not the other. However, if we're opening a // newer file in an older program, it's worth letting the user know that some stuff // may get lost as soon as they save the file. - public const int CONTENT_VERSION = 1; + public const int CONTENT_VERSION = 2; private static readonly bool ADD_CRLF = true; @@ -669,6 +669,33 @@ namespace SourceGen { dfd = null; FormatDescriptor.Type format; FormatDescriptor.SubType subFormat; + + // File version 1 used a different set of enumerated values for defining strings. + // Parse it out here. + if ("String".Equals(sfd.Format)) { + subFormat = FormatDescriptor.SubType.Ascii; + if ("None".Equals(sfd.SubFormat)) { + format = FormatDescriptor.Type.StringGeneric; + } else if ("Reverse".Equals(sfd.SubFormat)) { + format = FormatDescriptor.Type.StringReverse; + } else if ("CString".Equals(sfd.SubFormat)) { + format = FormatDescriptor.Type.StringNullTerm; + } else if ("L8String".Equals(sfd.SubFormat)) { + format = FormatDescriptor.Type.StringL8; + } else if ("L16String".Equals(sfd.SubFormat)) { + format = FormatDescriptor.Type.StringL16; + } else if ("Dci".Equals(sfd.SubFormat)) { + format = FormatDescriptor.Type.StringDci; + } else { + // DciReverse no longer supported; output as dense hex + format = FormatDescriptor.Type.Dense; + subFormat = FormatDescriptor.SubType.None; + } + Debug.WriteLine("Found v1 string, fmt=" + format + ", sub=" + subFormat); + dfd = FormatDescriptor.Create(sfd.Length, format, subFormat); + return true; + } + try { format = (FormatDescriptor.Type)Enum.Parse( typeof(FormatDescriptor.Type), sfd.Format); diff --git a/SourceGen/PseudoOp.cs b/SourceGen/PseudoOp.cs index 36d0c02..988dde1 100644 --- a/SourceGen/PseudoOp.cs +++ b/SourceGen/PseudoOp.cs @@ -87,8 +87,6 @@ namespace SourceGen { public string StrNullTermHi { get; set; } public string StrDci { get; set; } public string StrDciHi { get; set; } - public string StrDciReverse { get; set; } - public string StrDciReverseHi { get; set; } public string GetDefineData(int width) { switch (width) { @@ -180,8 +178,6 @@ namespace SourceGen { StrNullTermHi = ".zstrh", StrDci = ".dstr", StrDciHi = ".dstrh", - StrDciReverse = ".rdstr", - StrDciReverseHi = ".rdstrh", }; @@ -192,6 +188,37 @@ namespace SourceGen { /// Data format descriptor. /// Line count. public static int ComputeRequiredLineCount(Formatter formatter, FormatDescriptor dfd) { + if (dfd.IsString) { + // Subtract two chars, to leave room for start/end delimiter. We use + // non-ASCII delimiters on-screen, so there's nothing to escape there. + int maxLen = MAX_OPERAND_LEN - 2; + + // Remove leading length or trailing null byte from string length. + int textLen = dfd.Length; + switch (dfd.FormatType) { + case FormatDescriptor.Type.StringGeneric: + case FormatDescriptor.Type.StringReverse: + case FormatDescriptor.Type.StringDci: + break; + case FormatDescriptor.Type.StringNullTerm: + case FormatDescriptor.Type.StringL8: + textLen--; + break; + case FormatDescriptor.Type.StringL16: + textLen -= 2; + break; + default: + Debug.Assert(false); + break; + } + int strLen = (textLen + maxLen - 1) / maxLen; + if (strLen == 0) { + // Empty string, but we still need to output a line. + strLen = 1; + } + return strLen; + } + switch (dfd.FormatType) { case FormatDescriptor.Type.Default: case FormatDescriptor.Type.NumericLE: @@ -204,37 +231,6 @@ namespace SourceGen { int textLen = dfd.Length * 2; return (textLen + maxLen - 1) / maxLen; } - case FormatDescriptor.Type.String: { - // Subtract two chars, to leave room for start/end delimiter. We use - // non-ASCII delimiters on-screen, so there's nothing to escape there. - int maxLen = MAX_OPERAND_LEN - 2; - - // Remove leading length or trailing null byte from string length. - int textLen = dfd.Length; - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: - case FormatDescriptor.SubType.Dci: - case FormatDescriptor.SubType.Reverse: - case FormatDescriptor.SubType.DciReverse: - break; - case FormatDescriptor.SubType.CString: - case FormatDescriptor.SubType.L8String: - textLen--; - break; - case FormatDescriptor.SubType.L16String: - textLen -= 2; - break; - default: - Debug.Assert(false); - break; - } - int strLen = (textLen + maxLen - 1) / maxLen; - if (strLen == 0) { - // Empty string, but we still need to output a line. - strLen = 1; - } - return strLen; - } default: Debug.Assert(false); return 1; @@ -274,89 +270,94 @@ namespace SourceGen { // multi-line items. PseudoOut po = new PseudoOut(); - switch (dfd.FormatType) { - case FormatDescriptor.Type.Default: - if (length != 1) { - // This shouldn't happen. - Debug.Assert(false); - length = 1; + if (dfd.IsString) { + // It's hard to do strings in single-line pieces because of prefix lengths, + // terminating nulls, DCI polarity, and reverse-order strings. We + // really just want to convert the whole thing to a run of chars + // and then pull out a chunk. As an optimization we can handle + // generic strings more efficiently, which should help if auto-analysis is + // creating massive strings (at least until auto-analysis learns how to do + // more complex things). + // + // TODO: consider storing the full string on the first line, then each + // subsequent line has a reference to it with offset+length + if (dfd.FormatType == FormatDescriptor.Type.StringGeneric) { + int maxPerLine = MAX_OPERAND_LEN - 2; + offset += subIndex * maxPerLine; + length -= subIndex * maxPerLine; + if (length > maxPerLine) { + length = maxPerLine; } - po.Opcode = opNames.GetDefineData(length); - int operand = RawData.GetWord(data, offset, length, false); - po.Operand = formatter.FormatHexValue(operand, length * 2); - break; - case FormatDescriptor.Type.NumericLE: - po.Opcode = opNames.GetDefineData(length); - operand = RawData.GetWord(data, offset, length, false); - po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd, - operand, length, FormatNumericOpFlags.None); - break; - case FormatDescriptor.Type.NumericBE: - po.Opcode = opNames.GetDefineBigData(length); - operand = RawData.GetWord(data, offset, length, true); - po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd, - operand, length, FormatNumericOpFlags.None); - break; - case FormatDescriptor.Type.Fill: - po.Opcode = opNames.Fill; - po.Operand = length + "," + formatter.FormatHexValue(data[offset], 2); - break; - case FormatDescriptor.Type.Dense: { - int maxPerLine = MAX_OPERAND_LEN / 2; - offset += subIndex * maxPerLine; - length -= subIndex * maxPerLine; - if (length > maxPerLine) { - length = maxPerLine; - } - po.Opcode = opNames.Dense; - po.Operand = formatter.FormatDenseHex(data, offset, length); - //List outList = new List(); - //GenerateTextLines(text, "", "", po, outList); - //po = outList[subIndex]; - } - break; - case FormatDescriptor.Type.String: - // It's hard to do strings in single-line pieces because of prefix lengths, - // terminating nulls, DCI polarity, and reverse-order strings. We - // really just want to convert the whole thing to a run of chars - // and then pull out a chunk. As an optimization we can handle - // generic strings (subtype=None) more efficiently, which should solve - // the problem of massive strings created by auto-analysis. - if (dfd.FormatSubType == FormatDescriptor.SubType.None) { - int maxPerLine = MAX_OPERAND_LEN - 2; - offset += subIndex * maxPerLine; - length -= subIndex * maxPerLine; - if (length > maxPerLine) { - length = maxPerLine; - } - char[] ltext = BytesToChars(formatter, opNames, dfd.FormatSubType, data, - offset, length, out string lpopcode, out int unused); - po.Opcode = lpopcode; - po.Operand = "\u201c" + new string(ltext) + "\u201d"; - } else { - char[] text = BytesToChars(formatter, opNames, dfd.FormatSubType, data, - offset, length, out string popcode, out int showHexZeroes); + char[] ltext = BytesToChars(formatter, opNames, dfd.FormatType, data, + offset, length, out string lpopcode, out int unused); + po.Opcode = lpopcode; + po.Operand = "\u201c" + new string(ltext) + "\u201d"; + } else { + char[] text = BytesToChars(formatter, opNames, dfd.FormatType, data, + offset, length, out string popcode, out int showHexZeroes); - if (showHexZeroes == 1) { - po.Opcode = opNames.DefineData1; - po.Operand = formatter.FormatHexValue(0, 2); - } else if (showHexZeroes == 2) { - po.Opcode = opNames.DefineData2; - po.Operand = formatter.FormatHexValue(0, 4); - } else { - Debug.Assert(showHexZeroes == 0); - po.Opcode = popcode; - List outList = new List(); - GenerateTextLines(text, "\u201c", "\u201d", po, outList); - po = outList[subIndex]; - } + if (showHexZeroes == 1) { + po.Opcode = opNames.DefineData1; + po.Operand = formatter.FormatHexValue(0, 2); + } else if (showHexZeroes == 2) { + po.Opcode = opNames.DefineData2; + po.Operand = formatter.FormatHexValue(0, 4); + } else { + Debug.Assert(showHexZeroes == 0); + po.Opcode = popcode; + List outList = new List(); + GenerateTextLines(text, "\u201c", "\u201d", po, outList); + po = outList[subIndex]; } - break; - default: - Debug.Assert(false); - po.Opcode = ".???"; - po.Operand = "$" + data[offset].ToString("x2"); - break; + } + } else { + switch (dfd.FormatType) { + case FormatDescriptor.Type.Default: + if (length != 1) { + // This shouldn't happen. + Debug.Assert(false); + length = 1; + } + po.Opcode = opNames.GetDefineData(length); + int operand = RawData.GetWord(data, offset, length, false); + po.Operand = formatter.FormatHexValue(operand, length * 2); + break; + case FormatDescriptor.Type.NumericLE: + po.Opcode = opNames.GetDefineData(length); + operand = RawData.GetWord(data, offset, length, false); + po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd, + operand, length, FormatNumericOpFlags.None); + break; + case FormatDescriptor.Type.NumericBE: + po.Opcode = opNames.GetDefineBigData(length); + operand = RawData.GetWord(data, offset, length, true); + po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd, + operand, length, FormatNumericOpFlags.None); + break; + case FormatDescriptor.Type.Fill: + po.Opcode = opNames.Fill; + po.Operand = length + "," + formatter.FormatHexValue(data[offset], 2); + break; + case FormatDescriptor.Type.Dense: { + int maxPerLine = MAX_OPERAND_LEN / 2; + offset += subIndex * maxPerLine; + length -= subIndex * maxPerLine; + if (length > maxPerLine) { + length = maxPerLine; + } + po.Opcode = opNames.Dense; + po.Operand = formatter.FormatDenseHex(data, offset, length); + //List outList = new List(); + //GenerateTextLines(text, "", "", po, outList); + //po = outList[subIndex]; + } + break; + default: + Debug.Assert(false); + po.Opcode = ".???"; + po.Operand = "$" + data[offset].ToString("x2"); + break; + } } return po; @@ -368,7 +369,7 @@ namespace SourceGen { /// are not shown. /// /// Formatter object. - /// String sub-type. + /// String layout. /// File data. /// Offset, within data, of start of string. /// Number of bytes to convert. @@ -377,7 +378,7 @@ namespace SourceGen { /// length or null-termination) instead of an empty string. /// Array of characters with string data. private static char[] BytesToChars(Formatter formatter, PseudoOpNames opNames, - FormatDescriptor.SubType subType, byte[] data, int offset, int length, + FormatDescriptor.Type formatType, byte[] data, int offset, int length, out string popcode, out int showHexZeroes) { Debug.Assert(length > 0); @@ -389,32 +390,25 @@ namespace SourceGen { showHexZeroes = 0; - switch (subType) { - case FormatDescriptor.SubType.None: + switch (formatType) { + case FormatDescriptor.Type.StringGeneric: // High or low ASCII, full width specified by formatter. highAscii = (data[offset] & 0x80) != 0; popcode = highAscii ? opNames.StrGenericHi : opNames.StrGeneric; break; - case FormatDescriptor.SubType.Dci: + case FormatDescriptor.Type.StringDci: // High or low ASCII, full width specified by formatter. highAscii = (data[offset] & 0x80) != 0; popcode = highAscii ? opNames.StrDciHi : opNames.StrDci; break; - case FormatDescriptor.SubType.Reverse: + case FormatDescriptor.Type.StringReverse: // High or low ASCII, full width specified by formatter. Show characters // in reverse order. highAscii = (data[offset + strLen - 1] & 0x80) != 0; popcode = highAscii ? opNames.StrReverseHi : opNames.StrReverse; reverse = true; break; - case FormatDescriptor.SubType.DciReverse: - // High or low ASCII, full width specified by formatter. Show characters - // in reverse order. - highAscii = (data[offset + strLen - 1] & 0x80) != 0; - popcode = highAscii ? opNames.StrDciReverseHi : opNames.StrDciReverse; - reverse = true; - break; - case FormatDescriptor.SubType.CString: + case FormatDescriptor.Type.StringNullTerm: // High or low ASCII, with a terminating null. Don't show the null. If // it's an empty string, just show the null byte as hex. highAscii = (data[offset] & 0x80) != 0; @@ -424,7 +418,7 @@ namespace SourceGen { showHexZeroes = 1; } break; - case FormatDescriptor.SubType.L8String: + case FormatDescriptor.Type.StringL8: // High or low ASCII, with a leading length byte. Don't show the null. // If it's an empty string, just show the length byte as hex. strOffset++; @@ -436,7 +430,7 @@ namespace SourceGen { } popcode = highAscii ? opNames.StrLen8Hi : opNames.StrLen8; break; - case FormatDescriptor.SubType.L16String: + case FormatDescriptor.Type.StringL16: // High or low ASCII, with a leading length word. Don't show the null. // If it's an empty string, just show the length word as hex. Debug.Assert(strLen > 1); @@ -455,6 +449,7 @@ namespace SourceGen { break; } + // TODO(petscii): convert character encoding char[] text = new char[strLen]; if (!reverse) { for (int i = 0; i < strLen; i++) { @@ -547,6 +542,10 @@ namespace SourceGen { case FormatDescriptor.SubType.Binary: return formatter.FormatBinaryValue(operandValue, hexMinLen * 4); case FormatDescriptor.SubType.Ascii: + case FormatDescriptor.SubType.C64Petscii: + case FormatDescriptor.SubType.C64Screen: + // TODO(petscii): convert encoding; use a helper function *not* in + // formatter -- pass converted char value in along with operandValue return formatter.FormatAsciiOrHex(operandValue); case FormatDescriptor.SubType.Symbol: if (symbolTable.TryGetValue(dfd.SymbolRef.Label, out Symbol sym)) { diff --git a/SourceGen/WpfGui/EditDataOperand.xaml.cs b/SourceGen/WpfGui/EditDataOperand.xaml.cs index b377995..b368e11 100644 --- a/SourceGen/WpfGui/EditDataOperand.xaml.cs +++ b/SourceGen/WpfGui/EditDataOperand.xaml.cs @@ -528,6 +528,9 @@ namespace SourceGen.WpfGui { radioSimpleDataBinary.IsChecked = true; break; case FormatDescriptor.SubType.Ascii: + case FormatDescriptor.SubType.C64Petscii: + case FormatDescriptor.SubType.C64Screen: + // TODO(petscii): update UI radioSimpleDataAscii.IsChecked = true; break; case FormatDescriptor.SubType.Address: @@ -560,34 +563,23 @@ namespace SourceGen.WpfGui { // preferred format not enabled; leave Hex/Low checked } break; - case FormatDescriptor.Type.String: - switch (dfd.FormatSubType) { - case FormatDescriptor.SubType.None: - preferredFormat = radioStringMixed; - break; - case FormatDescriptor.SubType.Reverse: - preferredFormat = radioStringMixedReverse; - break; - case FormatDescriptor.SubType.CString: - preferredFormat = radioStringNullTerm; - break; - case FormatDescriptor.SubType.L8String: - preferredFormat = radioStringLen8; - break; - case FormatDescriptor.SubType.L16String: - preferredFormat = radioStringLen16; - break; - case FormatDescriptor.SubType.Dci: - preferredFormat = radioStringDci; - break; - case FormatDescriptor.SubType.DciReverse: - preferredFormat = radioDefaultFormat; - break; - default: - Debug.Assert(false); - preferredFormat = radioDefaultFormat; - break; - } + case FormatDescriptor.Type.StringGeneric: + preferredFormat = radioStringMixed; + break; + case FormatDescriptor.Type.StringReverse: + preferredFormat = radioStringMixedReverse; + break; + case FormatDescriptor.Type.StringNullTerm: + preferredFormat = radioStringNullTerm; + break; + case FormatDescriptor.Type.StringL8: + preferredFormat = radioStringLen8; + break; + case FormatDescriptor.Type.StringL16: + preferredFormat = radioStringLen16; + break; + case FormatDescriptor.Type.StringDci: + preferredFormat = radioStringDci; break; case FormatDescriptor.Type.Dense: preferredFormat = radioDenseHex; @@ -639,6 +631,7 @@ namespace SourceGen.WpfGui { } else if (radioSimpleDataBinary.IsChecked == true) { subType = FormatDescriptor.SubType.Binary; } else if (radioSimpleDataAscii.IsChecked == true) { + // TODO(petscii): configure subType correctly subType = FormatDescriptor.SubType.Ascii; } else if (radioSimpleDataAddress.IsChecked == true) { subType = FormatDescriptor.SubType.Address; @@ -688,26 +681,25 @@ namespace SourceGen.WpfGui { type = FormatDescriptor.Type.Dense; } else if (radioFill.IsChecked == true) { type = FormatDescriptor.Type.Fill; + subType = FormatDescriptor.SubType.Ascii; // TODO(petscii): set encoding } else if (radioStringMixed.IsChecked == true) { - type = FormatDescriptor.Type.String; + type = FormatDescriptor.Type.StringGeneric; + subType = FormatDescriptor.SubType.Ascii; } else if (radioStringMixedReverse.IsChecked == true) { - type = FormatDescriptor.Type.String; - subType = FormatDescriptor.SubType.Reverse; + type = FormatDescriptor.Type.StringReverse; + subType = FormatDescriptor.SubType.Ascii; } else if (radioStringNullTerm.IsChecked == true) { - type = FormatDescriptor.Type.String; - subType = FormatDescriptor.SubType.CString; + type = FormatDescriptor.Type.StringNullTerm; + subType = FormatDescriptor.SubType.Ascii; } else if (radioStringLen8.IsChecked == true) { - type = FormatDescriptor.Type.String; - subType = FormatDescriptor.SubType.L8String; + type = FormatDescriptor.Type.StringL8; + subType = FormatDescriptor.SubType.Ascii; } else if (radioStringLen16.IsChecked == true) { - type = FormatDescriptor.Type.String; - subType = FormatDescriptor.SubType.L16String; + type = FormatDescriptor.Type.StringL16; + subType = FormatDescriptor.SubType.Ascii; } else if (radioStringDci.IsChecked == true) { - type = FormatDescriptor.Type.String; - subType = FormatDescriptor.SubType.Dci; - //} else if (radioStringDciReverse.Checked) { - // type = FormatDescriptor.Type.String; - // subType = FormatDescriptor.SubType.DciReverse; + type = FormatDescriptor.Type.StringDci; + subType = FormatDescriptor.SubType.Ascii; } else { Debug.Assert(false); // default/none @@ -720,26 +712,26 @@ namespace SourceGen.WpfGui { while (iter.MoveNext()) { TypedRangeSet.TypedRange rng = iter.Current; - if (type == FormatDescriptor.Type.String) { - // We want to create one FormatDescriptor object per string. That way - // each string gets its own line. - if ((subType == FormatDescriptor.SubType.None || - subType == FormatDescriptor.SubType.Reverse)) { - CreateMixedStringEntries(rng.Low, rng.High, subType); - } else if (subType == FormatDescriptor.SubType.CString) { - CreateCStringEntries(rng.Low, rng.High, subType); - } else if (subType == FormatDescriptor.SubType.L8String || - subType == FormatDescriptor.SubType.L16String) { - CreateLengthStringEntries(rng.Low, rng.High, subType); - } else if (subType == FormatDescriptor.SubType.Dci || - subType == FormatDescriptor.SubType.DciReverse) { - CreateDciStringEntries(rng.Low, rng.High, subType); - } else { - Debug.Assert(false); - CreateMixedStringEntries(rng.Low, rng.High, subType); // shrug - } - } else { - CreateSimpleEntries(type, subType, chunkLength, symbolRef, rng.Low, rng.High); + // TODO(petscii): handle encoding on all four calls + switch (type) { + case FormatDescriptor.Type.StringGeneric: + case FormatDescriptor.Type.StringReverse: + CreateMixedStringEntries(rng.Low, rng.High, type, subType); + break; + case FormatDescriptor.Type.StringNullTerm: + CreateCStringEntries(rng.Low, rng.High, type, subType); + break; + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: + CreateLengthStringEntries(rng.Low, rng.High, type, subType); + break; + case FormatDescriptor.Type.StringDci: + CreateDciStringEntries(rng.Low, rng.High, type, subType); + break; + default: + CreateSimpleEntries(type, subType, chunkLength, symbolRef, + rng.Low, rng.High); + break; } } } @@ -793,7 +785,7 @@ namespace SourceGen.WpfGui { /// Offset of first byte in range. /// Offset of last byte in range. /// String sub-type. - private void CreateMixedStringEntries(int low, int high, + private void CreateMixedStringEntries(int low, int high, FormatDescriptor.Type type, FormatDescriptor.SubType subType) { int stringStart = -1; int highBit = 0; @@ -846,11 +838,12 @@ namespace SourceGen.WpfGui { Debug.Assert(length > 0); if (length == 1) { // single byte, output as single ASCII char rather than 1-byte string + // TODO(petscii): low/high? CreateByteFD(offset, FormatDescriptor.SubType.Ascii); } else { FormatDescriptor dfd; dfd = FormatDescriptor.Create(length, - FormatDescriptor.Type.String, subType); + FormatDescriptor.Type.StringGeneric, subType); Results.Add(offset, dfd); } } @@ -873,14 +866,14 @@ namespace SourceGen.WpfGui { /// Offset of first byte in range. /// Offset of last byte in range. /// String sub-type. - private void CreateCStringEntries(int low, int high, + private void CreateCStringEntries(int low, int high, FormatDescriptor.Type type, FormatDescriptor.SubType subType) { int startOffset = low; for (int i = low; i <= high; i++) { if (mFileData[i] == 0x00) { // End of string. Zero-length strings are allowed. FormatDescriptor dfd = FormatDescriptor.Create( - i - startOffset + 1, FormatDescriptor.Type.String, subType); + i - startOffset + 1, type, subType); Results.Add(startOffset, dfd); startOffset = i + 1; } else { @@ -899,20 +892,19 @@ namespace SourceGen.WpfGui { /// Offset of first byte in range. /// Offset of last byte in range. /// String sub-type. - private void CreateLengthStringEntries(int low, int high, + private void CreateLengthStringEntries(int low, int high, FormatDescriptor.Type type, FormatDescriptor.SubType subType) { int i; for (i = low; i <= high;) { int length = mFileData[i]; - if (subType == FormatDescriptor.SubType.L16String) { + if (type == FormatDescriptor.Type.StringL16) { length |= mFileData[i + 1] << 8; length += 2; } else { length++; } // Zero-length strings are allowed. - FormatDescriptor dfd = FormatDescriptor.Create(length, - FormatDescriptor.Type.String, subType); + FormatDescriptor dfd = FormatDescriptor.Create(length, type, subType); Results.Add(i, dfd); i += length; } @@ -927,36 +919,25 @@ namespace SourceGen.WpfGui { /// Offset of first byte in range. /// Offset of last byte in range. /// String sub-type. - private void CreateDciStringEntries(int low, int high, + private void CreateDciStringEntries(int low, int high, FormatDescriptor.Type type, FormatDescriptor.SubType subType) { - int start, end, adj, endMask; - if (subType == FormatDescriptor.SubType.Dci) { - start = low; - end = high + 1; - adj = 1; - } else if (subType == FormatDescriptor.SubType.DciReverse) { - start = high; - end = low - 1; - adj = -1; - } else { - Debug.Assert(false); - return; - } + int end, endMask; + + end = high + 1; // Zero-length strings aren't a thing for DCI. The analyzer requires that all // strings in a region have the same polarity, so just grab the last byte. endMask = mFileData[end - 1] & 0x80; - int stringStart = start; - for (int i = start; i != end; i += adj) { + int stringStart = low; + for (int i = low; i != end; i++) { byte val = mFileData[i]; if ((val & 0x80) == endMask) { // found the end of a string - int length = (i - stringStart) * adj + 1; - FormatDescriptor dfd = FormatDescriptor.Create(length, - FormatDescriptor.Type.String, subType); + int length = (i - stringStart) + 1; + FormatDescriptor dfd = FormatDescriptor.Create(length, type, subType); Results.Add(stringStart < i ? stringStart : i, dfd); - stringStart = i + adj; + stringStart = i + 1; } } diff --git a/SourceGen/WpfGui/EditInstructionOperand.xaml.cs b/SourceGen/WpfGui/EditInstructionOperand.xaml.cs index 0ed0c38..33b2fdd 100644 --- a/SourceGen/WpfGui/EditInstructionOperand.xaml.cs +++ b/SourceGen/WpfGui/EditInstructionOperand.xaml.cs @@ -333,6 +333,7 @@ namespace SourceGen.WpfGui { preview.Append(mFormatter.FormatBinaryValue(mOperandValue, 8)); break; case FormatDescriptor.SubType.Ascii: + // TODO(petscii): encoding preview.Append(mFormatter.FormatAsciiOrHex(mOperandValue)); break; case FormatDescriptor.SubType.Symbol: @@ -470,6 +471,7 @@ namespace SourceGen.WpfGui { binaryButton.IsChecked = true; break; case FormatDescriptor.SubType.Ascii: + // TODO(petscii): encoding asciiButton.IsChecked = true; break; case FormatDescriptor.SubType.Symbol: @@ -499,7 +501,13 @@ namespace SourceGen.WpfGui { } break; case FormatDescriptor.Type.NumericBE: - case FormatDescriptor.Type.String: + case FormatDescriptor.Type.StringGeneric: + case FormatDescriptor.Type.StringReverse: + case FormatDescriptor.Type.StringNullTerm: + case FormatDescriptor.Type.StringL8: + case FormatDescriptor.Type.StringL16: + case FormatDescriptor.Type.StringDci: + case FormatDescriptor.Type.Dense: case FormatDescriptor.Type.Fill: default: // Unexpected; used to be data? @@ -543,6 +551,7 @@ namespace SourceGen.WpfGui { } else if (binaryButton.IsChecked == true) { subType = FormatDescriptor.SubType.Binary; } else if (asciiButton.IsChecked == true) { + // TODO(petscii): encoding subType = FormatDescriptor.SubType.Ascii; } else if (symbolButton.IsChecked == true) { subType = FormatDescriptor.SubType.Symbol;