Esempio n. 1
0
        public static RawFile ReadRaw(string dbFile, DBEntry entry)
        {
            // figure out what file version exists
            string db2file = Path.ChangeExtension(dbFile, ".db2");

            if (File.Exists(db2file))
            {
                dbFile = db2file;
            }
            else
            {
                dbFile = Path.ChangeExtension(dbFile, ".dbc");
            }

            using (var fs = new FileStream(dbFile, FileMode.Open, FileAccess.Read))
                using (var br = new BinaryReader(fs, Encoding.UTF8))
                {
                    DBHeader header = ReadHeader(br, "", 0);
                    if (!ValidationChecks(header, dbFile, out string error))
                    {
                        return(null);
                    }

                    RawFile rawFile = new RawFile()
                    {
                        Entry = entry
                    };

                    // stringtable stuff
                    long pos = br.BaseStream.Position;
                    long stringTableStart = br.BaseStream.Position += header.RecordCount * header.RecordSize;
                    rawFile.StringTable = ReadStringTable(br, stringTableStart);             //Get stringtable
                    br.Scrub(pos);

                    // store data
                    rawFile.RawRecords = new List <byte[]>();
                    for (int i = 0; i < header.RecordCount; i++)
                    {
                        rawFile.RawRecords.Add(br.ReadBytes((int)header.RecordSize));
                    }

                    return(rawFile);
                }
        }
Esempio n. 2
0
        private static DBHeader ReadHeader(BinaryReader br, string dbFile, int build)
        {
            DBHeader header    = null;
            string   signature = br.ReadString(4);

            if (string.IsNullOrWhiteSpace(signature))
            {
                return(null);
            }

            if (signature[0] != 'W')
            {
                signature = signature.Reverse();
            }

            switch (signature)
            {
            case "WDBC":
                header = new WDBC();
                break;

            case "WDB2":
                header = new WDB2();
                break;
            }

            if (header != null)
            {
                header.ReadHeader(ref br, signature);
            }
            else
            {
                header = new WDBC();
            }

            if (build > 0)
            {
                header.BuildNumber = build;
                header.FileName    = Path.GetFileName(dbFile).ToUpper();
            }

            return(header);
        }
Esempio n. 3
0
        private static bool ValidationChecks(DBHeader header, string FileName, out string error)
        {
            error = string.Empty;
            string name = Path.GetFileName(FileName) + " " + Directory.GetParent(FileName).Name;

            if (header == null)
            {
                Console.WriteLine(name + ": Not a dbc.");
                error = "Not a dbc.";
                return(false);
            }

            if (header.RecordCount == 0 || header.RecordSize == 0)
            {
                Console.WriteLine(name + ": No records.");
                error = "No records.";
                return(false);
            }

            return(true);
        }
Esempio n. 4
0
        public static DBEntry Read(string dbFile, int build, out string error)
        {
            error = "";

            using (var fs = new FileStream(dbFile, FileMode.Open, FileAccess.Read))
                using (var br = new BinaryReader(fs, Encoding.UTF8))
                {
                    DBHeader header = ReadHeader(br, dbFile, build);
                    if (IsKnown(header, out DBEntry known))
                    {
                        return(known);
                    }

                    if (!ValidationChecks(header, dbFile, out error))
                    {
                        return(null);
                    }

                    if (header.RecordSize / header.FieldCount != 4)            // dbc has byte column
                    {
                        error = "Has byte columns.";
                        return(new DBEntry()
                        {
                            Name = Path.GetFileName(dbFile).ToUpper(),
                            Builds = new List <int>()
                            {
                                build
                            },
                            Fields = new List <DBField>()
                        });
                    }

                    Dictionary <int, string> stringTable = new Dictionary <int, string>();
                    List <byte[]>            dataTable   = new List <byte[]>();
                    FieldInfo[] fieldInfo   = new FieldInfo[header.FieldCount];
                    bool        hasStrings  = false;
                    int         nullStrings = 0;

                    // stringtable stuff
                    long pos = br.BaseStream.Position;
                    long stringTableStart = br.BaseStream.Position += header.RecordCount * header.RecordSize;
                    stringTable = ReadStringTable(br, stringTableStart);             //Get stringtable
                    br.Scrub(pos);

                    // if 1 or 2 empty strings only then strings aren't unused
                    hasStrings = !(stringTable.Values.Count <= 2 && stringTable.Values.All(x => string.IsNullOrWhiteSpace(x)));
                    // count empties
                    nullStrings = stringTable.Count(x => string.IsNullOrWhiteSpace(x.Value));

                    // read data
                    for (int i = 0; i < header.RecordCount; i++)
                    {
                        dataTable.Add(br.ReadBytes((int)header.RecordSize));
                    }

                    // compute possible types
                    for (int i = 0; i < header.FieldCount; i++)
                    {
                        // no pdb dbc struct has uint fields ITS ALL A LIE!!
                        List <FieldType> options = new List <FieldType>()
                        {
                            FieldType.INT, /*FieldType.UINT,*/ FieldType.FLOAT, FieldType.STRING
                        };
                        if (!hasStrings)
                        {
                            options.Remove(FieldType.STRING);                     // strings not used
                        }
                        List <int>    intVals    = new List <int>();
                        List <string> stringVals = new List <string>();
                        List <float>  floatVals  = new List <float>();

                        for (int r = 0; r < dataTable.Count; r++)
                        {
                            byte[] data = dataTable[r].Skip(i * 4).Take(4).ToArray();

                            // ignore 0 byte columns as they could be anything
                            if (data.All(x => x == 0))
                            {
                                continue;
                            }

                            // int value
                            int asInt = BitConverter.ToInt32(data, 0);
                            intVals.Add(asInt);

                            // string check
                            if (options.Contains(FieldType.STRING))
                            {
                                if (!stringTable.ContainsKey(asInt))
                                {
                                    options.Remove(FieldType.STRING);
                                    stringVals.Clear();                             // 100% not a string!
                                }
                                else
                                {
                                    stringVals.Add(stringTable[asInt]);
                                }
                            }

                            // float check
                            if (options.Contains(FieldType.FLOAT) && FloatUtil.IsLikelyFloat(asInt))
                            {
                                floatVals.Add(BitConverter.ToSingle(data, 0));
                            }

                            // uint check - prefer signed over unsigned as per the wow client
                            if (options.Contains(FieldType.UINT) && asInt < 0)
                            {
                                options.Remove(FieldType.UINT);
                            }
                        }

                        fieldInfo[i] = new FieldInfo()
                        {
                            IsEmpty         = intVals.Count == 0,
                            FloatPercentage = (floatVals.Count / (float)intVals.Count) * 100f,                     // % of valid floats
                            Options         = options,
                            UniqueStrings   = stringVals.Distinct().Count(),
                            UniqueInts      = intVals.Distinct().Count()
                        };
                    }

                    // calculate field types
                    List <FieldType> temp = new List <FieldType>();
                    for (int i = 0; i < fieldInfo.Length; i++)
                    {
                        var info = fieldInfo[i];

                        if (info.IsEmpty)                 // all records are 0
                        {
                            // most likely to be int, less likely to be float, very unlikely to be a string
                            temp.Add(info.Options.Contains(FieldType.UINT) ? FieldType.UINT : FieldType.INT);
                        }
                        else if (info.Options.Contains(FieldType.FLOAT) && info.FloatPercentage > FLOAT_THRESHOLD) // threshold needs tweaking?
                        {
                            temp.Add(FieldType.FLOAT);                                                             // high % of valid floats
                        }
                        else if (info.Options.Contains(FieldType.STRING) && info.UniqueStrings > 0)
                        {
                            // 1 string, 1st field is more likely an ID not a string
                            if (stringTable.Count - nullStrings < header.FieldCount && header.RecordCount == 1)
                            {
                                if (i == 0)
                                {
                                    temp.Add(info.Options.Contains(FieldType.UINT) ? FieldType.UINT : FieldType.INT);
                                }
                                else
                                {
                                    temp.Add(FieldType.STRING);
                                }
                            }
                            else if (info.UniqueStrings == 1)
                            {
                                // very unlikely to have a column with the same string in every row if there is
                                temp.Add(info.Options.Contains(FieldType.UINT) ? FieldType.UINT : FieldType.INT);
                            }
                            else
                            {
                                temp.Add(FieldType.STRING);                         // case of 0 = "" and 1 = "" in stringtable
                            }
                        }
                        else
                        {
                            temp.Add(info.Options.Contains(FieldType.UINT) ? FieldType.UINT : FieldType.INT);                     // uint over int
                        }

                        // LANGREFSTRING check
                        if (temp[temp.Count - 1] == FieldType.STRING)
                        {
                            if (IsLangStringRef(fieldInfo, i + 1, build, out int offset))
                            {
                                temp[temp.Count - 1] = FieldType.LANGSTRINGREF;
                                i += offset;
                            }
                        }
                    }

                    return(new DBEntry()
                    {
                        Name = Path.GetFileName(dbFile).ToUpper(),
                        Builds = new List <int>()
                        {
                            build
                        },
                        Fields = temp.Select(x => new DBField()
                        {
                            Name = "", Type = x.ToString().ToUpper()
                        }).ToList()
                    });
                }
        }
Esempio n. 5
0
        public static bool IsKnown(DBHeader header, out DBEntry entry)
        {
            entry = null;

            var def = Program.KnownDefinitions.Tables.FirstOrDefault(x => x.Build == header.BuildNumber && x.Name.ToUpper() == Path.GetFileNameWithoutExtension(header.FileName));

            if (def != null)
            {
                entry = new DBEntry()
                {
                    Name   = header.FileName,
                    Builds = new List <int>()
                    {
                        header.BuildNumber
                    },
                    Fields = new List <DBField>()
                };

                foreach (var field in def.Fields)
                {
                    if (field.AutoGenerate)
                    {
                        continue;
                    }
                    if (string.IsNullOrWhiteSpace(field.Name))
                    {
                        continue;
                    }

                    for (int i = 0; i < field.ArraySize; i++)
                    {
                        DBField fieldEntry = new DBField
                        {
                            Name = (field.ArraySize <= 1 ? field.Name : field.Name + (i + 1)).ToUpper()
                        };

                        switch (field.Type.Trim().ToLower().TrimStart('u'))
                        {
                        case "loc":
                            fieldEntry.Type = "LANGSTRINGREF";
                            break;

                        case "short":
                            fieldEntry.Type = "USHORT";
                            break;

                        case "int":
                        case "float":
                        case "string":
                        case "byte":
                        case "long":
                            fieldEntry.Type = field.Type.ToUpper();
                            break;
                        }

                        entry.Fields.Add(fieldEntry);
                    }
                }

                return(entry.Fields.Count == header.FieldCount);
            }

            return(false);
        }