Пример #1
0
 public virtual void Write(ResStringPool_header data)
 {
     Write(data.Header);
     _writer.Write(data.StringCount);
     _writer.Write(data.StyleCount);
     _writer.Write((uint)data.Flags);
     _writer.Write(data.StringStart);
     _writer.Write(data.StylesStart);
 }
Пример #2
0
        public virtual ResStringPool ReadResStringPool(ResStringPool_header header)
        {
            var pool = new ResStringPool
            {
                Header     = header,
                StringData = new List <string>(),
                StyleData  = new List <List <ResStringPool_span> >()
            };

            // Offsets of the string data, relative to header.StringStart
            var stringIndices = new List <uint>();

            for (var i = 0; i < header.StringCount; i++)
            {
                stringIndices.Add(ReadUInt32());
            }

            // Offset of the style data, relative to header.StylesStart
            var styleIndices = new List <uint>();

            for (var i = 0; i < header.StyleCount; i++)
            {
                styleIndices.Add(ReadUInt32());
            }

            // Keep track of how many bytes are left, to prevent us
            // from reading invalid data.
            long bytesLeft = header.Header.Size;

            bytesLeft -= header.Header.HeaderSize;
            bytesLeft -= 4 * header.StringCount;
            bytesLeft -= 4 * header.StyleCount;

            // Fetch the block which contains the string. If a styles section is
            // present, the strings block ends there; otherwise, it runs to the end
            // of this entry.
            var stringsEnd    = header.StyleCount > 0 ? header.StylesStart : header.Header.Size;
            var rawStringData = ReadBytes((int)stringsEnd - (int)header.StringStart);

            bytesLeft -= rawStringData.Length;

            var isUtf8 = (header.Flags & StringPoolFlags.UTF8_FLAG) == StringPoolFlags.UTF8_FLAG;

            foreach (var startingIndex in stringIndices)
            {
                // The starting index specifies where the string starts.
                // We can now read the string in either UTF8 or UTF16 format.
                var pos = startingIndex;
                if (isUtf8)
                {
                    var charLen = Helper.DecodeLengthUtf8(rawStringData, ref pos);
                    var byteLen = Helper.DecodeLengthUtf8(rawStringData, ref pos);
                    var item    = Encoding.UTF8.GetString(rawStringData, (int)pos, (int)byteLen);
                    if (item.Length != charLen)
                    {
#if !CORECLR
                        Debug.WriteLine(
                            $"Warning: UTF-8 string length ({item.Length}) not matching specified length ({charLen}).");
#endif
                    }
                    pool.StringData.Add(item);
                }
                else
                {
                    var charLen = Helper.DecodeLengthUtf16(rawStringData, ref pos);
                    var byteLen = charLen * 2;
                    var item    = Encoding.Unicode.GetString(rawStringData, (int)pos, (int)byteLen);
                    pool.StringData.Add(item);
                }
            }

            // If styles are present, we should read them, too.
            if (header.StyleCount > 0)
            {
                var rawStyleData = ReadBytes((int)header.Header.Size - (int)header.StylesStart);

                foreach (var startingIndex in styleIndices)
                {
                    // At startingIndex, there are N entries defining the individual tags (b, i,...)
                    // that style the string at index i
                    // They are terminated by a value with value END (0xFFFFFFFF)
                    var styleData = new List <ResStringPool_span>();

                    var pos = (int)startingIndex;

                    while (true)
                    {
                        var index     = BitConverter.ToUInt32(rawStyleData, pos);
                        var firstChar = BitConverter.ToUInt32(rawStyleData, pos + 4);
                        var lastChar  = BitConverter.ToUInt32(rawStringData, pos + 8);

                        var span = new ResStringPool_span
                        {
                            Name = new ResStringPool_ref
                            {
                                Index = index == 0xFFFFFFFFu ? (uint?)null : index
                            },
                            FirstChar = firstChar,
                            LastChar  = lastChar
                        };

                        styleData.Add(span);
                        if (span.IsEnd)
                        {
                            break;
                        }

                        pos += 12;
                    }

                    pool.StyleData.Add(styleData);
                }

                bytesLeft -= rawStyleData.Length;
            }

            // Make sure we didn't go out of bounds.
            if (bytesLeft < 0)
            {
                throw new InvalidDataException("The length of the content exceeds the ResStringPool block boundary.");
            }
            if (bytesLeft > 0)
            {
                // Padding: data is always aligned to 4 bytes.
#if !CORECLR
                Debug.WriteLine("Warning: Garbage at the end of the StringPool block. Padding?");
#endif
                ReadBytes((int)bytesLeft);
            }

            return(pool);
        }
Пример #3
0
        public virtual ResStringPool ReadResStringPool(ResStringPool_header header)
        {
            var pool = new ResStringPool
            {
                Header = header,
                //StringIndices = new List<uint>(),
                //StyleIndices = new List<uint>(),
                StringData = new List <string>(),
                StyleData  = new List <ResStringPool_span>()
            };
            var stringIndices = new List <uint>();

            for (int i = 0; i < header.StringCount; i++)
            {
                stringIndices.Add(ReadUInt32());
            }
            for (int i = 0; i < header.StyleCount; i++)
            {
                ReadUInt32(); // Skip
            }

            long bytesLeft = header.Header.Size;

            bytesLeft -= header.Header.HeaderSize;
            bytesLeft -= 4 * header.StringCount;
            bytesLeft -= 4 * header.StyleCount;

            uint stringsEnd = header.StyleCount > 0 ? header.StylesStart : header.Header.Size;

            byte[] rawStringData = ReadBytes((int)stringsEnd - (int)header.StringStart);

            bytesLeft -= rawStringData.Length;

            bool isUtf8 = (header.Flags & StringPoolFlags.UTF8_FLAG) == StringPoolFlags.UTF8_FLAG;

            foreach (uint startingIndex in stringIndices)
            {
                uint pos = startingIndex;
                if (isUtf8)
                {
                    uint   charLen = Helper.DecodeLengthUtf8(rawStringData, ref pos);
                    uint   byteLen = Helper.DecodeLengthUtf8(rawStringData, ref pos);
                    string item    = Encoding.UTF8.GetString(rawStringData, (int)pos, (int)byteLen);
                    if (item.Length != charLen)
                    {
                        Debug.WriteLine("Warning: UTF-8 string length ({0}) not matching specified length ({1}).",
                                        item.Length, charLen);
                    }
                    pool.StringData.Add(item);
                }
                else
                {
                    uint   charLen = Helper.DecodeLengthUtf16(rawStringData, ref pos);
                    uint   byteLen = charLen * 2;
                    string item    = Encoding.Unicode.GetString(rawStringData, (int)pos, (int)byteLen);
                    pool.StringData.Add(item);
                }
            }

            for (int i = 0; i < header.StyleCount; i++)
            {
                pool.StyleData.Add(ReadResStringPool_span());
            }

            bytesLeft -= header.StyleCount * 12; // sizeof(ResStringPool_span) in C++

            if (bytesLeft < 0)
            {
                throw new InvalidDataException("The length of the content exceeds the ResStringPool block boundary.");
            }
            if (bytesLeft > 0)
            {
                // Padding?
                Debug.WriteLine("Warning: Garbage at the end of the StringPool block. Padding?");
                ReadBytes((int)bytesLeft);
            }

            return(pool);
        }