示例#1
0
        private IEnumerable <XmlParserEventCode> ParserIterator()
        {
            while (true)
            {
                ClearState();

                if (_reader.BaseStream.Position >= _reader.BaseStream.Length)
                {
                    // If we're at the end of the file, stop reading chunks.
                    // Don't try to catch an EndOfStreamException - this way,
                    // we avoid an exception being created.
                    break;
                }

                ResChunk_header header;
                try
                {
                    header = _reader.ReadResChunk_header();
                }
                catch (EndOfStreamException)
                {
                    // Keep this just in case.
                    break;
                }

                var subStream = new BoundedStream(_reader.BaseStream, header.Size - 8);
                var subReader = new ResReader(subStream);
                switch (header.Type)
                {
                case ResourceType.RES_XML_TYPE:
                    yield return(XmlParserEventCode.StartDocument);

                    _reader = subReader; // Bound whole file
                    continue;            // Don't skip content

                case ResourceType.RES_STRING_POOL_TYPE:
                    var stringPoolHeader = subReader.ReadResStringPool_header(header);
                    Strings = subReader.ReadResStringPool(stringPoolHeader);
                    break;

                case ResourceType.RES_XML_RESOURCE_MAP_TYPE:
                    var resourceMap = subReader.ReadResResourceMap(header);
                    ResourceMap = resourceMap;
                    break;

                case ResourceType.RES_XML_START_NAMESPACE_TYPE:
                    _currentNode      = subReader.ReadResXMLTree_node(header);
                    _currentExtension = subReader.ReadResXMLTree_namespaceExt();
                    yield return(XmlParserEventCode.StartNamespace);

                    break;

                case ResourceType.RES_XML_END_NAMESPACE_TYPE:
                    _currentNode      = subReader.ReadResXMLTree_node(header);
                    _currentExtension = subReader.ReadResXMLTree_namespaceExt();
                    yield return(XmlParserEventCode.EndNamespace);

                    break;

                case ResourceType.RES_XML_START_ELEMENT_TYPE:
                    _currentNode = subReader.ReadResXMLTree_node(header);
                    var attrExt = subReader.ReadResXMLTree_attrExt();
                    _currentExtension = attrExt;

                    _attributes = new List <ResXMLTree_attribute>();
                    for (var i = 0; i < attrExt.AttributeCount; i++)
                    {
                        _attributes.Add(subReader.ReadResXMLTree_attribute());
                    }
                    yield return(XmlParserEventCode.StartTag);

                    break;

                case ResourceType.RES_XML_END_ELEMENT_TYPE:
                    _currentNode      = subReader.ReadResXMLTree_node(header);
                    _currentExtension = subReader.ReadResXMLTree_endElementExt();
                    yield return(XmlParserEventCode.EndTag);

                    break;

                case ResourceType.RES_XML_CDATA_TYPE:
                    _currentNode      = subReader.ReadResXMLTree_node(header);
                    _currentExtension = subReader.ReadResXMLTree_cdataExt();
                    yield return(XmlParserEventCode.Text);

                    break;

                default:
                    Debug.WriteLine(String.Format("Warning: Skipping chunk of type {0} (0x{1:x4})",
                                                  header.Type, (int)header.Type));
                    break;
                }
                var junk = subStream.ReadFully();
                if (junk.Length > 0)
                {
                    Debug.WriteLine(String.Format("Warning: Skipping {0} bytes at the end of a {1} (0x{2:x4}) chunk.",
                                                  junk.Length, header.Type, (int)header.Type));
                }
            }
        }
示例#2
0
        public static ArscFile Read(Stream stream)
        {
            var file = new ArscFile();

            using (var reader = new ResReader(stream))
            {
                var chunkHeader = reader.ReadResChunk_header();
                if (chunkHeader.Type != ResourceType.RES_TABLE_TYPE)
                {
                    throw new ApkReaderException("No RES_TABLE_TYPE found!");
                }
                if (chunkHeader.Size != stream.Length)
                {
                    throw new ApkReaderException("The buffer size not matches to the resource table size.");
                }
                file.Length = chunkHeader.Size;
                var resTable = reader.ReadResTable_header(chunkHeader);
                var globalStringPoolHeader = reader.ReadResStringPool_header(reader.ReadResChunk_header());
                var globalStringPool       = reader.ReadResStringPool(globalStringPoolHeader);
                file.GlobalStringPool = globalStringPool;
                for (var packageIndex = 0; packageIndex < resTable.PackageCount; packageIndex++)
                {
                    var package = new ArscPackage();
                    file.Packages.Add(package);
                    chunkHeader = reader.ReadResChunk_header();
                    var endPosition = stream.Position - 8 + chunkHeader.Size;
                    if (chunkHeader.Type != ResourceType.RES_TABLE_PACKAGE_TYPE)
                    {
                        throw new ApkReaderException();
                    }
                    var packageHeader = reader.ReadResTable_package(chunkHeader);
                    package.Id   = packageHeader.Id;
                    package.Name = packageHeader.Name.TrimEnd('\0');
                    chunkHeader  = reader.ReadResChunk_header();
                    if (chunkHeader.Type != ResourceType.RES_STRING_POOL_TYPE)
                    {
                        throw new ApkReaderException();
                    }
                    package.TypeStringPool = reader.ReadResStringPool(reader.ReadResStringPool_header(chunkHeader));
                    chunkHeader            = reader.ReadResChunk_header();
                    if (chunkHeader.Type != ResourceType.RES_STRING_POOL_TYPE)
                    {
                        throw new ApkReaderException();
                    }
                    package.KeyStringPool = reader.ReadResStringPool(reader.ReadResStringPool_header(chunkHeader));
                    do
                    {
                        chunkHeader = reader.ReadResChunk_header();
                        switch (chunkHeader.Type)
                        {
                        case ResourceType.RES_TABLE_TYPE_SPEC_TYPE:
                            var th = reader.ReadResTable_typeSpec(chunkHeader);
                            package.TypeSpecsData = new uint[th.EntryCount];
                            for (var i = 0; i < th.EntryCount; i++)
                            {
                                package.TypeSpecsData[i] = reader.ReadUInt32();
                            }
                            break;

                        case ResourceType.RES_TABLE_TYPE_TYPE:
                            var table     = reader.ReadResTable_type(chunkHeader);
                            var arscTable = new ArscTable
                            {
                                Config = table.Config
                            };
                            package.Tables.Add(arscTable);
                            var entryIndices = new int[table.EntryCount];
                            for (var i = 0; i < table.EntryCount; i++)
                            {
                                entryIndices[i] = reader.ReadInt32();
                            }
                            var entries = new ResTable_entry[table.EntryCount];
                            for (var i = 0; i < table.EntryCount; i++)
                            {
                                if (entryIndices[i] == -1)
                                {
                                    continue;
                                }
                                var resourceId = (packageHeader.Id << 24) | (table.RawID << 16) | i;
                                var entry      = reader.ReadResTable_entry();
                                entries[i] = entry;
                                if ((entry.Flags & EntryFlags.FLAG_COMPLEX) == 0)
                                {
                                    var value = reader.ReadRes_value();
                                    arscTable.Values[Convert.ToUInt32(resourceId)] = value;
                                }
                                else
                                {
                                    var parent = reader.ReadInt32();
                                    var count  = reader.ReadInt32();
                                    for (var x = 0; x < count; x++)
                                    {
                                        var refName = reader.ReadUInt32();
                                        var value   = reader.ReadRes_value();
                                    }
                                }
                            }
                            break;

                        default:
                            throw new ApkReaderException($"Unknow Data Type : {chunkHeader.Type}");
                        }
                    } while (stream.Position < endPosition);
                }
            }
            return(file);
        }