/// <summary> /// Writes BND0 data to a BinaryWriterEx. /// </summary> protected override void Write(BinaryWriterEx bw) { bw.BigEndian = false; bw.WriteASCII("BND\0"); if (Lite) { bw.ReserveInt32("FileSize"); bw.WriteInt32(Files.Count); bw.WriteInt32(0); } else { bw.WriteInt32(0xF7FF); bw.WriteInt32(0xD3); bw.ReserveInt32("FileSize"); bw.WriteInt32(Files.Count); bw.WriteInt32(0); bw.WriteByte(Flag1); bw.WriteByte(Flag2); bw.WriteByte(3); bw.WriteByte(0); bw.WriteInt32(0); bw.WriteInt32(0); } for (int i = 0; i < Files.Count; i++) { Files[i].Write(bw, Lite, i); } for (int i = 0; i < Files.Count; i++) { File file = Files[i]; bw.Pad(0x20); bw.FillInt32($"FileOffset{i}", (int)bw.Position); if (Lite) { bw.WriteInt32(file.Bytes.Length + 4); bw.WriteBytes(file.Bytes); } else { bw.WriteBytes(file.Bytes); } } bw.FillInt32("FileSize", (int)bw.Position); }
internal void WriteValue(BinaryWriterEx bw, object value) { switch (Type) { case ParamType.aob: bw.WriteBytes((byte[])value); break; case ParamType.b: bw.WriteBoolean((bool)value); break; case ParamType.u8: case ParamType.x8: bw.WriteByte((byte)value); break; case ParamType.s8: bw.WriteSByte((sbyte)value); break; case ParamType.u16: case ParamType.x16: bw.WriteUInt16((ushort)value); break; case ParamType.s16: bw.WriteInt16((short)value); break; case ParamType.u32: case ParamType.x32: bw.WriteUInt32((uint)value); break; case ParamType.s32: bw.WriteInt32((int)value); break; case ParamType.u64: case ParamType.x64: bw.WriteUInt64((ulong)value); break; case ParamType.s64: bw.WriteInt64((long)value); break; case ParamType.f32: bw.WriteSingle((float)value); break; case ParamType.f64: bw.WriteDouble((double)value); break; default: throw new Exception($"Invalid ParamTemplate ParamType: {Type.ToString()}"); } }
internal void WriteData(BinaryWriterEx bw, int animIndex, int eventIndex, TAEFormat format) { CopyParametersToBytes(bw.BigEndian); bw.FillVarint($"EventDataOffset{animIndex}:{eventIndex}", bw.Position); bw.WriteInt32(Type); if (format != TAEFormat.DS1) { bw.WriteInt32(Unk04); } if (format == TAEFormat.SDT && Type == 943) { bw.WriteVarint(0); } else { bw.WriteVarint(bw.Position + (bw.VarintLong ? 8 : 4)); } bw.WriteBytes(ParameterBytes); if (format != TAEFormat.DS1) { bw.Pad(0x10); } }
public void Write(BinaryWriterEx bw) { bw.WriteASCII(Name); bw.WriteInt32(Bytes.Length); bw.WriteInt32(Count); bw.WriteInt32(0); bw.WriteBytes(Bytes); }
public byte[] Write() { using (var ms = new MemoryStream()) { var bw = new BinaryWriterEx(false, ms); bw.WriteBytes(Data); bw.Position = 8; bw.WriteInt32(SteamID); bw.Position = 0x1098; bw.WriteBooleans(OccupiedSlots); for (int i = 0; i < 10; i++) { bw.Position = 0x10A2 + 0x22A * i; bw.WriteBytes(SlotData[i]); } return(bw.FinishBytes()); } }
public void WriteData(BinaryWriterEx bw) { uint absoluteOffset = (uint)bw.Position; bw.FillUInt32("absoffset" + SectionID, absoluteOffset); bw.WriteBytes(SectionData); while ((bw.Position % 16) != 0) { bw.WriteByte(0xFF); // 16 byte align } // Local fixups bw.FillUInt32("locoffset" + SectionID, (uint)bw.Position - absoluteOffset); foreach (var loc in LocalFixups) { loc.Write(bw); } while ((bw.Position % 16) != 0) { bw.WriteByte(0xFF); // 16 byte align } // Global fixups bw.FillUInt32("globoffset" + SectionID, (uint)bw.Position - absoluteOffset); foreach (var glob in GlobalFixups) { glob.Write(bw); } while ((bw.Position % 16) != 0) { bw.WriteByte(0xFF); // 16 byte align } // Virtual fixups bw.FillUInt32("virtoffset" + SectionID, (uint)bw.Position - absoluteOffset); foreach (var virt in VirtualFixups) { virt.Write(bw); } while ((bw.Position % 16) != 0) { bw.WriteByte(0xFF); // 16 byte align } bw.FillUInt32("expoffset" + SectionID, (uint)bw.Position - absoluteOffset); bw.FillUInt32("impoffset" + SectionID, (uint)bw.Position - absoluteOffset); bw.FillUInt32("endoffset" + SectionID, (uint)bw.Position - absoluteOffset); }
public void WriteStandardValueTypeToRaw(BinaryWriterEx bw, object value) { switch (ValueType) { case "aob": bw.WriteBytes((byte[])value); break; case "b": bw.WriteBoolean((bool)value); break; case "u8": case "x8": bw.WriteByte((byte)value); break; case "s8": bw.WriteSByte((sbyte)value); break; case "u16": case "x16": bw.WriteUInt16((ushort)value); break; case "s16": bw.WriteInt16((short)value); break; case "u32": case "x32": bw.WriteUInt32((uint)value); break; case "s32": bw.WriteInt32((int)value); break; case "u64": case "x64": bw.WriteUInt64((ulong)value); break; case "s64": bw.WriteInt64((long)value); break; case "f32": bw.WriteSingle((float)value); break; case "f64": bw.WriteDouble((double)value); break; default: throw new Exception($"Value type '{ValueType}' is not a standard type " + $"and must be handled manually instead of calling {nameof(XmlStructDefField)}." + $"{nameof(WriteStandardValueTypeToRaw)}."); } }
internal void WriteDefaultValue(BinaryWriterEx bw) { if (ValueToAssert != null) { WriteAssertValue(bw); } else if (DefaultValue == null) { switch (Type) { case ParamType.aob: for (int i = 0; i < AobLength; i++) { bw.WriteByte(0); } break; case ParamType.b: case ParamType.u8: case ParamType.x8: bw.WriteByte(0); break; case ParamType.s8: bw.WriteSByte(0); break; case ParamType.u16: case ParamType.x16: bw.WriteUInt16(0); break; case ParamType.s16: bw.WriteInt16(0); break; case ParamType.u32: case ParamType.x32: bw.WriteUInt32(0); break; case ParamType.s32: bw.WriteInt32(0); break; case ParamType.u64: case ParamType.x64: bw.WriteUInt64(0); break; case ParamType.s64: bw.WriteInt64(0); break; case ParamType.f32: bw.WriteSingle(0); break; case ParamType.f64: bw.WriteDouble(0); break; default: throw new Exception($"Invalid ParamTemplate ParamType: {Type.ToString()}"); } } else { switch (Type) { case ParamType.aob: var assertAob = (byte[])DefaultValue; bw.WriteBytes(assertAob); break; case ParamType.b: case ParamType.u8: case ParamType.x8: bw.WriteByte((byte)DefaultValue); break; case ParamType.s8: bw.WriteSByte((sbyte)DefaultValue); break; case ParamType.u16: case ParamType.x16: bw.WriteUInt16((ushort)DefaultValue); break; case ParamType.s16: bw.WriteInt16((short)DefaultValue); break; case ParamType.u32: case ParamType.x32: bw.WriteUInt32((uint)DefaultValue); break; case ParamType.s32: bw.WriteInt32((int)DefaultValue); break; case ParamType.u64: case ParamType.x64: bw.WriteUInt64((ulong)DefaultValue); break; case ParamType.s64: bw.WriteInt64((long)DefaultValue); break; case ParamType.f32: bw.WriteSingle((float)DefaultValue); break; case ParamType.f64: bw.WriteDouble((double)DefaultValue); break; default: throw new Exception($"Invalid ParamTemplate ParamType: {Type.ToString()}"); } } }
protected override void Write(BinaryWriterEx bw) { bw.WriteASCII("TAE "); bw.BigEndian = BigEndian; bw.WriteBoolean(BigEndian); bw.WriteByte(0); bw.WriteByte(0); if (Format == TAEFormat.DS1) { bw.VarintLong = false; bw.WriteByte(0); } else { bw.VarintLong = true; bw.WriteByte(0xFF); } if (Format == TAEFormat.DS1) { bw.WriteInt32(0x1000B); } else if (Format == TAEFormat.DS3 || Format == TAEFormat.SOTFS) { bw.WriteInt32(0x1000C); } else if (Format == TAEFormat.SDT) { bw.WriteInt32(0x1000D); } bw.ReserveInt32("FileSize"); bw.WriteVarint(0x40); bw.WriteVarint(1); bw.WriteVarint(0x50); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x70 : 0x80); if (Format == TAEFormat.DS1) { bw.WriteInt16(2); bw.WriteInt16(1); } else { bw.WriteVarint(EventBank); } bw.WriteVarint(0); //DeS also if (Format == TAEFormat.DS1) { bw.WriteInt64(0); bw.WriteInt64(0); bw.WriteInt64(0); } bw.WriteBytes(Flags); if (Format == TAEFormat.SOTFS) { bw.WriteByte(0); bw.WriteByte(1); } else { bw.WriteByte(1); bw.WriteByte(0); } for (int i = 0; i < 6; i++) { bw.WriteByte(0); } bw.WriteInt32(ID); bw.WriteInt32(Animations.Count); bw.ReserveVarint("AnimsOffset"); bw.ReserveVarint("AnimGroupsOffset"); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x90 : 0xA0); bw.WriteVarint(Animations.Count); bw.ReserveVarint("FirstAnimOffset"); if (Format == TAEFormat.DS1) { bw.WriteInt32(0); } bw.WriteVarint(1); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x80 : 0x90); if (Format == TAEFormat.DS1) { bw.WriteInt64(0); } bw.WriteInt32(ID); bw.WriteInt32(ID); bw.WriteVarint(0x50); bw.WriteInt64(0); bw.WriteVarint(Format == TAEFormat.DS1 ? 0x98 : 0xB0); bw.ReserveVarint("SkeletonName"); bw.ReserveVarint("SibName"); if (Format != TAEFormat.SOTFS) { bw.WriteVarint(0); bw.WriteVarint(0); } bw.FillVarint("SkeletonName", bw.Position); if (!string.IsNullOrEmpty(SkeletonName)) { bw.WriteUTF16(SkeletonName, true); if (Format != TAEFormat.DS1) { bw.Pad(0x10); } } bw.FillVarint("SibName", bw.Position); if (!string.IsNullOrEmpty(SibName)) { bw.WriteUTF16(SibName, true); if (Format != TAEFormat.DS1) { bw.Pad(0x10); } } Animations.Sort((a1, a2) => a1.ID.CompareTo(a2.ID)); var animOffsets = new List <long>(Animations.Count); if (Animations.Count == 0) { bw.FillVarint("AnimsOffset", 0); } else { bw.FillVarint("AnimsOffset", bw.Position); for (int i = 0; i < Animations.Count; i++) { animOffsets.Add(bw.Position); Animations[i].WriteHeader(bw, i); } } bw.FillVarint("AnimGroupsOffset", bw.Position); bw.ReserveVarint("AnimGroupsCount"); bw.ReserveVarint("AnimGroupsOffset"); int groupCount = 0; long groupStart = bw.Position; for (int i = 0; i < Animations.Count; i++) { int firstIndex = i; bw.WriteInt32((int)Animations[i].ID); while (i < Animations.Count - 1 && Animations[i + 1].ID == Animations[i].ID + 1) { i++; } bw.WriteInt32((int)Animations[i].ID); bw.WriteVarint(animOffsets[firstIndex]); groupCount++; } bw.FillVarint("AnimGroupsCount", groupCount); if (groupCount == 0) { bw.FillVarint("AnimGroupsOffset", 0); } else { bw.FillVarint("AnimGroupsOffset", groupStart); } if (Animations.Count == 0) { bw.FillVarint("FirstAnimOffset", 0); } else { bw.FillVarint("FirstAnimOffset", bw.Position); for (int i = 0; i < Animations.Count; i++) { Animations[i].WriteBody(bw, i, Format); } } for (int i = 0; i < Animations.Count; i++) { Animation anim = Animations[i]; anim.WriteAnimFile(bw, i, Format); Dictionary <float, long> timeOffsets = anim.WriteTimes(bw, i, Format); List <long> eventHeaderOffsets = anim.WriteEventHeaders(bw, i, timeOffsets); anim.WriteEventData(bw, i, Format); anim.WriteEventGroupHeaders(bw, i, Format); anim.WriteEventGroupData(bw, i, eventHeaderOffsets, Format); } bw.FillInt32("FileSize", (int)bw.Position); }
public void WriteWithContext(BinaryWriterEx bw, EzSembleContext context) { bw.WriteASCII(ESDMagicByFormat[FormatType]); bw.BigEndian = (FormatType == ESDFormatType.BigEndian32Bit || FormatType == ESDFormatType.BigEndian64Bit); context.IsBigEndian = bw.BigEndian; bw.WriteInt32(1); bw.WriteInt32(DarkSoulsCount); bw.WriteInt32(DarkSoulsCount); bw.WriteInt32(0x54); bw.ReserveInt32("DataSize"); bw.WriteInt32(6); bw.WriteInt32(LongFormat ? 0x48 : 0x2C); bw.WriteInt32(1); bw.WriteInt32(LongFormat ? 0x20 : 0x10); bw.WriteInt32(StateGroups.Count); int stateSize = LongFormat ? 0x48 : 0x24; bw.WriteInt32(stateSize); bw.WriteInt32(StateGroups.Values.Sum(sg => sg.Count + (sg.Count == 1 ? 0 : 1))); bw.WriteInt32(LongFormat ? 0x38 : 0x1C); bw.ReserveInt32("ConditionCount"); bw.WriteInt32(LongFormat ? 0x18 : 0x10); bw.ReserveInt32("CommandCallCount"); bw.WriteInt32(LongFormat ? 0x10 : 0x8); bw.ReserveInt32("CommandArgCount"); bw.ReserveInt32("ConditionOffsetsOffset"); bw.ReserveInt32("ConditionOffsetsCount"); bw.ReserveInt32("NameBlockOffset"); bw.WriteInt32(Name == null ? 0 : Name.Length + 1); bw.ReserveInt32("UnkOffset1"); bw.WriteInt32(0); bw.ReserveInt32("UnkOffset2"); bw.WriteInt32(0); long dataStart = bw.Position; bw.WriteInt32(Unk6C); bw.WriteInt32(Unk70); bw.WriteInt32(Unk74); bw.WriteInt32(Unk78); bw.WriteInt32(Unk7C); if (LongFormat) { bw.WriteInt32(0); } ReserveVarint(bw, LongFormat, "StateGroupsOffset"); WriteVarint(bw, LongFormat, StateGroups.Count); ReserveVarint(bw, LongFormat, "NameOffset"); WriteVarint(bw, LongFormat, Name == null ? 0 : Name.Length + 1); long unkNull = DarkSoulsCount == 1 ? 0 : -1; WriteVarint(bw, LongFormat, unkNull); WriteVarint(bw, LongFormat, unkNull); // Collect and sort all the IDs so everything is definitely in the same order everywhere List <long> stateGroupIDs = StateGroups.Keys.ToList(); stateGroupIDs.Sort(); var stateIDs = new Dictionary <long, List <long> >(); foreach (long groupID in stateGroupIDs) { stateIDs[groupID] = StateGroups[groupID].Keys.ToList(); stateIDs[groupID].Sort(); } if (StateGroups.Count == 0) { FillVarint(bw, LongFormat, "StateGroupsOffset", -1); } else { FillVarint(bw, LongFormat, "StateGroupsOffset", bw.Position - dataStart); foreach (long groupID in stateGroupIDs) { WriteVarint(bw, LongFormat, groupID); ReserveVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset1"); WriteVarint(bw, LongFormat, StateGroups[groupID].Count); ReserveVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset2"); } } var stateOffsets = new Dictionary <long, Dictionary <long, long> >(); var weirdStateOffsets = new List <long[]>(); foreach (long groupID in stateGroupIDs) { stateOffsets[groupID] = new Dictionary <long, long>(); FillVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset1", bw.Position - dataStart); FillVarint(bw, LongFormat, $"StateGroup{groupID}:StatesOffset2", bw.Position - dataStart); long firstStateOffset = bw.Position; foreach (long stateID in stateIDs[groupID]) { stateOffsets[groupID][stateID] = bw.Position - dataStart; StateGroups[groupID][stateID].WriteHeader(context, bw, LongFormat, groupID, stateID); } if (StateGroups[groupID].Count > 1) { weirdStateOffsets.Add(new long[] { firstStateOffset, bw.Position }); bw.Position += stateSize; } } // Make a list of every unique condition var conditions = new Dictionary <long, List <Condition> >(); foreach (long groupID in stateGroupIDs) { conditions[groupID] = new List <Condition>(); void addCondition(Condition cond) { if (!conditions[groupID].Any(c => ReferenceEquals(cond, c))) { conditions[groupID].Add(cond); foreach (Condition subCond in cond.Subconditions) { addCondition(subCond); } } } foreach (State state in StateGroups[groupID].Values) { foreach (Condition cond in state.Conditions) { addCondition(cond); } } } bw.FillInt32("ConditionCount", conditions.Values.Sum(group => group.Count)); // Yes, I do in fact want this to be keyed by reference var conditionOffsets = new Dictionary <Condition, long>(); foreach (long groupID in stateGroupIDs) { for (int i = 0; i < conditions[groupID].Count; i++) { Condition cond = conditions[groupID][i]; cond.MetaRefID = conditionOffsets[cond] = bw.Position - dataStart; cond.WriteHeader(context, bw, LongFormat, groupID, i, stateOffsets[groupID]); } } var commands = new List <CommandCall>(); foreach (long groupID in stateGroupIDs) { foreach (long stateID in stateIDs[groupID]) { StateGroups[groupID][stateID].WriteCommandCalls(context, bw, LongFormat, groupID, stateID, dataStart, commands); } for (int i = 0; i < conditions[groupID].Count; i++) { conditions[groupID][i].WriteCommandCalls(context, bw, LongFormat, groupID, i, dataStart, commands); } } bw.FillInt32("CommandCallCount", commands.Count); bw.FillInt32("CommandArgCount", commands.Sum(command => command.Arguments.Count)); for (int i = 0; i < commands.Count; i++) { commands[i].WriteArgs(context, bw, LongFormat, i, dataStart); } bw.FillInt32("ConditionOffsetsOffset", (int)(bw.Position - dataStart)); int conditionOffsetsCount = 0; foreach (long groupID in stateGroupIDs) { foreach (long stateID in stateIDs[groupID]) { conditionOffsetsCount += StateGroups[groupID][stateID].WriteConditionOffsets(bw, LongFormat, groupID, stateID, dataStart, conditionOffsets); } for (int i = 0; i < conditions[groupID].Count; i++) { conditionOffsetsCount += conditions[groupID][i].WriteConditionOffsets(bw, LongFormat, groupID, i, dataStart, conditionOffsets); } } bw.FillInt32("ConditionOffsetsCount", conditionOffsetsCount); foreach (long groupID in stateGroupIDs) { for (int i = 0; i < conditions[groupID].Count; i++) { conditions[groupID][i].WriteEvaluator(context, bw, LongFormat, groupID, i, dataStart); } } for (int i = 0; i < commands.Count; i++) { commands[i].WriteBytecode(context, bw, LongFormat, i, dataStart); } bw.FillInt32("NameBlockOffset", (int)(bw.Position - dataStart)); if (Name == null) { FillVarint(bw, LongFormat, "NameOffset", -1); } else { bw.Pad(2); FillVarint(bw, LongFormat, "NameOffset", bw.Position - dataStart); bw.WriteUTF16(Name, true); } bw.FillInt32("UnkOffset1", (int)(bw.Position - dataStart)); bw.FillInt32("UnkOffset2", (int)(bw.Position - dataStart)); bw.FillInt32("DataSize", (int)(bw.Position - dataStart)); if (DarkSoulsCount == 1) { bw.Pad(4); } else if (DarkSoulsCount == 2) { bw.Pad(0x10); } foreach (long[] offsets in weirdStateOffsets) { bw.Position = offsets[0]; byte[] bytes = new byte[stateSize]; bw.Stream.Read(bytes, 0, stateSize); bw.Position = offsets[1]; bw.WriteBytes(bytes); } LastSavedHash = bw.GetMD5HashOfStream(); Metadata = ESDMetadata.Generate(this); }
private static void Parse(string plaintext, BinaryWriterEx bw, int current, ref int next) { if (current == 0 && plaintext[current] == '.') { throw new Exception("Cannot start with an abort if previous number is false byte"); } else if (current == 0 && plaintext[current] == '~') { throw new Exception("Cannot start with a continuation byte thing or whatever"); } // Number literal if (plaintext[current] == '-' || char.IsDigit(plaintext[current])) { // Is subtract and not a literal if (plaintext[current] == '-' && (next == plaintext.Length || !char.IsDigit(plaintext[next]))) { bw.WriteByte(BytesByOperator["-"]); } else { while (next < plaintext.Length && char.IsDigit(plaintext[next])) { next++; } if (next + 1 < plaintext.Length && plaintext[next] == '.' && char.IsDigit(plaintext[next + 1])) { next++; while (next < plaintext.Length && char.IsDigit(plaintext[next])) { next++; } } string str = plaintext.Substring(current, next - current); double value = double.Parse(str); if (value == Math.Floor(value)) { if (value >= -64 && value <= 63) { bw.WriteByte((byte)(value + 64)); } else { bw.WriteByte((byte)0x82); bw.WriteInt32((int)value); } } else if (value == (float)value) { bw.WriteByte((byte)0x80); bw.WriteSingle((float)value); } else { bw.WriteByte((byte)0x81); bw.WriteDouble(value); } } } // String literal else if (plaintext[current] == '"') { while (next < plaintext.Length && plaintext[next] != '"') { next++; } if (next == plaintext.Length) { throw new Exception("Unclosed string literal"); } string value = plaintext.Substring(current + 1, next - current - 1); if (value.Contains('\r') || value.Contains('\n')) { throw new Exception("String literals may not contain newlines"); } bw.WriteByte((byte)0xA5); bw.WriteBytes(bw.BigEndian ? Encoding.BigEndianUnicode.GetBytes(value + "\0") : Encoding.Unicode.GetBytes(value + "\0")); next++; } // Add else if (plaintext[current] == '+') { bw.WriteByte(BytesByOperator["+"]); } // Multiply else if (plaintext[current] == '*') { bw.WriteByte(BytesByOperator["*"]); } // Negate else if (plaintext[current] == 'N' || plaintext[current] == 'n') { bw.WriteByte(BytesByOperator["N"]); } else if (plaintext[current] == '/') { // Comment if (next < plaintext.Length && plaintext[next] == '/') { while (next < plaintext.Length && plaintext[next] != '\n') { next++; } next++; } // Divide else { bw.WriteByte(BytesByOperator["/"]); } } else if (plaintext[current] == '<') { // Less than or equal to if (next < plaintext.Length && plaintext[next] == '=') { bw.WriteByte(BytesByOperator["<="]); next++; } // Less than else { bw.WriteByte(BytesByOperator["<"]); } } else if (plaintext[current] == '>') { // Set register if (next < plaintext.Length && plaintext[next] == '[') { if (next + 2 >= plaintext.Length || plaintext[next + 2] != ']') { throw new Exception("Malformed register storage"); } if (!"01234567".Contains(plaintext[next + 1])) { throw new Exception("Register must be from 0-7"); } bw.WriteByte((byte)(0xA7 + byte.Parse(plaintext[next + 1].ToString()))); next += 3; } // Greater than or equal to else if (next < plaintext.Length && plaintext[next] == '=') { bw.WriteByte(BytesByOperator[">="]); next++; } // Greater than else { bw.WriteByte(BytesByOperator[">"]); } } // Equal to else if (plaintext[current] == '=') { if (next == plaintext.Length || plaintext[next] != '=') { throw new Exception("Orphaned = found"); } bw.WriteByte(BytesByOperator["=="]); next++; } // Not equal to else if (plaintext[current] == '!') { if (next == plaintext.Length || plaintext[next] != '=') { throw new Exception("Orphaned ! found"); } bw.WriteByte(BytesByOperator["!="]); next++; } // Logical and else if (plaintext[current] == '&') { if (next == plaintext.Length || plaintext[next] != '&') { throw new Exception("Orphaned & found"); } bw.WriteByte(BytesByOperator["&&"]); next++; } // Logical or else if (plaintext[current] == '|') { if (next == plaintext.Length || plaintext[next] != '|') { throw new Exception("Orphaned | found"); } bw.WriteByte(BytesByOperator["||"]); next++; } // Function call else if (plaintext[current] == '(') { if (next + 1 >= plaintext.Length || plaintext[next + 1] != ')') { throw new Exception("Unclosed function call"); } if (!"0123456".Contains(plaintext[next])) { throw new Exception("Function call must take 0-6 arguments"); } bw.WriteByte((byte)(0x84 + byte.Parse(plaintext[next].ToString()))); next += 2; } // Get register else if (plaintext[current] == '[') { if (next + 2 >= plaintext.Length || plaintext[next + 1] != ']' || plaintext[next + 2] != '>') { throw new Exception("Malformed register retrieval"); } if (!"01234567".Contains(plaintext[next])) { throw new Exception("Register must be from 0-7"); } bw.WriteByte((byte)(0xAF + byte.Parse(plaintext[next].ToString()))); next += 3; } // ~ or . else if (BytesByTerminator.ContainsKey(plaintext[current])) { bw.WriteByte(BytesByTerminator[plaintext[current]]); } // Unknown opcode else if (plaintext[current] == '#') { if (next + 1 >= plaintext.Length) { throw new Exception("Hex literal too short"); } bw.WriteByte(Convert.ToByte(plaintext.Substring(current + 1, 2), 16)); next += 2; } // Whitespace else if (char.IsWhiteSpace(plaintext[current])) { while (next < plaintext.Length && char.IsWhiteSpace(plaintext[next])) { next++; } } // Uh-oh else { throw new Exception($"Unknown character: {plaintext[current]}"); } }