public virtual void read() { int entryOffset = outerInstance.tell(); type = outerInstance.read8(); id = outerInstance.read8(); outerInstance.skip16(); labelOffset = outerInstance.read32(); eHeadSize = outerInstance.read32(); entrySize = outerInstance.read32(); numSubEntries = outerInstance.read32(); nextEntryOffset = outerInstance.read32(); prevEntryOffset = outerInstance.read32(); parentTblOffset = outerInstance.read32(); outerInstance.skip32(); outerInstance.skip32(); outerInstance.entries[entryOffset] = this; if (parentTblOffset != 0) { parent = outerInstance.entries[entryOffset - parentTblOffset]; } if (labelOffset != RCO_NULL_PTR) { label = outerInstance.readLabel(labelOffset); } //if (log.DebugEnabled) { Console.WriteLine(string.Format("RCO entry at offset 0x{0:X}: {1}", entryOffset, ToString())); } switch (id) { case RCO_TABLE_MAIN: if (type != 1) { Console.WriteLine(string.Format("Unknown RCO entry type 0x{0:X} at offset 0x{1:X}", type, entryOffset)); } break; case RCO_TABLE_VSMX: if (type == 1) { int offsetVSMX = outerInstance.read32(); int lengthVSMX = outerInstance.read32(); outerInstance.skip(offsetVSMX); data = outerInstance.readBytes(lengthVSMX); // 4-bytes alignment outerInstance.skip(Utilities.alignUp(lengthVSMX, 3) - lengthVSMX); } else { Console.WriteLine(string.Format("Unknown RCO entry type 0x{0:X} at offset 0x{1:X}", type, entryOffset)); } break; case RCO_TABLE_IMG: case RCO_TABLE_MODEL: if (type == 1) { int format = outerInstance.read16(); int compression = outerInstance.read16(); int sizePacked = outerInstance.read32(); int offset = outerInstance.read32(); int sizeUnpacked; // this value doesn't exist if entry isn't compressed if (compression != RCO_DATA_COMPRESSION_NONE) { sizeUnpacked = outerInstance.read32(); } else { sizeUnpacked = sizePacked; } if (id == RCO_TABLE_IMG) { System.Drawing.Bitmap image = outerInstance.readImage(offset, sizePacked); if (image != null) { obj = new ImageObject(image); outerInstance.images[entryOffset] = image; } } //if (log.DebugEnabled) { Console.WriteLine(string.Format("RCO entry {0}: format={1:D}, compression={2:D}, sizePacked=0x{3:X}, offset=0x{4:X}, sizeUnpacked=0x{5:X}", id == RCO_TABLE_IMG ? "IMG" : "MODEL", format, compression, sizePacked, offset, sizeUnpacked)); } } else if (type != 0) { Console.WriteLine(string.Format("Unknown RCO entry type 0x{0:X} at offset 0x{1:X}", type, entryOffset)); } break; case RCO_TABLE_SOUND: if (type == 1) { int format = outerInstance.read16(); // 0x01 = VAG int channels = outerInstance.read16(); // 1 or 2 channels int sizeTotal = outerInstance.read32(); int offset = outerInstance.read32(); int[] channelSize = new int[channels]; int[] channelOffset = new int[channels]; // now pairs of size/offset for each channel //if (log.DebugEnabled) { Console.WriteLine(string.Format("RCO entry SOUND: format={0:D}, channels={1:D}, sizeTotal=0x{2:X}, offset=0x{3:X}", format, channels, sizeTotal, offset)); } for (int channel = 0; channel < channels; channel++) { channelSize[channel] = outerInstance.read32(); channelOffset[channel] = outerInstance.read32(); //if (log.DebugEnabled) { Console.WriteLine(string.Format("Channel {0:D}: size=0x{1:X}, offset=0x{2:X}", channel, channelSize[channel], channelOffset[channel])); } } obj = SoundFactory.newSound(format, channels, channelSize, channelOffset); // there _must_ be two channels defined (no clear indication of size otherwise) if (channels < 2) { for (int i = channels; i < 2; i++) { int dummyChannelSize = outerInstance.read32(); int dummyChannelOffset = outerInstance.read32(); if (log.TraceEnabled) { log.trace(string.Format("Dummy channel {0:D}: size=0x{1:X}, offset=0x{2:X}", i, dummyChannelSize, dummyChannelOffset)); } } } } else if (type != 0) { Console.WriteLine(string.Format("Unknown RCO entry type 0x{0:X} at offset 0x{1:X}", type, entryOffset)); } break; case RCO_TABLE_OBJ: if (type > 0) { obj = ObjectFactory.newObject(type); if (obj != null && entrySize == 0) { entrySize = obj.size() + RCO_ENTRY_SIZE; } if (entrySize > RCO_ENTRY_SIZE) { int dataLength = entrySize - RCO_ENTRY_SIZE; data = outerInstance.readBytes(dataLength); if (log.TraceEnabled) { log.trace(string.Format("OBJ data at 0x{0:X}: {1}", entryOffset + RCO_ENTRY_SIZE, Utilities.getMemoryDump(data, 0, dataLength))); } if (obj != null) { RCOContext context = new RCOContext(data, 0, outerInstance.events, outerInstance.images, outerInstance.objects); obj.read(context); if (context.offset != dataLength) { Console.WriteLine(string.Format("Incorrect Length data for ANIM")); } outerInstance.objects[entryOffset] = obj; //if (log.DebugEnabled) { Console.WriteLine(string.Format("OBJ: {0}", obj)); } } } } break; case RCO_TABLE_ANIM: if (type > 0) { obj = AnimFactory.newAnim(type); if (obj != null && entrySize == 0) { entrySize = obj.size() + RCO_ENTRY_SIZE; } if (entrySize > RCO_ENTRY_SIZE) { int dataLength = entrySize - RCO_ENTRY_SIZE; data = outerInstance.readBytes(dataLength); if (log.TraceEnabled) { log.trace(string.Format("ANIM data at 0x{0:X}: {1}", entryOffset + RCO_ENTRY_SIZE, Utilities.getMemoryDump(data, 0, dataLength))); } if (obj != null) { RCOContext context = new RCOContext(data, 0, outerInstance.events, outerInstance.images, outerInstance.objects); obj.read(context); if (context.offset != dataLength) { Console.WriteLine(string.Format("Incorrect Length data for ANIM")); } outerInstance.objects[entryOffset] = obj; //if (log.DebugEnabled) { Console.WriteLine(string.Format("ANIM: {0}", obj)); } } } } break; case RCO_TABLE_FONT: if (type == 1) { int format = outerInstance.read16(); int compression = outerInstance.read16(); int unknown1 = outerInstance.read32(); int unknown2 = outerInstance.read32(); //if (log.DebugEnabled) { Console.WriteLine(string.Format("RCO entry FONT: format={0:D}, compression={1:D}, unknown1=0x{2:X}, unknown2=0x{3:X}", format, compression, unknown1, unknown2)); } } else if (type != 0) { Console.WriteLine(string.Format("Unknown RCO FONT entry type 0x{0:X} at offset 0x{1:X}", type, entryOffset)); } break; case RCO_TABLE_TEXT: if (type == 1) { int lang = outerInstance.read16(); int format = outerInstance.read16(); int numIndexes = outerInstance.read32(); //if (log.DebugEnabled) { Console.WriteLine(string.Format("RCO entry TEXT: lang={0:D}, format={1:D}, numIndexes=0x{2:X}", lang, format, numIndexes)); } texts = new string[numIndexes]; for (int i = 0; i < numIndexes; i++) { int labelOffset = outerInstance.read32(); int Length = outerInstance.read32(); int offset = outerInstance.read32(); texts[i] = outerInstance.readText(lang, offset, Length); //if (log.DebugEnabled) { Console.WriteLine(string.Format("RCO entry TEXT Index#{0:D}: labelOffset={1:D}, Length={2:D}, offset=0x{3:X}; '{4}'", i, labelOffset, Length, offset, texts[i])); } } } else if (type != 0) { Console.WriteLine(string.Format("Unknown RCO TEXT entry type 0x{0:X} at offset 0x{1:X}", type, entryOffset)); } break; default: Console.WriteLine(string.Format("Unknown RCO entry id 0x{0:X} at offset 0x{1:X}", id, entryOffset)); break; } if (numSubEntries > 0) { subEntries = new RCOEntry[numSubEntries]; for (int i = 0; i < numSubEntries; i++) { subEntries[i] = new RCOEntry(outerInstance); subEntries[i].read(); } } }