static void Main(string[] args) { if (args.Length < 2) { throw new ArgumentException("Not enough arguments! Required: file, outdir, (build in x.x.x format), (pattern name to always use)"); } if (!File.Exists(args[0])) { throw new FileNotFoundException("File not found!"); } var file = MemoryMappedFile.CreateFromFile(args[0], FileMode.Open); var maps = EXEParsing.GenerateMap(file.CreateViewAccessor()); ulong translate(ulong search) => maps.Select(map => map.translateMemoryToFile(search)).FirstOrDefault(r => r != 0x0); using (var bin = new BinaryReader(file.CreateViewStream())) { var chunkSize = 1024; // Find version var buildPattern = new byte?[] { 0x42, 0x75, 0x69, 0x6C, 0x64, 0x20, null, null, null, null, null, 0x20, 0x28, null, null, null, null, null, 0x29, 0x20, 0x28 }; var buildPatternLength = buildPattern.Length; var build = ""; var patternOverride = ""; if (args.Length >= 3) { build = args[2]; if (args.Length >= 4) { patternOverride = args[3]; } } if (build == "") { while (true) { if ((bin.BaseStream.Length - bin.BaseStream.Position) < chunkSize) { break; } var posInStack = Search(bin.ReadBytes(chunkSize), buildPattern); if (posInStack != chunkSize) { var matchPos = bin.BaseStream.Position - chunkSize + posInStack; bin.BaseStream.Position = matchPos; bin.ReadBytes(6); var buildNumber = new string(bin.ReadChars(5)); bin.ReadBytes(2); var patch = new string(bin.ReadChars(5)); build = patch + "." + buildNumber; } else { bin.BaseStream.Position = bin.BaseStream.Position - buildPatternLength; } } } if (build == "") { // Retry with backup pattern (crash log output) bin.BaseStream.Position = 0; buildPattern = new byte?[] { 0x00, 0x3C, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3E, 0x20 }; // <Version> buildPatternLength = buildPattern.Length; while (true) { if ((bin.BaseStream.Length - bin.BaseStream.Position) < chunkSize) { break; } var posInStack = Search(bin.ReadBytes(chunkSize), buildPattern); if (posInStack != chunkSize) { var matchPos = bin.BaseStream.Position - chunkSize + posInStack; bin.BaseStream.Position = matchPos; bin.ReadBytes(11); build = new string(bin.ReadChars(11)); } else { bin.BaseStream.Position = bin.BaseStream.Position - buildPatternLength; } } } if (build == "") { // Retry with RenderService pattern.. bin.BaseStream.Position = 0; buildPattern = new byte?[] { 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, null, null, null, null, null, 0x00 }; // <Version> buildPatternLength = buildPattern.Length; while (true) { if ((bin.BaseStream.Length - bin.BaseStream.Position) < chunkSize) { break; } var posInStack = Search(bin.ReadBytes(chunkSize), buildPattern); if (posInStack != chunkSize) { var matchPos = bin.BaseStream.Position - chunkSize + posInStack; bin.BaseStream.Position = matchPos; bin.ReadBytes(14); build = new string(bin.ReadChars(5)); if (args.Length == 3) { build = args[2]; } else { Console.WriteLine("Expansion, major and minor version not found in binary. Please enter it in this format X.X.X: "); build = Console.ReadLine() + "." + build; } } else { bin.BaseStream.Position = bin.BaseStream.Position - buildPatternLength; } } } if (build == "") { Console.WriteLine("Build was not found! Please enter a build in this format: X.X.X.XXXXX"); build = Console.ReadLine(); } if (build == "8.0.1.26321") { Console.WriteLine("Build 8.0.1.26321 has incorrect DBMeta, skipping.."); return; } // Reset position for DBMeta reading bin.BaseStream.Position = 0; // Extract DBMeta var metas = new Dictionary <string, DBMeta>(); var patternBuilder = new PatternBuilder(); foreach (var pattern in patternBuilder.patterns) { if (patternOverride == "") { // Skip versions of the pattern that aren't for this expansion if (build.StartsWith("1")) { if (!pattern.compatiblePatches.Contains(build.Substring(0, 6))) { Console.WriteLine("Skipping " + pattern.name + " as it does not list " + build + " as compatible!"); continue; } if (!pattern.compatiblePatches.Contains(build.Substring(0, 6))) { Console.WriteLine("Skipping " + pattern.name + " as it does not list " + build + " as compatible!"); continue; } if (pattern.minBuild != 0 && pattern.minBuild > int.Parse(build.Substring(7))) { Console.WriteLine("Skipping " + pattern.name + " as minimum build " + pattern.minBuild + " exceeds build of " + build.Substring(6)); continue; } if (pattern.maxBuild != 0 && int.Parse(build.Substring(7)) > pattern.maxBuild) { Console.WriteLine("Skipping " + pattern.name + " as maximum build " + pattern.maxBuild + " exceeds build of " + build.Substring(6)); continue; } } else { if (!pattern.compatiblePatches.Contains(build.Substring(0, 5))) { Console.WriteLine("Skipping " + pattern.name + " as it does not list " + build + " as compatible!"); continue; } if (!pattern.compatiblePatches.Contains(build.Substring(0, 5))) { Console.WriteLine("Skipping " + pattern.name + " as it does not list " + build + " as compatible!"); continue; } if (pattern.minBuild != 0 && pattern.minBuild > int.Parse(build.Substring(6))) { Console.WriteLine("Skipping " + pattern.name + " as minimum build " + pattern.minBuild + " exceeds build of " + build.Substring(6)); continue; } if (pattern.maxBuild != 0 && int.Parse(build.Substring(6)) > pattern.maxBuild) { Console.WriteLine("Skipping " + pattern.name + " as maximum build " + pattern.maxBuild + " exceeds build of " + build.Substring(6)); continue; } } } else { if (patternOverride != pattern.name) { continue; } } var patternBytes = ParsePattern(pattern.cur_pattern).ToArray(); var patternLength = patternBytes.Length; while (true) { if ((bin.BaseStream.Length - bin.BaseStream.Position) < chunkSize) { break; } var posInStack = Search(bin.ReadBytes(chunkSize), patternBytes); if (posInStack != chunkSize) { var matchPos = bin.BaseStream.Position - chunkSize + posInStack; Console.WriteLine("Pattern " + pattern.name + " matched at " + matchPos); if (pattern.offsets.ContainsKey(Name.FDID)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.FDID]; var fdid = bin.ReadUInt32(); if (fdid < 53183) { Console.WriteLine("Invalid filedataid " + fdid + ", skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.RECORD_SIZE)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.RECORD_SIZE]; if (bin.ReadUInt32() == 0) { Console.WriteLine("Record size is 0, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.DB_NAME)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_NAME]; if (bin.ReadUInt32() < 10) { Console.WriteLine("Name offset is invalid, skipping match.."); continue; } bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_NAME]; var targetOffset = (long)translate(bin.ReadUInt64()); if (targetOffset > bin.BaseStream.Length) { Console.WriteLine("Name offset is out of range of file, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.DB_FILENAME)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_FILENAME]; if (bin.ReadUInt32() < 10) { Console.WriteLine("Name offset is invalid, skipping match.."); continue; } bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_FILENAME]; var targetOffset = (long)translate(bin.ReadUInt64()); if (targetOffset > bin.BaseStream.Length) { Console.WriteLine("Name offset is out of range of file, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.NUM_FIELD_IN_FILE)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.NUM_FIELD_IN_FILE]; if (bin.ReadUInt32() > 5000) { Console.WriteLine("Num fields in file is over 5000, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.FIELD_TYPES_IN_FILE) && pattern.offsets.ContainsKey(Name.FIELD_SIZES_IN_FILE)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.FIELD_TYPES_IN_FILE]; var fieldTypesInFile = bin.ReadInt64(); bin.BaseStream.Position = matchPos + pattern.offsets[Name.FIELD_SIZES_IN_FILE]; var fieldSizesInFileOffs = bin.ReadInt64(); if (fieldTypesInFile == fieldSizesInFileOffs) { Console.WriteLine("Field types in file offset == field sizes in file offset, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.DB_CACHE_FILENAME)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_CACHE_FILENAME]; bin.BaseStream.Position = (long)translate((ulong)bin.ReadInt64()); var adbname = bin.ReadCString(); bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_CACHE_FILENAME]; if (!adbname.EndsWith("adb")) { Console.WriteLine("ADB filename does not end in adb, skipping match.."); continue; } } bin.BaseStream.Position = matchPos; var meta = ReadMeta(bin, pattern); if (pattern.offsets.ContainsKey(Name.DB_NAME)) { bin.BaseStream.Position = (long)translate((ulong)meta.nameOffset); var filename = bin.ReadCString(); if (filename.Contains("DBFilesClient")) { filename = filename.Substring(filename.IndexOf("\\") + 1); } metas.TryAdd(Path.GetFileNameWithoutExtension(filename), meta); } else if (pattern.offsets.ContainsKey(Name.DB_FILENAME)) { bin.BaseStream.Position = (long)translate((ulong)meta.dbFilenameOffs); var name = bin.ReadCString(); metas.TryAdd(Path.GetFileNameWithoutExtension(name), meta); } bin.BaseStream.Position = matchPos + patternLength; } else { bin.BaseStream.Position = bin.BaseStream.Position - patternLength; } } bin.BaseStream.Position = 0; } var outputDirectory = Path.Combine(args[1], build); if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } // Process DBMetas foreach (var meta in metas) { if ((long)translate((ulong)meta.Value.field_offsets_offs) > bin.BaseStream.Length) { Console.WriteLine("Skipping reading of " + meta.Key + " because first offset is way out of range!"); continue; } var writer = new StreamWriter(Path.Combine(outputDirectory, meta.Key + ".dbd")); writer.WriteLine("COLUMNS"); Console.Write("Writing " + meta.Key + ".dbd.."); var fieldCount = 0; if (meta.Value.num_fields == 0 && meta.Value.num_fields_in_file != 0) { fieldCount = meta.Value.num_fields_in_file; } else { fieldCount = meta.Value.num_fields; } var field_offsets = ReadFieldArray(bin, fieldCount, (long)translate((ulong)meta.Value.field_offsets_offs)); var field_sizes = ReadFieldArray(bin, fieldCount, (long)translate((ulong)meta.Value.field_sizes_offs)); var field_types = ReadFieldArray(bin, fieldCount, (long)translate((ulong)meta.Value.field_types_offs)); var field_flags = ReadFieldArray(bin, fieldCount, (long)translate((ulong)meta.Value.field_flags_offs)); var field_sizes_in_file = ReadFieldArray(bin, fieldCount, (long)translate((ulong)meta.Value.field_sizes_in_file_offs)); var field_types_in_file = ReadFieldArray(bin, fieldCount, (long)translate((ulong)meta.Value.field_types_in_file_offs)); var field_flags_in_file = ReadFieldArray(bin, fieldCount, (long)translate((ulong)meta.Value.field_flags_in_file_offs)); var field_names_in_file = ReadFieldOffsetArray(bin, fieldCount, (long)translate((ulong)meta.Value.namesInFileOffs)); if (meta.Value.id_column == -1) { writer.WriteLine("int ID"); } var columnNames = new List <string>(); var columnTypeFlags = new List <Tuple <int, int> >(); for (var i = 0; i < meta.Value.num_fields_in_file; i++) { if (field_flags_in_file.Count == 0) { columnTypeFlags.Add(new Tuple <int, int>(field_types_in_file[i], 0)); } else { columnTypeFlags.Add(new Tuple <int, int>(field_types_in_file[i], field_flags_in_file[i])); } } if (meta.Value.num_fields != 0 && (meta.Value.num_fields_in_file != meta.Value.num_fields)) { if (meta.Value.num_fields_in_file > field_flags.Count()) { columnTypeFlags.Add(new Tuple <int, int>(field_types[meta.Value.num_fields_in_file], 0)); } else { columnTypeFlags.Add(new Tuple <int, int>(field_types[meta.Value.num_fields_in_file], field_flags[meta.Value.num_fields_in_file])); } } for (var i = 0; i < columnTypeFlags.Count; i++) { if (field_names_in_file.Count > 0) { bin.BaseStream.Position = (long)translate(field_names_in_file[i]); columnNames.Add(CleanRealName(bin.ReadCString())); } else { columnNames.Add(GenerateName(i, build)); } var t = TypeToT(columnTypeFlags[i].Item1, (FieldFlags)columnTypeFlags[i].Item2); if (field_names_in_file.Count > 0) { if (t.Item1 == "locstring") { writer.WriteLine(t.Item1 + " " + columnNames[i] + "_lang"); } else { if (t.Item1 == "uint") { writer.WriteLine("int " + columnNames[i]); } else { writer.WriteLine(t.Item1 + " " + columnNames[i]); } } } else { if (t.Item1 == "locstring") { writer.WriteLine(t.Item1 + " " + columnNames[i] + "_lang?"); } else { if (t.Item1 == "uint") { writer.WriteLine("int " + columnNames[i] + "?"); } else { writer.WriteLine(t.Item1 + " " + columnNames[i] + "?"); } } } } writer.WriteLine(); if (meta.Value.layout_hash != 0) { writer.WriteLine("LAYOUT " + meta.Value.layout_hash.ToString("X8").ToUpper()); } writer.WriteLine("BUILD " + build); if (meta.Value.sparseTable == 1) { writer.WriteLine("COMMENT table is sparse"); } if (meta.Value.id_column == -1) { writer.WriteLine("$noninline,id$ID<32>"); } for (var i = 0; i < meta.Value.num_fields_in_file; i++) { var typeFlags = ("int", 32); if (field_flags_in_file.Count == 0) { typeFlags = TypeToT(field_types_in_file[i], 0); } else { typeFlags = TypeToT(field_types_in_file[i], (FieldFlags)field_flags_in_file[i]); } if (meta.Value.id_column == i) { writer.Write("$id$"); } if (build.StartsWith("7.3.5") || build.StartsWith("8")) { if (meta.Value.column_8C == i) { writer.Write("$relation$"); if (meta.Value.column_90 != i) { throw new Exception("No column_90 but there is column_8C send help!"); } } } writer.Write(columnNames[i]); if (typeFlags.Item1 == "locstring") { writer.Write("_lang"); } if (typeFlags.Item2 > 0) { if (typeFlags.Item1 == "uint") { writer.Write("<u" + typeFlags.Item2 + ">"); } else { writer.Write("<" + typeFlags.Item2 + ">"); } } if (field_sizes_in_file[i] != 1) { // 6.0.1 has sizes in bytes if (build.StartsWith("6.0.1")) { var supposedSize = 0; if ((typeFlags.Item1 == "uint" || typeFlags.Item1 == "int") && typeFlags.Item2 != 32) { supposedSize = typeFlags.Item2 / 8; } else { supposedSize = 4; } var fixedSize = field_sizes_in_file[i] / supposedSize; if (fixedSize > 1) { writer.Write("[" + fixedSize + "]"); } } else { writer.Write("[" + field_sizes_in_file[i] + "]"); } } writer.WriteLine(); } if (meta.Value.num_fields != 0 && (meta.Value.num_fields_in_file != meta.Value.num_fields)) { var i = meta.Value.num_fields_in_file; var typeFlags = TypeToT(columnTypeFlags[i].Item1, (FieldFlags)columnTypeFlags[i].Item2); writer.Write("$noninline,relation$" + columnNames[i]); if (typeFlags.Item1 == "locstring") { writer.Write("_lang"); } if (typeFlags.Item2 > 0) { if (typeFlags.Item1 == "uint") { writer.Write("<u" + typeFlags.Item2 + ">"); } else if (typeFlags.Item1 == "int") { writer.Write("<" + typeFlags.Item2 + ">"); } } if (field_sizes[i] != 1) { writer.Write("[" + field_sizes[i] + "]"); } } writer.Flush(); writer.Close(); Console.Write("..done!\n"); } } Environment.Exit(0); }
static void Main(string[] args) { if (args.Length < 2) { throw new ArgumentException("Not enough arguments! Required: file, outdir"); } if (!File.Exists(args[0])) { throw new FileNotFoundException("File not found!"); } var file = MemoryMappedFile.CreateFromFile(args[0], FileMode.Open); var stream = file.CreateViewAccessor(); #region BinaryMagic long offset = 0; stream.Read(offset, out Header header); offset += Marshal.SizeOf(header); var maps = new List <Map>(); for (var i = 0; i < header.commandsCount; i++) { stream.Read(offset, out Command command); if (command.id == 25) { var segmentOffset = offset + 4 + 4 + 16; // Segment start + id + size + name; var vmemOffs = stream.ReadUInt64(segmentOffset); var vmemSize = stream.ReadUInt64(segmentOffset + 8); var fileOffs = stream.ReadUInt64(segmentOffset + 16); var fileSize = stream.ReadUInt64(segmentOffset + 24); var map = new Map { memoryStart = vmemOffs, memoryEnd = vmemOffs + vmemSize, fileStart = fileOffs, fileEnd = fileOffs + fileSize }; maps.Add(map); } offset += command.size; } Func <UInt64, UInt64> translate = search => maps.Select(map => map.translateMemoryToFile(search)).FirstOrDefault(r => r != 0x0); #endregion using (var bin = new BinaryReader(file.CreateViewStream())) { var chunkSize = 1024; // Find version var buildPattern = new byte?[] { 0x42, 0x75, 0x69, 0x6C, 0x64, 0x20, null, null, null, null, null, 0x20, 0x28, null, null, null, null, null, 0x29, 0x20, 0x28 }; var buildPatternLength = buildPattern.Length; var build = ""; while (true) { if ((bin.BaseStream.Length - bin.BaseStream.Position) < chunkSize) { break; } var posInStack = Search(bin.ReadBytes(chunkSize), buildPattern); if (posInStack != chunkSize) { var matchPos = bin.BaseStream.Position - chunkSize + posInStack; bin.BaseStream.Position = matchPos; bin.ReadBytes(6); var buildNumber = new string(bin.ReadChars(5)); bin.ReadBytes(2); var patch = new string(bin.ReadChars(5)); build = patch + "." + buildNumber; } else { bin.BaseStream.Position = bin.BaseStream.Position - buildPatternLength; } } if (build == "") { // Retry with backup pattern (crash log output) bin.BaseStream.Position = 0; buildPattern = new byte?[] { 0x00, 0x3C, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3E, 0x20 }; // <Version> buildPatternLength = buildPattern.Length; while (true) { if ((bin.BaseStream.Length - bin.BaseStream.Position) < chunkSize) { break; } var posInStack = Search(bin.ReadBytes(chunkSize), buildPattern); if (posInStack != chunkSize) { var matchPos = bin.BaseStream.Position - chunkSize + posInStack; bin.BaseStream.Position = matchPos; bin.ReadBytes(11); build = new string(bin.ReadChars(11)); } else { bin.BaseStream.Position = bin.BaseStream.Position - buildPatternLength; } } } if (build == "") { throw new Exception("Build was not found!"); } // Reset position for DBMeta reading bin.BaseStream.Position = 0; // Extract DBMeta var metas = new Dictionary <string, DBMeta>(); var patternBuilder = new PatternBuilder(); foreach (var pattern in patternBuilder.patterns) { // Skip versions of the pattern that aren't for this expansion if (build[0] != pattern.name[0]) { continue; } var patternBytes = ParsePattern(pattern.cur_pattern).ToArray(); var patternLength = patternBytes.Length; while (true) { if ((bin.BaseStream.Length - bin.BaseStream.Position) < chunkSize) { break; } var posInStack = Search(bin.ReadBytes(chunkSize), patternBytes); if (posInStack != chunkSize) { var matchPos = bin.BaseStream.Position - chunkSize + posInStack; Console.WriteLine("Pattern " + pattern.name + " matched at " + matchPos); if (pattern.offsets.ContainsKey(Name.FDID)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.FDID]; if (bin.ReadUInt32() < 53183) { Console.WriteLine("Invalid filedataid, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.RECORD_SIZE)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.RECORD_SIZE]; if (bin.ReadUInt32() == 0) { Console.WriteLine("Record size is 0, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.DB_NAME)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_NAME]; if (bin.ReadUInt32() < 10) { Console.WriteLine("Name offset is invalid, skipping match.."); continue; } bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_NAME]; var targetOffset = (long)translate(bin.ReadUInt64()); if (targetOffset > bin.BaseStream.Length) { Console.WriteLine("Name offset is out of range of file, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.DB_FILENAME)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_FILENAME]; if (bin.ReadUInt32() < 10) { Console.WriteLine("Name offset is invalid, skipping match.."); continue; } bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_FILENAME]; var targetOffset = (long)translate(bin.ReadUInt64()); if (targetOffset > bin.BaseStream.Length) { Console.WriteLine("Name offset is out of range of file, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.NUM_FIELD_IN_FILE)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.NUM_FIELD_IN_FILE]; if (bin.ReadUInt32() > 5000) { Console.WriteLine("Num fields in file is over 5000, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.FIELD_TYPES_IN_FILE) && pattern.offsets.ContainsKey(Name.FIELD_SIZES_IN_FILE)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.FIELD_TYPES_IN_FILE]; var fieldTypesInFile = bin.ReadInt64(); bin.BaseStream.Position = matchPos + pattern.offsets[Name.FIELD_SIZES_IN_FILE]; var fieldSizesInFileOffs = bin.ReadInt64(); if (fieldTypesInFile == fieldSizesInFileOffs) { Console.WriteLine("Field types in file offset == field sizes in file offset, skipping match.."); continue; } } if (pattern.offsets.ContainsKey(Name.DB_CACHE_FILENAME)) { bin.BaseStream.Position = matchPos + pattern.offsets[Name.DB_CACHE_FILENAME]; var name = bin.ReadCString(); if (!name.EndsWith("adb")) { Console.WriteLine("ADB filename does not end in adb, skipping match.."); continue; } } bin.BaseStream.Position = matchPos; var meta = ReadMeta(bin, pattern); if (pattern.offsets.ContainsKey(Name.DB_NAME)) { bin.BaseStream.Position = (long)translate((ulong)meta.nameOffset); metas.TryAdd(bin.ReadCString(), meta); } else if (pattern.offsets.ContainsKey(Name.DB_FILENAME)) { bin.BaseStream.Position = (long)translate((ulong)meta.dbFilenameOffs); var name = bin.ReadCString(); metas.TryAdd(Path.GetFileNameWithoutExtension(name), meta); } bin.BaseStream.Position = matchPos + patternLength; } else { bin.BaseStream.Position = bin.BaseStream.Position - patternLength; } } bin.BaseStream.Position = 0; } var outputDirectory = Path.Combine(args[1], build); if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } // Process DBMetas foreach (var meta in metas) { if ((long)translate((ulong)meta.Value.field_offsets_offs) > bin.BaseStream.Length) { Console.WriteLine("Skipping reading of " + meta.Key + " because first offset is way out of range!"); continue; } var writer = new StreamWriter(Path.Combine(outputDirectory, meta.Key + ".dbd")); writer.WriteLine("COLUMNS"); Console.Write("Writing " + meta.Key + ".dbd.."); var field_offsets = new List <int>(); bin.BaseStream.Position = (long)translate((ulong)meta.Value.field_offsets_offs); for (var i = 0; i < meta.Value.num_fields; i++) { field_offsets.Add(bin.ReadInt32()); } var field_sizes = new List <int>(); bin.BaseStream.Position = (long)translate((ulong)meta.Value.field_sizes_offs); for (var i = 0; i < meta.Value.num_fields; i++) { field_sizes.Add(bin.ReadInt32()); } var field_types = new List <int>(); bin.BaseStream.Position = (long)translate((ulong)meta.Value.field_types_offs); for (var i = 0; i < meta.Value.num_fields; i++) { field_types.Add(bin.ReadInt32()); } var field_flags = new List <int>(); bin.BaseStream.Position = (long)translate((ulong)meta.Value.field_flags_offs); for (var i = 0; i < meta.Value.num_fields; i++) { field_flags.Add(bin.ReadInt32()); } var field_sizes_in_file = new List <int>(); bin.BaseStream.Position = (long)translate((ulong)meta.Value.field_sizes_in_file_offs); for (var i = 0; i < meta.Value.num_fields; i++) { field_sizes_in_file.Add(bin.ReadInt32()); } var field_types_in_file = new List <int>(); bin.BaseStream.Position = (long)translate((ulong)meta.Value.field_types_in_file_offs); for (var i = 0; i < meta.Value.num_fields; i++) { field_types_in_file.Add(bin.ReadInt32()); } // Read field flags in file var field_flags_in_file = new List <int>(); bin.BaseStream.Position = (long)translate((ulong)meta.Value.field_flags_in_file_offs); for (var i = 0; i < meta.Value.num_fields; i++) { field_flags_in_file.Add(bin.ReadInt32()); } if (meta.Value.id_column == -1) { writer.WriteLine("int ID"); } var columnNames = new List <string>(); var columnTypeFlags = new List <Tuple <int, int> >(); for (var i = 0; i < meta.Value.num_fields_in_file; i++) { columnTypeFlags.Add(new Tuple <int, int>(field_types_in_file[i], field_flags_in_file[i])); } if (meta.Value.num_fields_in_file != meta.Value.num_fields) { columnTypeFlags.Add(new Tuple <int, int>(field_types[meta.Value.num_fields_in_file], field_flags[meta.Value.num_fields_in_file])); } for (var i = 0; i < columnTypeFlags.Count; i++) { columnNames.Add("field_" + new Random().Next(1, int.MaxValue).ToString().PadLeft(9, '0')); var t = TypeToT(columnTypeFlags[i].Item1, (FieldFlags)columnTypeFlags[i].Item2); if (t.Item1 == "locstring") { writer.WriteLine(t.Item1 + " " + columnNames[i] + "_lang"); } else { if (t.Item1 == "uint") { writer.WriteLine("int " + columnNames[i]); } else { writer.WriteLine(t.Item1 + " " + columnNames[i]); } } } writer.WriteLine(); writer.WriteLine("LAYOUT " + meta.Value.layout_hash.ToString("X8").ToUpper()); writer.WriteLine("BUILD " + build); if (meta.Value.sparseTable == 1) { writer.WriteLine("COMMENT table is sparse"); } if (meta.Value.id_column == -1) { writer.WriteLine("$noninline,id$ID<32>"); } for (var i = 0; i < meta.Value.num_fields_in_file; i++) { var typeFlags = TypeToT(field_types_in_file[i], (FieldFlags)field_flags_in_file[i]); if (meta.Value.id_column == i) { writer.Write("$id$"); } if (build.StartsWith("7.3.5") || build.StartsWith("8.0.1")) { if (meta.Value.column_8C == i) { writer.Write("$relation$"); if (meta.Value.column_90 != i) { throw new Exception("No column_90 but there is column_8C send help!"); } } } writer.Write(columnNames[i]); if (typeFlags.Item1 == "locstring") { writer.Write("_lang"); } if (typeFlags.Item2 > 0) { if (typeFlags.Item1 == "uint") { writer.Write("<u" + typeFlags.Item2 + ">"); } else { writer.Write("<" + typeFlags.Item2 + ">"); } } if (field_sizes_in_file[i] != 1) { writer.Write("[" + field_sizes_in_file[i] + "]"); } writer.WriteLine(); } if (meta.Value.num_fields_in_file != meta.Value.num_fields) { var i = meta.Value.num_fields_in_file; var typeFlags = TypeToT(field_types[i], (FieldFlags)field_flags[i]); writer.Write("$noninline,relation$" + columnNames[i]); if (typeFlags.Item1 == "locstring") { writer.Write("_lang"); } if (typeFlags.Item2 > 0) { if (typeFlags.Item1 == "uint") { writer.Write("<u" + typeFlags.Item2 + ">"); } else { writer.Write("<" + typeFlags.Item2 + ">"); } } if (field_sizes[i] != 1) { writer.Write("[" + field_sizes[i] + "]"); } } writer.Flush(); writer.Close(); Console.Write("..done!\n"); } } Environment.Exit(0); }