예제 #1
0
파일: DBEntry.cs 프로젝트: lyosky/WDBXLib
        /// <summary>
        /// Generates a Bit map for all columns as the Blizzard one combines array columns
        /// </summary>
        /// <returns></returns>
        public FieldStructureEntry[] GetBits()
        {
            FieldStructureEntry[] bits = new FieldStructureEntry[TableStructure.Length];
            if (!Header.IsTypeOf <WDB5>())
            {
                return(bits);
            }

            int c = 0, f = 0;

            for (int i = 0; i < TableStructure.Length; i++)
            {
                var dbField = TableStructure[i].GetCustomAttribute <DBFieldAttribute>();
                if (dbField != null && dbField.Bits > -1)
                {
                    bits[c] = new FieldStructureEntry(dbField.Bits, 0, (byte)Convert.ChangeType((dbField.DefaultValue ?? 0xFF), TypeCode.Byte));
                }
                else
                {
                    FieldStructureEntry field = Header.FieldStructure[f];
                    bits[c] = new FieldStructureEntry(field?.Bits ?? 0, 0, field?.CommonDataType ?? 0xFF);
                    f++;
                }

                c++;
            }

            return(bits);
        }
예제 #2
0
        private void Parse(MemoryStream stream, string file)
        {
            ParseWDC1(stream, file);
            return;

#pragma warning disable CS0162 // Unreachable code detected
            stream.Position = 0;

            using (var dbReader = new BinaryReader(stream, Encoding.UTF8))
            {
                DBHeader header = ExtractHeader(dbReader);
                if (header == null)
                {
                    return;
                }

                long pos = dbReader.BaseStream.Position;

                int  CopyTableSize       = header.CopyTableSize;          //Only WDB5 has a copy table
                uint CommonDataTableSize = header.CommonDataTableSize;

                //StringTable - only if applicable
                long copyTablePos     = dbReader.BaseStream.Length - CommonDataTableSize - CopyTableSize;
                long indexTablePos    = copyTablePos - (header.HasIndexTable ? header.RecordCount * 4 : 0);
                long wch7TablePos     = indexTablePos - (header.UnknownWCH7 * 4);
                long stringTableStart = wch7TablePos - header.StringBlockSize;

                Dictionary <int, string> StringTable = new Dictionary <int, string>();
                if (!header.HasOffsetTable)
                {
                    dbReader.Scrub(stringTableStart);
                    StringTable = new StringTable().Read(dbReader, stringTableStart, stringTableStart + header.StringBlockSize);
                    dbReader.Scrub(pos);
                }

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

                //Read data
                List <byte[]> copytabledata = new List <byte[]>();
                if (header.IsTypeOf <WDB6>())
                {
                    copytabledata = (header as WDB6).ReadOffsetData(dbReader, pos).Values.ToList();
                }
                else
                {
                    copytabledata = (header as WDB5).ReadOffsetData(dbReader, pos).Values.ToList();
                }

                //String table
                bool stringtableused = StringTable.Values.Any(x => !string.IsNullOrWhiteSpace(x)) && !header.HasOffsetTable;

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

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

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

                    //WDB6 Common Data check
                    if (header.FieldStructure[i].CommonDataColumn)
                    {
                        switch (header.FieldStructure[i].CommonDataType)
                        {
                        case 0:
                            fi.Type = FieldType.STRING;
                            break;

                        case 1:
                            fi.Type = FieldType.USHORT;
                            break;

                        case 2:
                            fi.Type = FieldType.BYTE;
                            break;

                        case 3:
                            fi.Type = FieldType.FLOAT;
                            break;

                        case 4:
                            fi.Type = FieldType.INT;
                            break;
                        }
                    }

                    fields.Add(fi);
                }

                //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 = header.FieldStructure[i].Offset;
                        if (header.HasOffsetTable)
                        {
                            start = 0;
                            for (int x = 0; x < i; x++)
                            {
                                if (fields[x].Type != FieldType.STRING)
                                {
                                    int bytecount = header.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 (!header.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 (header.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) && 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 (!header.HasOffsetTable && options.Contains(FieldType.STRING))                     //Int if only 1 Int else String
                    {
                        fields[i].Type = (uniqueint.Count == 1 ? FieldType.INT : FieldType.STRING);
                    }
                    else if (header.HasOffsetTable && options.Contains(FieldType.STRING) && uniquestr.Count > 1)                     //More than 1 string
                    {
                        fields[i].Type = FieldType.STRING;
                    }
                    else if (header.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{header.FieldStructure.Max(x => x.Offset).ToString().Length}";                 //X2, X3 etc

                for (int i = 0; i < fields.Count; i++)
                {
                    Field field = new Field();
                    field.Name      = (i == header.IdIndex ? "ID" : $"field{header.FieldStructure[i].Offset.ToString(format)}");
                    field.IsIndex   = (i == header.IdIndex);
                    field.ArraySize = (field.IsIndex ? 1 : fields[i].ArraySize);
                    field.Type      = fields[i].Type.ToString().ToLower();
                    table.Fields.Add(field);
                    Console.WriteLine($"Name: {field.Name} | Array: {field.ArraySize} | Type: {field.Type}");
                }

                tables.Add(table);
                Database.ForceGC();
            }
#pragma warning restore CS0162 // Unreachable code detected
        }