public ZMemory(byte[] data, Action restart) { _restart = restart; Header = new ZHeader(data.AsSpan(0, 31)); if (Header.Version > 5) { throw new NotSupportedException("ZMachine > V5 not currently supported"); } // Version specific offsets Offsets = VersionedOffsets.For(Header.Version); Manager = new MemoryManager(data); // ZMachine tables Abbreviations = new ZAbbreviations(Header, Manager); Dictionary = new ZDictionary(Header, Manager, Abbreviations); ObjectTree = new ZObjectTree(Header, Manager, Abbreviations); Globals = new ZGlobals(Header, Manager); // Custom Stack with some abstractions for better testing. Stack = new ZStack(); // Simple managers to abstract variable and argument usage VariableManager = new VariableManager(Stack, Globals); OperandManager = new OperandManager(Manager, Stack, VariableManager); }
public ZObjectTree(ZHeader header, IMemoryManager manager, ZAbbreviations abbreviations) { _header = header; var objectTableData = manager.AsSpan(header.ObjectTable);// memory.AsSpan(header.ObjectTable); var(defaultProps, ptr) = GetDefaultProps(objectTableData); DefaultProperties = defaultProps; var lastObject = false; ushort objNumber = 1; _dict = new Dictionary <ushort, IZMachineObject>(); while (!lastObject && objNumber < 255) { // Objects end when the properties start! ushort objectAddress = (ushort)(header.ObjectTable + ptr); var min = _dict.Values.Any() ? _dict.Values.Min(v => v.PropertiesAddress) : ushort.MaxValue; lastObject = objectAddress >= min; if (!lastObject) { var zObj = new ZMachineObject(objNumber, objectAddress, header, manager, abbreviations, DefaultProperties); _dict.Add(objNumber, zObj); ptr += zObj.BytesRead; objNumber++; } } }
public ZsciiString(Span <byte> data, ZAbbreviations abbreviations, ZHeader header, int zsciiWordsToUse = int.MaxValue) { _v2CharProvider = new V2CharProvider(abbreviations); _header = header; var chars = GetZsciiChars(data, zsciiWordsToUse); BytesUsed = (ushort)(chars.Count / 3 * 2); String = DecodeZsciiChars(chars, abbreviations); }
public ZDictionary(ZHeader header, IMemoryManager manager, ZAbbreviations abbreviations) { var bytes = manager.AsSpan(header.Dictionary); ushort addr = 0; var numOfInputCodes = bytes[addr++]; InputCodes = bytes.AsSpan(addr, numOfInputCodes).ToArray(); addr += numOfInputCodes; var zsciiStringArray = new ZsciiStringArray(bytes.AsSpan(addr), abbreviations, header); Words = zsciiStringArray.Words; EntryLength = zsciiStringArray.EntryLength; WordStart = (ushort)(addr + zsciiStringArray.WordStart); }
public ZsciiStringArray(Span <byte> data, ZAbbreviations abbreviations, ZHeader header) { var bytes = data.ToArray(); ushort ptr = 0; EntryLength = bytes[ptr++]; var numEntries = bytes.GetUShort(ptr); ptr += 2; WordStart = ptr; Words = new string[numEntries]; for (var i = 0; i < numEntries; i++) { var stringData = bytes.AsSpan(ptr); var zStr = new ZsciiString(stringData, abbreviations, header, header.Version <= 3 ? 2 : 3); ptr += EntryLength; Words[i] = zStr.String; } }
private string DecodeZsciiChars(List <byte> zChars, ZAbbreviations abbreviations) { _v2CharProvider.ResetTable(); var sb = new StringBuilder(); for (var i = 0; i < zChars.Count; i++) { if (zChars[i] == 0x00) { sb.Append(" "); } else if (_header.Version <= 2) { var zChar = zChars[i]; if (zChar == 1) { var abbrIdx = zChars[++i]; sb.Append(abbreviations.Abbreviations[abbrIdx]); } else { var(zCharTable, inc) = _v2CharProvider.GetCharTable(zChar); i += inc; if (i < zChars.Count) { zChar = zChars[i]; if (zChar == 6 && zCharTable[0] == ' ') { ushort x = (ushort)(zChars[i + 1] << 5 | zChars[i + 2]); sb.Append(Convert.ToChar(x)); i += 2; } if (zChar > 5) { var realChar = zCharTable[zChar - 6]; sb.Append(realChar); } } } } // else if (zChars[i] >= 0x01 && zChars[i] <= 0x03) // { // ushort offset = (ushort)(32 * (chars[i] - 1) + chars[++i]); // ushort lookup = (ushort)(_abbreviationsTable + (offset * 2)); // ushort wordAddr = GetWord(lookup); // List<byte> abbrev = GetZsciiChars((ushort)(wordAddr * 2)); // sb.Append(DecodeZsciiChars(abbrev)); // } // else if (zChars[i] == 0x02 && _header.Version <= 2) // { // sb.Append(Convert.ToChar((zChars[++i] - 6) + 'A')); // } // else if (zChars[i] == 0x03 && _header.Version <= 2) // { // if (zChars.Count < i + 1) // { // sb.Append(Table[zChars[++i] - 6]); // } // } // else if (zChars[i] == 0x04 && _header.Version <= 2) // { // sb.Append(Convert.ToChar((zChars[++i] - 6) + 'A')); // } // else if (zChars[i] == 0x05 && _header.Version <= 2) // { // if (zChars.Count < i + 1) // { // sb.Append(Table[zChars[++i] - 6]); // } // } else if (abbreviations != null && IsAbbreviation(zChars[i])) { if (i + 1 <= zChars.Count - 1) { var offset = (ushort)(32 * (zChars[i] - 1) + zChars[++i]); sb.Append(abbreviations.Abbreviations[offset]); } } else if (zChars[i] == 0x04) { sb.Append(Convert.ToChar((zChars[++i] - 6) + 'A')); } else if (zChars[i] == 0x05) { if (i == zChars.Count - 1 || zChars[i + 1] == 0x05) { break; } if (zChars[i + 1] == 0x06) { var x = (ushort)(zChars[i + 2] << 5 | zChars[i + 3]); i += 3; sb.Append(Convert.ToChar(x)); } else if (zChars[i + 1] == 0x07) { sb.AppendLine(""); i++; } else { sb.Append(Table[zChars[++i] - 6]); } } else { sb.Append(Convert.ToChar((zChars[i] - 6) + 'a')); } } return(sb.ToString()); }
public static string Get(Span <byte> data, ZAbbreviations abbreviations, ZHeader header) => new ZsciiString(data, abbreviations, header).String;