public static TCBlock ReadBlock(MemoryStream byteCheckerFile) { TCBlock block = new TCBlock(byteCheckerFile); block.blockTime = block.ReadBlockTime(byteCheckerFile); block.blockSize = block.ReadBlockSize(byteCheckerFile); block.blockType = block.ReadBlockType(byteCheckerFile); return(block); }
static void DecompressRecordings(string source, string destination) { string[] recordings = Directory.GetFiles(source); int len = recordings.Length; string versionDirectory = ""; Dictionary <int, string> PacketNames = new Dictionary <int, string>(); Dictionary <int, Dictionary <string, int> > PacketCounts = new Dictionary <int, Dictionary <string, int> >(); Dictionary <int, Dictionary <string, List <int> > > PacketSizes = new Dictionary <int, Dictionary <string, List <int> > >(); PacketNames[PACKET_ID_MAPINFO] = "MapInfoInit"; PacketNames[PACKET_ID_MAPINFO_CONTINUED] = "MapInfoCont"; PacketNames[0x0A] = "UK1"; PacketNames[0x0F] = "UK2"; PacketNames[0x17] = "UK3"; PacketNames[0x1D] = "UK4"; PacketNames[0x65] = "UK5"; PacketNames[0x66] = "UK6"; PacketNames[0x67] = "UK7"; PacketNames[0x68] = "UK8"; PacketNames[0x69] = "UK9"; PacketNames[0x6A] = "UK10"; PacketNames[0x6B] = "UK11"; PacketNames[0x6C] = "UK12"; PacketNames[0x6E] = "UK13"; PacketNames[0x6F] = "UK14"; PacketNames[0x78] = "UK15"; PacketNames[0x79] = "UK16"; PacketNames[0x82] = "UK17"; PacketNames[0x83] = "UK18"; PacketNames[0x85] = "UK19"; PacketNames[0x8C] = "UK20"; PacketNames[0x8D] = "UK21"; PacketNames[0x8E] = "UK22"; PacketNames[0x8F] = "UK23"; PacketNames[0x90] = "UK24"; PacketNames[0x92] = "UK25"; PacketNames[0x93] = "UK26"; PacketNames[0x94] = "UK27"; PacketNames[0x9F] = "UK28"; PacketNames[0xA0] = "UK29"; PacketNames[0xA1] = "UK30"; PacketNames[0xA2] = "UK31"; PacketNames[0xA4] = "UK32"; PacketNames[0xA5] = "UK33"; PacketNames[0xA6] = "UK34"; PacketNames[0xA7] = "UK35"; PacketNames[0xAA] = "UK36"; PacketNames[0xB3] = "UK37"; PacketNames[0xB4] = "UK38"; PacketNames[0xB7] = "UK39"; PacketNames[0xB8] = "UK40"; PacketNames[0xBE] = "UK41"; PacketNames[0xBF] = "UK42"; PacketNames[0xF3] = "UK43"; PacketNames[0xF5] = "UK44"; // New PacketNames[0x70] = "UK45"; PacketNames[0x71] = "UK46"; PacketNames[0x91] = "UK47"; PacketNames[0x72] = "UK48"; // Newer PacketNames[0x7D] = "UK49"; PacketNames[0x7E] = "UK50"; PacketNames[0x7F] = "UK51"; // Even newer PacketNames[0x7B] = "UK52"; PacketNames[0x7C] = "UK53"; //List<int> RecordingPackets = new List<int> { 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6E, 0xAA, 0xB4, 0xBE, 0xBF, 0xF3, 0xF5 }; List <int> RecordingPackets = new List <int> { 0x64, 0x65, 0x66, 0x67, 0x68, 0xBE, 0xBF }; Position pos = new Position(0, 0, 0); Dictionary <string, Dictionary <int, int> > UnexpectedBlockTypeCount = new Dictionary <string, Dictionary <int, int> >(); TCRecording recording = new TCRecording(-1); for (int i = 0; i < len; i++) { try { string filename = Path.GetFileNameWithoutExtension(recordings[i]); string recordingID = filename.Split('.')[0]; recording = new TCRecording(Convert.ToInt32(recordingID)); using (MemoryStream ms = recording.Decompress(recordings[i])) { versionDirectory = destination + "\\" + recording.Version; if (!Directory.Exists(versionDirectory)) { Directory.CreateDirectory(versionDirectory); } // TEMPORARY TO TEST FILE HEADERS. if (StructureFileExists(versionDirectory, filename)) { // TODO refactor. Do not like this. Console.WriteLine("Skipped because already done: " + filename); continue; } ms.Position = 0; using (FileStream debugOutFs = new FileStream(versionDirectory + "\\" + "debug-" + filename + ".recording", FileMode.Create, FileAccess.Write)) { ms.CopyTo(debugOutFs); } ms.Position = 0; Console.WriteLine("Reading Recording #" + filename); string txtOutput = ""; while (ms.Position < ms.Length) { TCBlock block = TCBlock.ReadBlock(ms); MemoryStream ms_block = block.Stream; if (block.blockSize > 0) { List <TCCreature> creatures; if (block.blockType == TCBlock.BLOCK_TYPE_INIT) { // The initial block has an array of creatures before the // array of packets. Parse the creatures and handle the // packets as we do for the packet block. creatures = Packet.ParseCreatureList(ms_block, recording.Version); // For analysis, output the creatures to a text file. // Ensure the directory exists. string creaturesDirectory = ConstructFilePath(versionDirectory, "Extra"); // Output to file. OutputCreaturesToFile(creaturesDirectory, creatures); } if (block.blockType == TCBlock.BLOCK_TYPE_TIBIACASTMESSAGE) { ms_block.Position += block.blockSize - 1; } if (block.blockType == TCBlock.BLOCK_TYPE_UNKNOWN) { ms_block.Position += block.blockSize - 1; } if (!TCBlock.ExpectedBlockTypes.Contains(block.blockType)) { // Either we encountered an error, or the block type is not supported. Console.WriteLine("UnexpectedType=" + block.blockType.ToString()); // Increment the counter to generate a unique filename. if (!UnexpectedBlockTypeCount.ContainsKey(filename)) { UnexpectedBlockTypeCount[filename] = new Dictionary <int, int>(); } if (!UnexpectedBlockTypeCount[filename].ContainsKey(block.blockType)) { UnexpectedBlockTypeCount[filename][block.blockType] = 0; } UnexpectedBlockTypeCount[filename][block.blockType]++; // The size is part of the block, so go back 1 byte. ms_block.Position -= 1; SaveUnexpectedBlock(versionDirectory + "\\UnexpectedBlocks\\", filename + "-" + block.blockType + "-" + UnexpectedBlockTypeCount[filename][block.blockType] + ".blk", ms_block, block.blockSize); } if (block.blockType == TCBlock.BLOCK_TYPE_INIT || block.blockType == TCBlock.BLOCK_TYPE_PACKETS) { // Handle the array of packets. int count = 0; for (int bCounter = 0; bCounter < 2; bCounter++) { count += ms_block.ReadByte() << (8 * bCounter); } for (int bCounter = 0; bCounter < count; bCounter++) { Packet packet = Packet.ReadPacket(ms_block); int packetType = packet.packetType; if (PacketNames.ContainsKey(packetType)) { // For debugging purposes, track the character's position // within the map. if (packetType == Packet.ID_MAP_WHOLE) { pos = Packet.GetMapPosition(packet); } else if (packetType == Packet.ID_MAP_NORTH) { pos.y--; } else if (packetType == Packet.ID_MAP_EAST) { pos.x++; } else if (packetType == Packet.ID_MAP_SOUTH) { pos.y++; } else if (packetType == Packet.ID_MAP_WEST) { pos.x--; } else if (packetType == Packet.ID_MAP_DOWN) { pos.z++; } else if (packetType == Packet.ID_MAP_UP) { pos.z--; } // Position = 1 (we don't care for the header // at index 0). //ms_packet.Position = 1; string dir = ConstructFilePath(versionDirectory + "\\PacketDumpTest", PacketNames[packetType]); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (!PacketCounts.ContainsKey(packetType)) { PacketCounts[packetType] = new Dictionary <string, int>(); } if (!PacketCounts[packetType].ContainsKey(filename)) { PacketCounts[packetType][filename] = 0; } PacketCounts[packetType][filename]++; // Packet Sizes if (!PacketSizes.ContainsKey(packetType)) { PacketSizes[packetType] = new Dictionary <string, List <int> >(); } if (!PacketSizes[packetType].ContainsKey(filename)) { PacketSizes[packetType][filename] = new List <int>(); } PacketSizes[packetType][filename].Add((int)packet.data.Length); // Record the data if (RecordingPackets.IndexOf(packetType) != -1) { string packetDirectory = versionDirectory; if (!Directory.Exists(packetDirectory)) { Directory.CreateDirectory(packetDirectory); } packetDirectory = ConstructFilePath(packetDirectory, "Packets"); if (!Directory.Exists(packetDirectory)) { Directory.CreateDirectory(packetDirectory); } packetDirectory = ConstructFilePath(packetDirectory, packetType.ToString()); if (!Directory.Exists(packetDirectory)) { Directory.CreateDirectory(packetDirectory); } string fn = filename + "-" + PacketCounts[packetType][filename].ToString() + ".tpk"; using (FileStream fs = new FileStream(ConstructFilePath(packetDirectory, fn), FileMode.Create, FileAccess.Write)) { fs.Write(packet.data, 0, packet.data.Length); txtOutput += packetType.ToString() + "\t" + fn + "\t" + block.blockTime.ToString() + "\t" + pos.x + ", " + pos.y + ", " + pos.z + "\t" + Environment.NewLine; } } } else { Console.WriteLine("Could not find PacketNames dictionary entry for key=" + packetType.ToString()); } } } //ms_block.Position = 0; } else { Console.WriteLine("Skipped a block."); } } if (txtOutput != "") { // Structure file. // Create the /Structure directory, if it doesn't exist. string structureDirectory = versionDirectory + "\\Structure"; if (!Directory.Exists(structureDirectory)) { Directory.CreateDirectory(structureDirectory); } using (FileStream fs = new FileStream(ConstructFilePath(structureDirectory, filename + ".structure"), FileMode.Create, FileAccess.Write)) { using (StreamWriter sw = new StreamWriter(fs)) { sw.Write(txtOutput); txtOutput = ""; } } } Console.WriteLine("Finished reading recording."); // Record the PacketSizes for future references string packetSizeDirectory = ConstructFilePath(versionDirectory, "PacketSizes"); if (!Directory.Exists(packetSizeDirectory)) { Directory.CreateDirectory(packetSizeDirectory); } foreach (KeyValuePair <int, Dictionary <string, List <int> > > packet in PacketSizes) { int packetID = packet.Key; List <int> sizes = new List <int>(); Dictionary <string, List <int> > filedata = packet.Value; foreach (KeyValuePair <string, List <int> > packetSizesInFile in filedata) { sizes.AddRange(packetSizesInFile.Value); } using (FileStream fs = new FileStream(ConstructFilePath(packetSizeDirectory, packetID.ToString() + ".pktsz"), FileMode.Create, FileAccess.Write)) { using (StreamWriter sw = new StreamWriter(fs)) { sw.Write(String.Join("\n", sizes.ToArray())); } } } } } catch (Exception) { string dir = destination + "\\" + recording.Version + "\\FailedDecompression"; string dest = dir + "\\" + Path.GetFileName(recordings[i]); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (recordings[i] != dest) { using (FileStream fs = new FileStream(recordings[i], FileMode.Open, FileAccess.Read)) { using (FileStream fsOut = new FileStream(dest, FileMode.Create, FileAccess.Write)) { fs.CopyTo(fsOut); } } } //Console.WriteLine(e); Console.WriteLine("Failed to decompress recording " + recordings[i] + ". Stream might be corrupted."); } } }