public cDatFileNode buildBtreeStructure(Node node, cDatFileBlockCache blockCache) { cDatFileNode newFolder = new cDatFileNode(this, blockCache); foreach (uint entry in node.Entries) { cDatFileEntry file = fileCache[entry]; file.startBlockOffset = 0; file.listOfBlocks = new List <cDatFileBlock>(); //blockCache.dataToBlocks(file.listOfBlocks, file.fileContent); //file.startBlockOffset = file.listOfBlocks[0].blockOffset; newFolder.files.Add(file.fileId, file); } if (!node.IsLeaf) { foreach (Node child in node.Children) { cDatFileNode newSubFolder = buildBtreeStructure(child, blockCache); newFolder.subFolders.Add(newSubFolder); } } //newFolder.updateBlockData(this, blockCache); return(newFolder); }
public void exportDirTree(cDatFileNode directory) { StreamWriter outputFile = new StreamWriter(new FileStream(".\\dirTree.json", FileMode.Create, FileAccess.Write)); outputFile.WriteLine($"-- root directory({directory.files.Count} files, {directory.subFolders.Count} subDirectories)-- "); exportSubDirTrees(directory, 0, outputFile); }
public int countDirs(cDatFileNode directory) { int count = 1; foreach (cDatFileNode subDirectory in directory.subFolders) { count += countDirs(subDirectory); } return(count); }
public cDatFileNode(StreamReader inputFile, cDatFileBlockCache blockCache, uint startBlockOffset, int blockSize, eDatFormat fileFormat) { this.startBlockOffset = startBlockOffset; this.blockSize = blockSize; int size; if (fileFormat == eDatFormat.ToD) { size = sizeToD; } else { size = sizeRetail; } listOfBlocks = new List <cDatFileBlock>(); MemoryStream memoryStream = blockCache.blocksToData(startBlockOffset, size, listOfBlocks); memoryStream.Position = 0; StreamReader reader = new StreamReader(memoryStream); files = new SortedDictionary <uint, cDatFileEntry>(); //max 61 subFolders = new List <cDatFileNode>(); //max 62 List <uint> subFolderOffsets = new List <uint>(); for (int i = 0; i < 62; i++) { subFolderOffsets.Add(Utils.readUInt32(reader)); } uint entryCount = Utils.readUInt32(reader); // folder is allowed to have (files + 1) subfolders if (subFolderOffsets[0] != 0) { for (int i = 0; i < entryCount + 1; i++) { cDatFileNode newDirectory = new cDatFileNode(inputFile, blockCache, subFolderOffsets[i], blockSize, fileFormat); subFolders.Add(newDirectory); } } for (uint i = 0; i < entryCount; i++) { cDatFileEntry file = new cDatFileEntry(reader, fileFormat); files.Add(file.fileId, file); } }
private void exportSubDirTrees(cDatFileNode directory, int tabCount, StreamWriter outputFile) { string tab = ""; for (int i = 0; i < tabCount; i++) { tab += " "; } foreach (KeyValuePair <uint, cDatFileEntry> entry in directory.files) { cDatFileEntry file = entry.Value; //if ((file.fileId & 0x0000FFFF) == 0x0000FFFF) //{ // uint x = (uint)file.fileId >> 24; // uint y = (uint)(file.fileId & 0x00FF0000) >> 16; // outputFile.WriteLine($"{tab}file: {file.fileId.ToString("x8")} = cellLandblock {x},{y}"); //} //else if((file.fileId & 0x0000FFFE) == 0x0000FFFE) //{ // uint x = (uint)file.fileId >> 24; // uint y = (uint)(file.fileId & 0x00FF0000) >> 16; // outputFile.WriteLine($"{tab}file: {file.fileId.ToString("x8")} = landblockInfo {x},{y}"); //} //else //outputFile.WriteLine($"{tab}file: {file.fileId.ToString("x8")} bitFlags:{file.bitFlags.ToString("x8")}"); outputFile.WriteLine($"{tab}file: {file.fileId.ToString("x8")}"); } outputFile.Flush(); int subDirCount = 0; foreach (cDatFileNode subDirectory in directory.subFolders) { outputFile.WriteLine($"{tab}-- {tabCount} subDirectory {subDirCount} ({subDirectory.files.Count} files, {subDirectory.subFolders.Count} subDirectories)-- "); exportSubDirTrees(subDirectory, tabCount + 1, outputFile); subDirCount++; } outputFile.Flush(); }
public void loadFromDat(string filename) { StreamReader inputFile = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read)); if (inputFile.BaseStream.Length < 1024) { Console.WriteLine("{0} is too small to be a valid dat file", filename); return; } Console.WriteLine("Reading data from {0}...", filename); Stopwatch timer = new Stopwatch(); timer.Start(); inputFile.BaseStream.Seek(257, SeekOrigin.Begin); int format = Utils.readInt32(inputFile); if (format == 0x4C50) { inputFile.BaseStream.Seek(256, SeekOrigin.Begin); //skip acVersionStr which is empty acTransactionRecord = Utils.readBytes(inputFile, 64); for (int i = 4; i < 64; i++) { acTransactionRecord[i] = 0; } fileType = Utils.readUInt32(inputFile); if (fileType == 0x5442) { fileFormat = eDatFormat.ToD; } } else { acTransactionRecord = new byte[64]; acTransactionRecord[0] = 0x00; acTransactionRecord[1] = 0x50; acTransactionRecord[2] = 0x4C; acTransactionRecord[3] = 0x00; inputFile.BaseStream.Seek(300, SeekOrigin.Begin); fileType = Utils.readUInt32(inputFile); if (fileType == 0x5442) { fileFormat = eDatFormat.retail; } } if (fileFormat == eDatFormat.invalid) { Console.WriteLine("{0} is not a valid dat file.", filename); return; } blockSize = Utils.readInt32(inputFile); fileSize = Utils.readUInt32(inputFile); dataSet = Utils.readUInt32(inputFile); if (fileFormat == eDatFormat.ToD) { dataSubset = Utils.readUInt32(inputFile); } else { //dataSet = 0x00000043 for old cell.dat //dataSet = 0x0000082f for old portal.dat if (dataSet == 0x00000043) { dataSet = 0x00000002; dataSubset = 0x00000001; } else { dataSet = 0x00000001; dataSubset = 0x00000000; } } //dataSet = 0x00000001 - dataSubset = 0x00000000 for client_portal.dat //dataSet = 0x00000001 - dataSubset = 0x69466948 for client_highres.dat //dataSet = 0x00000002 - dataSubset = 0x00000001 for client_cell_1.dat //dataSet = 0x00000003 - dataSubset = 0x00000001 for client_local_English.dat freeHead = Utils.readUInt32(inputFile); freeTail = Utils.readUInt32(inputFile); freeCount = Utils.readUInt32(inputFile); rootDirectoryOffset = Utils.readUInt32(inputFile); if (fileFormat == eDatFormat.ToD) { youngLRU = Utils.readUInt32(inputFile); oldLRU = Utils.readUInt32(inputFile); useLRU = Utils.readUInt32(inputFile); masterMapId = Utils.readUInt32(inputFile); enginePackVersion = Utils.readUInt32(inputFile); gamePackVersion = Utils.readUInt32(inputFile); versionMajor = Utils.readBytes(inputFile, 16);//int data1, short data2, short data3, int64 data4 versionMinor = Utils.readUInt32(inputFile); } else { youngLRU = 0x00000000; oldLRU = 0x00000000; useLRU = 0xcdcdcd00; masterMapId = 0x00000000; enginePackVersion = 0x00000016; gamePackVersion = 0x00000000; versionMajor = new byte[] { 0xD2, 0xD7, 0xA7, 0x34, 0x2F, 0x72, 0x46, 0x4C, 0x8A, 0xB4, 0xEF, 0x51, 0x4F, 0x85, 0x6F, 0xFD }; versionMinor = 0x000000de; } inputBlockCache = new cDatFileBlockCache(fileSize, blockSize, freeHead, freeTail, freeCount); cDatFileBlock.loadBlocksAndAddToDictionary(inputBlockCache, inputFile, blockSize); rootDirectory = new cDatFileNode(inputFile, inputBlockCache, rootDirectoryOffset, blockSize, fileFormat); rootDirectory.loadFilesAndAddToCache(fileCache, inputBlockCache, inputFile, blockSize); timer.Stop(); Console.WriteLine("{0} blocks read in {1} seconds.", inputBlockCache.blocks.Count, timer.ElapsedMilliseconds / 1000f); }
//we only write to the ToD data format. public void writeToDat(string filename) { fileSize = inputBlockCache.fileSize; freeHead = inputBlockCache.freeHead; freeTail = inputBlockCache.freeTail; freeCount = inputBlockCache.freeCount; StreamWriter outputFile = new StreamWriter(new FileStream(filename, FileMode.Create, FileAccess.Write)); Console.WriteLine("Writing data to {0}...", filename); Stopwatch timer = new Stopwatch(); timer.Start(); ////keep some free blocks //if (inputBlockCache.freeCount < 1000) // inputBlockCache.addNewFreeBlocks(1000 - (int)inputBlockCache.freeCount); //rootDirectory.updateBlockData(this, inputBlockCache); //foreach (KeyValuePair<uint, cDatFileBlock> entry in inputBlockCache.blocks) //{ // outputFile.BaseStream.Seek(entry.Key, SeekOrigin.Begin); // entry.Value.writeToDat(outputFile, blockSize); //} //fileSize = inputBlockCache.fileSize; //freeHead = inputBlockCache.fileSize; //freeTail = inputBlockCache.fileSize; //freeCount = inputBlockCache.fileSize; bTree = new cBTree(31); foreach (KeyValuePair <uint, cDatFileEntry> entry in fileCache) { bTree.Insert(entry.Key); } outputBlockCache = new cDatFileBlockCache(blockSize, 1024); rootDirectory = buildBtreeStructure(bTree.Root, outputBlockCache); rootDirectory.updateBlockData(this, outputBlockCache); foreach (KeyValuePair <uint, cDatFileBlock> entry in outputBlockCache.blocks) { outputFile.BaseStream.Seek(entry.Key, SeekOrigin.Begin); entry.Value.writeToDat(outputFile, blockSize); } if (outputBlockCache.freeCount < 1000) { outputBlockCache.addNewFreeBlocks(1000 - (int)outputBlockCache.freeCount); } rootDirectoryOffset = rootDirectory.startBlockOffset; fileSize = outputBlockCache.fileSize; freeHead = outputBlockCache.fileSize; freeTail = outputBlockCache.fileSize; freeCount = outputBlockCache.fileSize; outputFile.BaseStream.Seek(256, SeekOrigin.Begin); //skip acVersionStr which is empty Utils.writeBytes(acTransactionRecord, outputFile); Utils.writeUInt32(fileType, outputFile); Utils.writeInt32(blockSize, outputFile); Utils.writeUInt32(fileSize, outputFile); Utils.writeUInt32(dataSet, outputFile); Utils.writeUInt32(dataSubset, outputFile); Utils.writeUInt32(freeHead, outputFile); Utils.writeUInt32(freeTail, outputFile); Utils.writeUInt32(freeCount, outputFile); Utils.writeUInt32(rootDirectoryOffset, outputFile); Utils.writeUInt32(youngLRU, outputFile); Utils.writeUInt32(oldLRU, outputFile); Utils.writeUInt32(useLRU, outputFile); Utils.writeUInt32(masterMapId, outputFile); Utils.writeUInt32(enginePackVersion, outputFile); Utils.writeUInt32(gamePackVersion, outputFile); Utils.writeBytes(versionMajor, outputFile); Utils.writeUInt32(versionMinor, outputFile); outputFile.Close(); timer.Stop(); Console.WriteLine("{0} blocks written in {1} seconds.", outputBlockCache.blocks.Count, timer.ElapsedMilliseconds / 1000f); //exportDirTree(rootDirectory); }
public void updateBlockData(cDatFile datFile, cDatFileBlockCache blockCache) { MemoryStream memoryStream = new MemoryStream(new byte[sizeToD]); StreamWriter writer = new StreamWriter(memoryStream); for (int i = 0; i < 62; i++) { if (i == 0 && subFolders.Count == 0) { Utils.writeUInt32(0, writer); } else if (i < subFolders.Count && i < files.Count + 1) //directory is allowed to have (files + 1) subdirectories { cDatFileNode subFolder = subFolders[i]; subFolder.updateBlockData(datFile, blockCache); Utils.writeUInt32(subFolder.startBlockOffset, writer); } else { Utils.writeUInt32(0xcdcdcdcd, writer); } } Utils.writeUInt32((uint)files.Count, writer); foreach (KeyValuePair <uint, cDatFileEntry> entry in files) { cDatFileEntry fileEntry = entry.Value; if (fileEntry.fileContent != null) { fileEntry.fileSize = (int)fileEntry.fileContent.Length; blockCache.dataToBlocks(fileEntry.listOfBlocks, fileEntry.fileContent); if (fileEntry.listOfBlocks.Count > 0) { fileEntry.startBlockOffset = fileEntry.listOfBlocks[0].blockOffset; } } else { fileEntry.fileSize = 0; } fileEntry.writeHeader(writer); } cDatFileEntry emptyFileEntry = new cDatFileEntry(0, datFile.fileFormat); for (int i = files.Count; i < 61; i++) { emptyFileEntry.writeHeader(writer); } writer.Flush(); blockCache.dataToBlocks(listOfBlocks, memoryStream); if (listOfBlocks.Count > 0) { startBlockOffset = listOfBlocks[0].blockOffset; } }