コード例 #1
0
 void IAstVisitor <ResolveContext> .Visit(FontNode node, ResolveContext context)
 {
     context.Parent = node;
     foreach (var item in node.Children)
     {
         item.Accept(this, context);
     }
 }
コード例 #2
0
        void IAstVisitor <ParsingContext> .Visit(FontNode node, ParsingContext context)
        {
            bool flag = false;

            if (node.HexColor.Length > 0)
            {
                flag = true;
                var c     = (System.Drawing.Color)colorConverter.ConvertFromString(node.HexColor);
                var color = Color.FromArgb(c.A, c.R, c.G, c.B);
                context.Colors.Push(new SolidColorBrush(color));
            }
            foreach (var item in node.Children)
            {
                item.Accept(this, context);
            }
            if (flag)
            {
                context.Colors.Pop();
            }
        }
コード例 #3
0
        /// <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);
                }
        }