/// <summary> /// Reading ctor /// </summary> internal Value(ResReader reader) { var size = reader.ReadUInt16(); reader.Skip(1); // res0 type = (Types)reader.ReadByte(); data = reader.ReadInt32(); }
/// <summary> /// Reading ctor /// </summary> protected Node(ResReader reader, XmlTree tree, ChunkTypes expectedType) : base(reader, expectedType) { this.tree = tree; LineNumber = reader.ReadInt32(); Comment = StringPoolRef.Read(reader, tree.StringPool); }
/// <summary> /// Read ctor /// </summary> internal Type(TypeSpec parent, ResReader reader) : base(reader, ChunkTypes.RES_TABLE_TYPE_TYPE) { this.parent = parent; var id = reader.ReadByte(); reader.Skip(3); // reserved if (id != parent.Id) { throw new IOException("Type id (" + id + ") " + "doesn't match parent id (" + parent.Id + ")."); } var entryCount = reader.ReadInt32(); if (entryCount != parent.EntryCount) { throw new IOException(string.Format("Type entry count ({0}) doesn't match parent entry count ({1})", entryCount, parent.EntryCount)); } var entriesStart = reader.ReadInt32(); configuration = new Configuration(reader); // Data var offsets = reader.ReadIntArray(entryCount); var dataSize = (Size - entriesStart); if ((dataSize % 4) != 0) { throw new IOException("Type data size (" + dataSize + ") is not multiple of 4."); } for (var i = 0; i < entryCount; i++ ) { if (offsets[i] != NO_ENTRY) { var actualOffset = reader.Position; var instance = EntryInstance.Read(this, reader); parent.GetEntry(i).Add(instance); } } }
/// <summary> /// Reader ctor /// </summary> protected Chunk(ResReader reader, ChunkTypes expectedType) : this(reader) { if (type != expectedType) { throw new IOException(string.Format("Expected chunk of type 0x{0:X}, read 0x{1:X}.", (int)expectedType, (int)type)); } }
/// <summary> /// Read ctor /// </summary> internal Attribute(ResReader reader, XmlTree tree) { this.tree = tree; Namespace = StringPoolRef.Read(reader, tree.StringPool); Name = StringPoolRef.Read(reader, tree.StringPool); RawValue = StringPoolRef.Read(reader, tree.StringPool); TypedValue = new Value(reader); }
/// <summary> /// Read ctor /// </summary> protected EntryInstance(Type parent, ResReader reader) { this.parent = parent; // header var size = reader.ReadUInt16(); flags = (EntryFlags) reader.ReadUInt16(); key = StringPoolRef.Read(reader, parent.TypeSpec.Package.KeyStrings); }
/// <summary> /// Reading ctor /// </summary> internal ResourceMap(ResReader reader) : base(reader, ChunkTypes.RES_XML_RESOURCE_MAP_TYPE) { if (Size < 8 || (Size % 4) != 0) { throw new IOException("Invalid resource ids size (" + Size + ")."); } resourceIds.AddRange(reader.ReadIntArray(Size / 4 - 2)); }
/// <summary> /// Read ctor /// </summary> protected EntryInstance(Type parent, ResReader reader) { this.parent = parent; // header var size = reader.ReadUInt16(); flags = (EntryFlags)reader.ReadUInt16(); key = StringPoolRef.Read(reader, parent.TypeSpec.Package.KeyStrings); }
/// <summary> /// Default ctor /// </summary> internal Table(ResReader reader) : base(reader, ChunkTypes.RES_TABLE_TYPE) { var packageCount = reader.ReadInt32(); strings = new StringPool(reader); for (var i = 0; i < packageCount; i++) { packages.Add(new Package(this, reader)); } }
/// <summary> /// Reader ctor /// </summary> internal TypeSpec(Package parent, ResReader reader) : base(reader, ChunkTypes.RES_TABLE_TYPE_SPEC_TYPE) { this.parent = parent; id = reader.ReadByte(); reader.Skip(3); // reserved var entryCount = reader.ReadInt32(); var flags = reader.ReadIntArray(entryCount).ToList(); entries.AddRange(flags.Select(x => new Entry(this, x))); }
/// <summary> /// Read an entry and return it. /// </summary> internal static EntryInstance Read(Type parent, ResReader reader) { var position = reader.Position; var size = reader.ReadUInt16(); var flags = (EntryFlags) reader.ReadUInt16(); reader.Position = position; if ((flags & EntryFlags.Complex) != 0) return new ComplexEntryInstance(parent, reader); return new SimpleEntryInstance(parent, reader); }
/// <summary> /// Read ctor /// </summary> internal ComplexEntryInstance(Type parent, ResReader reader) : base(parent, reader) { var parentResId = TableRef.Read(reader); var count = reader.ReadInt32(); //reader.Skip(count*12); for (var i = 0; i < count; i++) { maps.Add(new Map(this, reader)); } }
/// <summary> /// Default a length for charsize=2 /// </summary> private static int DecodeLength16(ResReader reader, byte[] strings, ref int offset) { var length = reader.ReadUInt16(strings, offset); offset += 2; if ((length & 0x8000) != 0) { length = ((length & 0x7FFF) << 16) | reader.ReadUInt16(strings, offset); offset += 2; } return(length); }
/// <summary> /// Read an entry and return it. /// </summary> internal static EntryInstance Read(Type parent, ResReader reader) { var position = reader.Position; var size = reader.ReadUInt16(); var flags = (EntryFlags)reader.ReadUInt16(); reader.Position = position; if ((flags & EntryFlags.Complex) != 0) { return(new ComplexEntryInstance(parent, reader)); } return(new SimpleEntryInstance(parent, reader)); }
/// <summary> /// Reading ctor /// </summary> internal StartElement(ResReader reader, XmlTree tree) : base(reader, tree, ChunkTypes.RES_XML_START_ELEMENT_TYPE) { var attributeStart = reader.ReadUInt16(); var attributeSize = reader.ReadUInt16(); var attributeCount = reader.ReadUInt16(); var id = reader.ReadUInt16(); var classIndex = reader.ReadUInt16(); var styleIndex = reader.ReadUInt16(); for (var i = 0; i < attributeCount; i++) { attributes.Add(new Attribute(reader, tree)); } }
/// <summary> /// Helper used to read chunks and check the actual size read. /// </summary> internal static T Read <T>(ResReader reader, Func <T> readAction) where T : Chunk { var startPosition = reader.Position; var result = readAction(); var endPosition = reader.Position; var size = endPosition - startPosition; if (size != result.Size) { #if DEBUG Debugger.Launch(); #endif throw new ArgumentException("Size mismatch"); } return(result); }
/// <summary> /// Default ctor /// </summary> internal Package(Table table, ResReader reader) : base(reader, ChunkTypes.RES_TABLE_PACKAGE_TYPE) { this.table = table; id = reader.ReadInt32(); name = reader.ReadFixedLenghtUnicodeString(128); var typeStringsOffset = reader.ReadInt32(); var lastPublicType = reader.ReadInt32(); var keyStringsOffset = reader.ReadInt32(); var lastPublicKey = reader.ReadInt32(); // Record offset var dataOffset = reader.Position; // Data typeStrings = new StringPool(reader); keyStrings = new StringPool(reader); TypeSpec currentTypeSpec = null; while (reader.Position - dataOffset < DataSize) { var chunkType = reader.PeekChunkType(); if (chunkType == ChunkTypes.RES_TABLE_TYPE_SPEC_TYPE) { currentTypeSpec = Read(reader, () => new TypeSpec(this, reader)); typeSpecs.Add(currentTypeSpec); } else if (chunkType == ChunkTypes.RES_TABLE_TYPE_TYPE) { if (currentTypeSpec == null) { throw new IOException("Invalid chunk sequence: content read before typeSpec."); } var parent = currentTypeSpec; var type = Read(reader, () => new Type(parent, reader)); currentTypeSpec.Add(type); } else { throw new IOException("Unexpected chunk type (" + chunkType + ")."); } } }
/// <summary> /// Reading ctor /// </summary> public XmlTree(ResReader reader) : base(reader, ChunkTypes.RES_XML_TYPE) { strings = new StringPool(reader); resourceMap = new ResourceMap(reader); while (true) { var tag = reader.PeekChunkType(); Node node; switch (tag) { case ChunkTypes.RES_XML_START_NAMESPACE_TYPE: node = new StartNamespace(reader, this); break; case ChunkTypes.RES_XML_START_ELEMENT_TYPE: node = new StartElement(reader, this); break; case ChunkTypes.RES_XML_CDATA_TYPE: node = new CData(reader, this); break; case ChunkTypes.RES_XML_END_ELEMENT_TYPE: node = new EndElement(reader, this); break; case ChunkTypes.RES_XML_END_NAMESPACE_TYPE: node = new EndNamespace(reader, this); break; default: throw new IOException(string.Format("Unexpected tag: 0x{0:X}", (int)tag)); } nodes.Add(node); if (tag == ChunkTypes.RES_XML_END_NAMESPACE_TYPE) { break; } } }
/// <summary> /// Default ctor /// </summary> internal StringPool(ResReader reader) : base(reader, ChunkTypes.RES_STRING_POOL_TYPE) { var stringCount = reader.ReadInt32(); var styleOffsetCount = reader.ReadInt32(); var flags = (StringPoolFlags)reader.ReadInt32(); IsUtf8 = ((flags & StringPoolFlags.UTF8_FLAG) != 0); var stringsStart = reader.ReadInt32(); var stylesStart = reader.ReadInt32(); var stringOffsets = reader.ReadIntArray(stringCount); if (styleOffsetCount != 0) { styleOffsets = reader.ReadIntArray(styleOffsetCount); } byte[] stringData; { var size = ((stylesStart == 0) ? Size : stylesStart) - stringsStart; if ((size % 4) != 0) { throw new IOException(string.Format("String data size is not multiple of 4 ({0}).", size)); } stringData = reader.ReadByteArray(size); } if (stylesStart != 0) { var size = (Size - stylesStart); if ((size % 4) != 0) { throw new IOException(string.Format("Style data size is not multiple of 4 ({0}).", size)); } styles = reader.ReadIntArray(size / 4); } var count = (stringOffsets != null) ? stringOffsets.Length : 0; for (var i = 0; i != count; ++i) { list.Add(new Entry(GetRaw(i, stringOffsets, stringData, IsUtf8, reader), -1)); } }
/// <summary> /// Read ctor /// </summary> internal Type(TypeSpec parent, ResReader reader) : base(reader, ChunkTypes.RES_TABLE_TYPE_TYPE) { this.parent = parent; var id = reader.ReadByte(); reader.Skip(3); // reserved if (id != parent.Id) { throw new IOException("Type id (" + id + ") " + "doesn't match parent id (" + parent.Id + ")."); } var entryCount = reader.ReadInt32(); if (entryCount != parent.EntryCount) { throw new IOException(string.Format("Type entry count ({0}) doesn't match parent entry count ({1})", entryCount, parent.EntryCount)); } var entriesStart = reader.ReadInt32(); configuration = new Configuration(reader); // Data var offsets = reader.ReadIntArray(entryCount); var dataSize = (Size - entriesStart); if ((dataSize % 4) != 0) { throw new IOException("Type data size (" + dataSize + ") is not multiple of 4."); } for (var i = 0; i < entryCount; i++) { if (offsets[i] != NO_ENTRY) { var actualOffset = reader.Position; var instance = EntryInstance.Read(this, reader); parent.GetEntry(i).Add(instance); } } }
/// <summary> /// Reading ctor /// </summary> public XmlTree(ResReader reader) : base(reader, ChunkTypes.RES_XML_TYPE) { strings = new StringPool(reader); resourceMap = new ResourceMap(reader); while (true) { var tag = reader.PeekChunkType(); Node node; switch (tag) { case ChunkTypes.RES_XML_START_NAMESPACE_TYPE: node = new StartNamespace(reader, this); break; case ChunkTypes.RES_XML_START_ELEMENT_TYPE: node = new StartElement(reader, this); break; case ChunkTypes.RES_XML_CDATA_TYPE: node = new CData(reader, this); break; case ChunkTypes.RES_XML_END_ELEMENT_TYPE: node = new EndElement(reader, this); break; case ChunkTypes.RES_XML_END_NAMESPACE_TYPE: node = new EndNamespace(reader, this); break; default: throw new IOException(string.Format("Unexpected tag: 0x{0:X}", (int)tag)); } nodes.Add(node); if (tag == ChunkTypes.RES_XML_END_NAMESPACE_TYPE) break; } }
/// <summary> /// Reading ctor /// </summary> internal EndNamespace(ResReader reader, XmlTree tree) : base(reader, tree, ChunkTypes.RES_XML_END_NAMESPACE_TYPE) { }
/// <summary> /// Reading ctor /// </summary> internal StartNamespace(ResReader reader, XmlTree tree) : base(reader, tree, ChunkTypes.RES_XML_START_NAMESPACE_TYPE) { }
/// <summary> /// Reading ctor /// </summary> internal EndElement(ResReader reader, XmlTree tree) : base(reader, tree, ChunkTypes.RES_XML_END_ELEMENT_TYPE) { }
/// <summary> /// Reading ctor /// </summary> internal CData(ResReader reader, XmlTree tree) : base(reader, tree, ChunkTypes.RES_XML_CDATA_TYPE) { Data = StringPoolRef.Read(reader, tree.StringPool); TypedData = new Value(reader); }
/// <summary> /// Reader ctor /// </summary> protected Chunk(ResReader reader) { type = (ChunkTypes)reader.ReadUInt16(); headerSize = reader.ReadUInt16(); size = reader.ReadInt32(); }
/// <summary> /// Read ctor /// </summary> internal SimpleEntryInstance(Type parent, ResReader reader) : base(parent, reader) { // Read value value = new Value(reader); }
/// <summary> /// Read ctor /// </summary> internal Configuration(ResReader reader) { var size = reader.ReadInt32(); data = reader.ReadByteArray(size - 4); }
/// <summary> /// Read a 32-bit unsigned int from the given offset. /// </summary> private int GetInt32(int offset) { return(ResReader.DecodeInt32(data, offset, UseBigEndian)); }
/// <summary> /// Returns raw string (without any styling information) at specified index. /// Returns null if index is invalid or object was not initialized. /// </summary> private static string GetRaw(int index, int[] stringOffsets, byte[] strings, bool isUtf8, ResReader reader) { if (index < 0 || (stringOffsets == null) || (index >= stringOffsets.Length)) { return(null); } var offset = stringOffsets[index]; int length; if (isUtf8) { // charsize = 1 // Decode length var u16Length = DecodeLength8(strings, ref offset); length = DecodeLength8(strings, ref offset); return(AndroidEncodings.UTF8.GetString(strings, offset, length)); } // charsize = 2 length = DecodeLength16(reader, strings, ref offset); var data = new char[length]; for (var i = 0; i < length; i++) { data[i] = (char)reader.ReadUInt16(strings, offset); offset += 2; } return(new string(data)); }