public ISSNode GetNode(IAcSmComponent item) { ISSNode node = null; var typeName = item.GetTypeName(); switch (typeName) { case "AcSmSheet": node = new SheetNode((AcSmSheet)item, this); break; case "AcSmSubset": node = new SubsetNode((AcSmSubset)item, this); break; } return(node); }
public JsonParser(string text) { //var root = JSON.Parse(text); var root = JToken.Parse(text); Sheets = new List <SheetNode>(); Nested = new List <SheetNode>(); foreach (var item in root[JsonSheets]) { var sheet = new SheetNode(item); if (sheet.NestedType) { Nested.Add(sheet); } else { Sheets.Add(sheet); } } }
/// <summary> /// Saves this <see cref="CnvrsTextFile"/> to the specified path. /// </summary> /// <param name="path">A string that contains the name of the path.</param> public void Save(string path) { using (var destination = new FileStream(path, FileMode.Create, FileAccess.Write)) using (var writer = new BinaryWriter(destination, Encoding.Unicode)) { // Create the lists and dictionaries to hold offset information var offsets = new List <long>(); var nameOffsets = new Dictionary <string, long>(); var sheetNodes = new Dictionary <string, SheetNode>(); var fontNodes = new Dictionary <string, FontNode>(); var layoutNodes = new Dictionary <string, LayoutNode>(); // A helper method to reduce the amount of code we need to write // For this to work as expected, offsets need to be written in the order they appear within the file. void writeOffset(long value) { offsets.Add(destination.Position); writer.WriteInt64(value); } // BINA section writer.Write(Encoding.UTF8.GetBytes("BINA210L")); // Always write as little endian writer.WriteInt32(0); // File length (filled in later) writer.WriteInt32(1); // DATA section writer.Write(Encoding.UTF8.GetBytes("DATA")); writer.WriteInt32(0); // Length of this section (filled in later) writer.WriteInt32(0); // Offset of name entry table (filled in later) writer.WriteInt32(0); // Length of name entry table (filled in later) writer.WriteInt32(0); // Length of final offset table (filled in later) writer.WriteInt32(24); writer.Write(new byte[24]); // 24 null bytes // Sheet entry table foreach (var(name, sheet) in Sheets) { if (!languageCodes.ContainsKey(name)) { throw new KeyNotFoundException(string.Format(Resources.InvalidSheetName, name)); } var sheetNode = new SheetNode { EntryPosition = destination.Position, }; sheetNodes.Add(name, sheetNode); writer.WriteByte(6); writer.WriteByte(languageCodes[name]); writer.WriteInt16((short)sheet.Count); writer.WriteInt32(0); // 4 null bytes writeOffset(0); // Primary entry offset (filled in later) writeOffset(0); // Sheet name offset (filled in later) writer.WriteInt64(0); // 8 null bytes } // Primary entries (per sheet) foreach (var(sheetName, sheet) in Sheets) { var sheetNode = sheetNodes[sheetName]; sheetNode.TextNodeStartPosition = destination.Position; foreach (var(textName, text) in sheet) { var textNode = new TextNode { EntryPosition = destination.Position, }; sheetNode.TextNodes.Add(textName, textNode); writer.WriteUInt64(text.Id); writeOffset(0); // Entry name offset (filled in later) writeOffset(0); // Secondary entry offset (filled in later) writeOffset(0); // Text string offset (filled in later) writer.WriteInt64(encoding.GetByteCount(text.Text) / 2); // Length of text string in characters writer.WriteInt64(0); // 8 null bytes } } // Text strings foreach (var(sheetName, sheet) in Sheets) { var sheetNode = sheetNodes[sheetName]; foreach (var(textName, text) in sheet) { var textNode = sheetNode.TextNodes[textName]; textNode.TextPosition = destination.Position; encoding.Write(writer, text.Text); writer.Write('\0'); writer.Align(8); } } // Secondary offsets foreach (var(sheetName, texts) in Sheets) { var sheetNode = sheetNodes[sheetName]; foreach (var textName in texts.Keys) { var textNode = sheetNode.TextNodes[textName]; textNode.SecondaryEntryPosition = destination.Position; writeOffset(0); // Entry name offset (filled in later) writeOffset(0); // Font entry offset (filled in later) writeOffset(0); // Layout entry offset (filled in later) writer.WriteInt64(0); // 8 null bytes } } // Font entries foreach (var(name, font) in Fonts) { var entryPosition = destination.Position; var fontNode = new FontNode { EntryPosition = entryPosition, }; fontNodes.Add(name, fontNode); writeOffset(0); // Entry name offset (filled in later) writeOffset(0); // Typeface name offset (filled in later) writeOffset(entryPosition + 0x78 - 64); // Font size offset (always points to entry + 0x78) if (font.LineSpacing.HasValue) { writeOffset(entryPosition + 0x80 - 64); // Line spacing offset (always points to entry + 0x80) } else { writer.WriteInt64(0); } if (font.Unknown1.HasValue) { writeOffset(entryPosition + 0x88 - 64); // Unknown 1 offset (always points to entry + 0x88) } else { writer.WriteInt64(0); } if (font.Color.HasValue && !font.Unknown1.HasValue) // This is intentional (unknown1 and color point to the same offset) { writeOffset(entryPosition + 0x88 - 64); // Color offset (always points to entry + 0x88) } else { writer.WriteInt64(0); } if (font.Unknown2.HasValue) { writeOffset(entryPosition + 0x90 - 64); // Unknown 2 offset (always points to entry + 0x90) } else { writer.WriteInt64(0); } writer.WriteInt64(0); // Always null if (font.Unknown3.HasValue) { writeOffset(entryPosition + 0xA0 - 64); // Unknown 3 offset (always points to entry + 0xA0) } else { writer.WriteInt64(0); } writer.WriteInt64(0); // Always null writer.WriteInt64(0); // Always null writer.WriteInt64(0); // Always null if (font.Unknown4.HasValue) { writeOffset(entryPosition + 0x98 - 64); // Unknown 4 offset (always points to entry + 0x98) } else { writer.WriteInt64(0); } writer.WriteInt64(0); // Always null writer.WriteInt64(0); // Always null writer.WriteFloat(font.Size); writer.WriteInt32(0); writer.WriteFloat(font.LineSpacing ?? 0); writer.WriteInt32(0); if (font.Unknown1.HasValue) { writer.WriteUInt32(font.Unknown1.Value); } else if (font.Color.HasValue) { writer.WriteUInt32(font.Color.Value); } else { writer.WriteUInt32(0); } writer.WriteInt32(0); writer.WriteUInt32(font.Unknown2 ?? 0); writer.WriteInt32(0); writer.WriteUInt32(font.Unknown4 ?? 0); writer.WriteInt32(0); writer.WriteUInt32(font.Unknown3 ?? 0); writer.WriteInt32(0); } // Layout entries foreach (var(name, layout) in Layouts) { var entryPosition = destination.Position; var layoutNode = new LayoutNode { EntryPosition = entryPosition, }; layoutNodes.Add(name, layoutNode); writeOffset(0); // Entry name offset (filled in later) writer.Write(new byte[24]); // Unknown (just null bytes?) writeOffset(entryPosition + 0x60 - 64); // Text alignment writeOffset(entryPosition + 0x68 - 64); // Vertical alignment writeOffset(entryPosition + 0x70 - 64); // Word wrap writeOffset(entryPosition + 0x78 - 64); // Fit writer.Write(new byte[32]); // Unknown (just null bytes?) writer.WriteInt32((int)layout.TextAlignment); writer.WriteInt32(0); writer.WriteInt32((int)layout.VerticalAlignment); writer.WriteInt32(0); writer.WriteInt32(layout.WordWrap ? 1 : 0); writer.WriteInt32(0); writer.WriteInt32((int)layout.Fit); writer.WriteInt32(0); // May not be needed } // Name entries var nameEntryPosition = destination.Position; foreach (var(sheetName, sheet) in Sheets) { if (!nameOffsets.ContainsKey(sheetName)) { nameOffsets.Add(sheetName, destination.Position); writer.WriteNullTerminatedString(sheetName); } foreach (var textName in sheet.Keys) { if (!nameOffsets.ContainsKey(textName)) { nameOffsets.Add(textName, destination.Position); writer.WriteNullTerminatedString(textName); } } } foreach (var(name, font) in Fonts) { if (!nameOffsets.ContainsKey(name)) { nameOffsets.Add(name, destination.Position); writer.WriteNullTerminatedString(name); } if (!nameOffsets.ContainsKey(font.Typeface)) { nameOffsets.Add(font.Typeface, destination.Position); writer.WriteNullTerminatedString(font.Typeface); } } foreach (var name in Layouts.Keys) { if (!nameOffsets.ContainsKey(name)) { nameOffsets.Add(name, destination.Position); writer.WriteNullTerminatedString(name); } } writer.Align(4); // Write the offset table // This contains a list of all the offsets located within the DATA section // Offsets are stored as relative to the previous offset. var offsetTablePosition = destination.Position; var prevOffset = 64L; foreach (var offset in offsets) { var d = (uint)(offset - prevOffset) >> 2; if (d <= 0x3F) { writer.WriteByte((byte)(0x40 | d)); // Starts with "01" } else if (d <= 0x3FFF) { writer.WriteUInt16(BinaryPrimitives.ReverseEndianness((ushort)((0x80 << 8) | d))); // Starts with "10" } else { writer.WriteUInt32(BinaryPrimitives.ReverseEndianness((uint)((0xC0 << 24) | d))); // Starts with "11" } prevOffset = offset; } writer.Align(4); // Go back and fill in all of the missing offsets destination.Position = 0x8; writer.WriteUInt32((uint)destination.Length); destination.Position = 0x14; writer.WriteUInt32((uint)destination.Length - 16); writer.WriteUInt32((uint)nameEntryPosition - 64); writer.WriteUInt32((uint)(offsetTablePosition - nameEntryPosition)); writer.WriteUInt32((uint)(destination.Length - offsetTablePosition)); foreach (var(sheetName, sheetNode) in sheetNodes) { destination.Position = sheetNode.EntryPosition + 0x8; writer.WriteInt64(sheetNode.TextNodeStartPosition - 64); writer.WriteInt64(nameOffsets[sheetName] - 64); foreach (var(textName, textNode) in sheetNode.TextNodes) { var fontName = Sheets[sheetName][textName].FontName; var layoutName = Sheets[sheetName][textName].LayoutName; destination.Position = textNode.EntryPosition + 0x8; writer.WriteInt64(nameOffsets[textName] - 64); writer.WriteInt64(textNode.SecondaryEntryPosition - 64); writer.WriteInt64(textNode.TextPosition - 64); destination.Position = textNode.SecondaryEntryPosition; writer.WriteInt64(nameOffsets[textName] - 64); writer.WriteInt64(fontName is not null ? fontNodes[fontName].EntryPosition - 64 : 0); writer.WriteInt64(layoutName is not null ? layoutNodes[layoutName].EntryPosition - 64 : 0); } } foreach (var(name, node) in fontNodes) { var typefaceName = Fonts[name].Typeface; destination.Position = node.EntryPosition; writer.WriteInt64(nameOffsets[name] - 64); writer.WriteInt64(nameOffsets[typefaceName] - 64); } foreach (var(name, node) in layoutNodes) { destination.Position = node.EntryPosition; writer.WriteInt64(nameOffsets[name] - 64); } destination.Seek(0, SeekOrigin.End); } }