Exemple #1
0
        private DBHeader ExtractHeader(BinaryReader dbReader)
        {
            DBHeader header    = null;
            string   signature = dbReader.ReadString(4);

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

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

            case "WDB6":
                header = new WDB6();
                break;

            case "WDC1":
                header = new WDC1();
                break;

            default:
                return(null);
            }

            header?.ReadHeader(ref dbReader, signature);
            return(header);
        }
Exemple #2
0
        private DBHeader ExtractHeader(BinaryReader dbReader)
        {
            DBHeader header    = null;
            string   signature = dbReader.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":
            case "WCH2":
                header = new WDB2();
                break;

            case "WDB5":
                header = new WDB5();
                break;

            case "WCH5":
                header = new WCH5(FileName);
                break;

            case "WCH7":
                header = new WCH7(FileName);
                break;

            case "WCH8":
                header = new WCH8(FileName);
                break;

            case "WMOB":
            case "WGOB":
            case "WQST":
            case "WIDB":
            case "WNDB":
            case "WITX":
            case "WNPC":
            case "WPTX":
            case "WRDN":
                header = new WDB();
                break;
            }

            header?.ReadHeader(ref dbReader, signature);
            return(header);
        }
Exemple #3
0
        private int GetArraySize(ref WDB5 wdb5, int index)
        {
            int bytecount = wdb5.FieldStructure[index].ByteCount;
            int count     = wdb5.FieldStructure[index].Count;
            int result    = 1;

            if (index == wdb5.FieldStructure.Length - 1)
            {
                result = ((int)wdb5.RecordSize - count) / bytecount; //Get difference to end of the record and divide by bits
            }
            else
            {
                result = (wdb5.FieldStructure[index + 1].Count - count) / bytecount; //Get difference and divide by bits
            }
            return(result < 1 ? 1 : result);
        }
Exemple #4
0
        public DBEntry Read(MemoryStream stream, string dbFile)
        {
            FileName        = dbFile;
            stream.Position = 0;

            using (var dbReader = new BinaryReader(stream, Encoding.UTF8))
            {
                DBHeader header = ExtractHeader(dbReader);
                long     pos    = dbReader.BaseStream.Position;

                //No header - must be invalid
                if (!(header?.IsValidFile ?? false))
                {
                    throw new Exception("Unknown file type.");
                }

                if (header.RecordCount == 0 || header.RecordSize == 0)
                {
                    throw new Exception("File contains no records.");
                }

                DBEntry entry = new DBEntry(header, dbFile);
                if (entry.TableStructure == null)
                {
                    throw new Exception("Definition missing.");
                }

                if (header.IsTypeOf <WDBC>() || header.IsTypeOf <WDB2>())
                {
                    long stringTableStart = dbReader.BaseStream.Position += header.RecordCount * header.RecordSize;
                    Dictionary <int, string> StringTable = new StringTable().Read(dbReader, stringTableStart); //Get stringtable
                    dbReader.Scrub(pos);

                    ReadIntoTable(ref entry, dbReader, StringTable); //Read data

                    stream.Dispose();
                    return(entry);
                }
                else if (header.IsTypeOf <WDB5>() || header.IsTypeOf <WCH5>())
                {
                    WDB5 wdb5 = (header as WDB5);
                    WCH5 wch5 = (header as WCH5);
                    WCH7 wch7 = (header as WCH7);

                    int CopyTableSize = wdb5?.CopyTableSize ?? 0; //Only WDB5 has a copy table

                    //StringTable - only if applicable
                    long copyTablePos     = dbReader.BaseStream.Length - CopyTableSize;
                    long indexTablePos    = copyTablePos - (header.HasIndexTable ? header.RecordCount * 4 : 0);
                    long wch7TablePos     = indexTablePos - (wch7?.UnknownWCH7 * 4 ?? 0);
                    long stringTableStart = wch7TablePos - header.StringBlockSize;
                    Dictionary <int, string> StringTable = new Dictionary <int, string>();
                    if (!header.HasOffsetTable) //Stringtable is only present if there isn't an offset map
                    {
                        dbReader.Scrub(stringTableStart);
                        StringTable = new StringTable().Read(dbReader, stringTableStart, stringTableStart + header.StringBlockSize);
                        dbReader.Scrub(pos);
                    }

                    //Read the data
                    using (MemoryStream ms = new MemoryStream(header.ReadData(dbReader, pos)))
                        using (BinaryReader dataReader = new BinaryReader(ms, Encoding.UTF8))
                        {
                            ReadIntoTable(ref entry, dataReader, StringTable);
                        }

                    //Cleanup
                    if (header.IsTypeOf <WDB5>())
                    {
                        wdb5.OffsetLengths = null;
                    }
                    else if (header.IsTypeOf <WCH5>())
                    {
                        wch5.OffsetLengths = null;
                    }
                    else if (header.IsTypeOf <WCH7>())
                    {
                        wch7.OffsetLengths = null;
                    }

                    stream.Dispose();
                    return(entry);
                }
                else if (header.IsTypeOf <WDB>())
                {
                    WDB wdb = (WDB)header;
                    wdb.ReadExtendedHeader(dbReader, entry.Build);

                    using (MemoryStream ms = new MemoryStream(wdb.ReadData(dbReader)))
                        using (BinaryReader dataReader = new BinaryReader(ms, Encoding.UTF8))
                        {
                            ReadIntoTable(ref entry, dataReader, new Dictionary <int, string>());
                        }

                    stream.Dispose();
                    return(entry);
                }
                else
                {
                    stream.Dispose();
                    throw new Exception($"Invalid filetype.");
                }
            }
        }
Exemple #5
0
        private void Parse(MemoryStream stream, string file)
        {
            stream.Position = 0;

            using (var dbReader = new BinaryReader(stream, Encoding.UTF8))
            {
                string signature = dbReader.ReadString(4);
                if (signature != "WDB5")
                {
                    return;
                }

                WDB5 wdb5 = new WDB5();
                wdb5.ReadHeader(dbReader, signature);

                long pos              = dbReader.BaseStream.Position;
                long copyTablePos     = dbReader.BaseStream.Length - wdb5.CopyTableSize;
                long indexTablePos    = copyTablePos - (wdb5.HasIndexTable ? wdb5.RecordCount * 4 : 0);
                long stringTableStart = indexTablePos - wdb5.StringBlockSize;
                Dictionary <int, string> StringTable = new Dictionary <int, string>();
                if (!wdb5.HasOffsetTable)
                {
                    dbReader.Scrub(stringTableStart);
                    StringTable = new StringTable().Read(dbReader, stringTableStart, stringTableStart + wdb5.StringBlockSize);
                    dbReader.Scrub(pos);
                }

                Dictionary <int, FieldType> FieldTypes = new Dictionary <int, FieldType>()
                {
                    { 4, FieldType.UNKNOWN },
                    { 3, FieldType.INT },
                    { 2, FieldType.USHORT },
                    { 1, FieldType.BYTE },
                };

                //Calculate known field types
                List <FieldInfo> fields = new List <FieldInfo>();
                for (int i = 0; i < wdb5.FieldStructure.Length; i++)
                {
                    int bytecount = wdb5.FieldStructure[i].ByteCount;

                    FieldInfo fi = new FieldInfo();
                    fi.ArraySize = GetArraySize(ref wdb5, i);

                    if (i == wdb5.IdIndex)
                    {
                        fi.Type = FieldType.INT;
                    }
                    else
                    {
                        fi.Type = FieldTypes[bytecount];
                    }

                    fields.Add(fi);
                }

                var  copytabledata   = wdb5.ReadOffsetData(dbReader, pos).Values.ToList();
                bool stringtableused = StringTable.Values.Any(x => !string.IsNullOrWhiteSpace(x)) && !wdb5.HasOffsetTable;

                //Attempt to figure out unknown types
                for (int i = 0; i < fields.Count; i++)
                {
                    if (fields[i].Type != FieldType.UNKNOWN)
                    {
                        continue;
                    }

                    List <FieldType> options = new List <FieldType>()
                    {
                        FieldType.INT, FieldType.UINT, FieldType.FLOAT, FieldType.STRING
                    };
                    if (!stringtableused)
                    {
                        options.Remove(FieldType.STRING); //Stringtable not used
                    }
                    List <int>    intvals    = new List <int>();
                    List <string> stringvals = new List <string>();
                    List <float>  floatvals  = new List <float>();

                    for (int d = 0; d < copytabledata.Count; d++)
                    {
                        byte[] cdata = copytabledata[d];

                        int start = wdb5.FieldStructure[i].Count;
                        if (wdb5.HasOffsetTable)
                        {
                            start = 0;
                            for (int x = 0; x < i; x++)
                            {
                                if (fields[x].Type != FieldType.STRING)
                                {
                                    int bytecount = wdb5.FieldStructure[x].ByteCount;
                                    start += bytecount * fields[x].ArraySize;
                                }
                                else
                                {
                                    start += cdata.Skip(start).TakeWhile(b => b != 0).Count() + 1;
                                }
                            }
                        }

                        byte[] data = cdata.Skip(start).Take(4).ToArray();
                        if (!wdb5.HasOffsetTable && data.All(x => x == 0))
                        {
                            continue;                                                //Ignore 0 byte columns as they could be anything
                        }
                        //Get int value
                        int intval = BitConverter.ToInt32(data, 0);
                        intvals.Add(intval);

                        //String check
                        if (options.Contains(FieldType.STRING))
                        {
                            if (wdb5.HasOffsetTable)
                            {
                                //Check for control and nonunicode chars
                                string stringval = Encoding.UTF8.GetString(cdata.Skip(start).TakeWhile(x => x != 0).ToArray());
                                if (stringval.Length >= 1 && stringval.Any(x => char.IsControl(x) || x == 0xFFFD))
                                {
                                    options.Remove(FieldType.STRING);
                                }
                                else
                                {
                                    stringvals.Add(stringval);
                                }
                            }
                            else
                            {
                                //Check it is in the stringtable and more than -1
                                if (intval < 0 || !StringTable.ContainsKey(intval))
                                {
                                    options.Remove(FieldType.STRING);
                                }
                            }
                        }

                        //Float check
                        if (options.Contains(FieldType.FLOAT))
                        {
                            //Basic float checks
                            float single = BitConverter.ToSingle(data, 0);
                            if (!float.IsInfinity(single) && !float.IsNaN(single) && (single >= 9.99999997475243E-07 && single <= 100000.0))
                            {
                                floatvals.Add(single);
                            }
                            else if (single != 0) //Ignore 0s
                            {
                                options.Remove(FieldType.FLOAT);
                            }
                        }

                        //UInt check
                        if (options.Contains(FieldType.UINT))
                        {
                            if (intval < 0) //If less than 0 must be signed
                            {
                                options.Remove(FieldType.UINT);
                            }
                        }
                    }

                    var uniquestr   = new HashSet <string>(stringvals);
                    var uniqueint   = new HashSet <int>(intvals);
                    var uniquefloat = new HashSet <float>(floatvals);

                    if (uniqueint.Count == 1 && uniqueint.First() == 0) //All 0s
                    {
                        fields[i].Type = FieldType.INT;
                    }
                    else if (!wdb5.HasOffsetTable && options.Contains(FieldType.STRING)) //Int if only 1 Int else String
                    {
                        fields[i].Type = (uniqueint.Count == 1 ? FieldType.INT : FieldType.STRING);
                    }
                    else if (wdb5.HasOffsetTable && options.Contains(FieldType.STRING) && uniquestr.Count > 1) //More than 1 string
                    {
                        fields[i].Type = FieldType.STRING;
                    }
                    else if (wdb5.HasOffsetTable && options.Contains(FieldType.STRING) && uniquefloat.Count <= 1) //1 or less float and string
                    {
                        fields[i].Type = FieldType.STRING;
                    }
                    else if (options.Contains(FieldType.FLOAT) && floatvals.Count > 0) //Floats count more than 1
                    {
                        fields[i].Type = FieldType.FLOAT;
                    }
                    else if (options.Contains(FieldType.UINT)) //Uint over Int
                    {
                        fields[i].Type = FieldType.UINT;
                    }
                    else
                    {
                        fields[i].Type = FieldType.INT;
                    }
                }

                Table table = new Table();
                table.Name   = Path.GetFileNameWithoutExtension(file);
                table.Fields = new List <Field>();
                string format = $"X{wdb5.FieldStructure.Max(x => x.Count).ToString().Length}"; //X2, X3 etc

                for (int i = 0; i < fields.Count; i++)
                {
                    Field field = new Field();
                    field.Name      = (i == wdb5.IdIndex ? "m_ID" : $"field{wdb5.FieldStructure[i].Count.ToString(format)}");
                    field.IsIndex   = (i == wdb5.IdIndex);
                    field.ArraySize = fields[i].ArraySize;
                    field.Type      = fields[i].Type.ToString().ToLower();
                    table.Fields.Add(field);
                }

                tables.Add(table);
                Database.ForceGC();
            }
        }
Exemple #6
0
        private static DBHeader ReadHeader(BinaryReader dbReader, DBHeader counterpart = null)
        {
            DBHeader header    = null;
            string   signature = dbReader.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":
            case "WCH2":
                header = new WDB2();
                break;

            case "WDB5":
                header = new WDB5();
                break;

            case "WDB6":
                header = new WDB6();
                break;

            case "WCH5":
                header = new WCH5(counterpart);
                break;

            case "WCH7":
                header = new WCH7(counterpart);
                break;

            case "WCH8":
                header = new WCH8(counterpart);
                break;

            case "WMOB":
            case "WGOB":
            case "WQST":
            case "WIDB":
            case "WNDB":
            case "WITX":
            case "WNPC":
            case "WPTX":
            case "WRDN":
                header = new WDB();
                break;

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

            header?.ReadHeader(ref dbReader, signature);
            return(header);
        }