Beispiel #1
0
        public WDC1Reader(Stream stream)
        {
            using (var reader = new BinaryReader(stream, Encoding.UTF8))
            {
                if (reader.BaseStream.Length < HeaderSize)
                {
                    throw new InvalidDataException(String.Format("WDC1 file is corrupted!"));
                }

                uint magic = reader.ReadUInt32();

                if (magic != WDC1FmtSig)
                {
                    throw new InvalidDataException(String.Format("WDC1 file is corrupted!"));
                }

                RecordsCount    = reader.ReadInt32();
                FieldsCount     = reader.ReadInt32();
                RecordSize      = reader.ReadInt32();
                StringTableSize = reader.ReadInt32();

                TableHash  = reader.ReadUInt32();
                LayoutHash = reader.ReadUInt32();
                MinIndex   = reader.ReadInt32();
                MaxIndex   = reader.ReadInt32();
                int locale        = reader.ReadInt32();
                int copyTableSize = reader.ReadInt32();
                int flags         = reader.ReadUInt16();
                IdFieldIndex = reader.ReadUInt16();

                int totalFieldsCount   = reader.ReadInt32();
                int packedDataOffset   = reader.ReadInt32(); // Offset within the field where packed data starts
                int lookupColumnCount  = reader.ReadInt32(); // count of lookup columns
                int sparseTableOffset  = reader.ReadInt32(); // absolute value, {uint offset, ushort size}[MaxId - MinId + 1]
                int indexDataSize      = reader.ReadInt32(); // int indexData[IndexDataSize / 4]
                int columnMetaDataSize = reader.ReadInt32(); // 24 * NumFields bytes, describes column bit packing, {ushort recordOffset, ushort size, uint additionalDataSize, uint compressionType, uint packedDataOffset or commonvalue, uint cellSize, uint cardinality}[NumFields], sizeof(DBC2CommonValue) == 8
                int commonDataSize     = reader.ReadInt32();
                int palletDataSize     = reader.ReadInt32(); // in bytes, sizeof(DBC2PalletValue) == 4
                int referenceDataSize  = reader.ReadInt32(); // uint NumRecords, uint minId, uint maxId, {uint id, uint index}[NumRecords], questionable usefulness...

                // field meta data
                m_meta = reader.ReadArray <FieldMetaData>(FieldsCount);

                byte[] recordsData;
                Dictionary <long, string> stringsTable  = null;
                SparseEntry[]             sparseEntries = null;

                if ((flags & 0x1) == 0)
                {
                    // records data
                    recordsData = reader.ReadBytes(RecordsCount * RecordSize);

                    Array.Resize(ref recordsData, recordsData.Length + 8); // pad with extra zeros so we don't crash when reading

                    // string data
                    stringsTable = new Dictionary <long, string>();

                    for (int i = 0; i < StringTableSize;)
                    {
                        long oldPos = reader.BaseStream.Position;

                        stringsTable[i] = CStringExtensions.ReadCString(reader);

                        i += (int)(reader.BaseStream.Position - oldPos);
                    }
                }
                else
                {
                    // sparse data with inlined strings
                    recordsData = reader.ReadBytes(sparseTableOffset - HeaderSize - Marshal.SizeOf <FieldMetaData>() * FieldsCount);

                    if (reader.BaseStream.Position != sparseTableOffset)
                    {
                        throw new Exception("r.BaseStream.Position != sparseTableOffset");
                    }

                    sparseEntries = reader.ReadArray <SparseEntry>(MaxIndex - MinIndex + 1);

                    if (sparseTableOffset != 0)
                    {
                        throw new Exception("Sparse Table NYI!");
                    }
                    else
                    {
                        throw new Exception("Sparse Table with zero offset?");
                    }
                }

                // index data
                int[] indexData = reader.ReadArray <int>(indexDataSize / 4);

                // duplicate rows data
                Dictionary <int, int> copyData = new Dictionary <int, int>();

                for (int i = 0; i < copyTableSize / 8; i++)
                {
                    copyData[reader.ReadInt32()] = reader.ReadInt32();
                }

                // column meta data
                m_columnMeta = reader.ReadArray <ColumnMetaData>(FieldsCount);

                // pallet data
                m_palletData = new Value32[m_columnMeta.Length][];

                for (int i = 0; i < m_columnMeta.Length; i++)
                {
                    if (m_columnMeta[i].CompressionType == CompressionType.Pallet || m_columnMeta[i].CompressionType == CompressionType.PalletArray)
                    {
                        m_palletData[i] = reader.ReadArray <Value32>((int)m_columnMeta[i].AdditionalDataSize / 4);
                    }
                }

                // common data
                m_commonData = new Dictionary <int, Value32> [m_columnMeta.Length];

                for (int i = 0; i < m_columnMeta.Length; i++)
                {
                    if (m_columnMeta[i].CompressionType == CompressionType.Common)
                    {
                        Dictionary <int, Value32> commonValues = new Dictionary <int, Value32>();
                        m_commonData[i] = commonValues;

                        for (int j = 0; j < m_columnMeta[i].AdditionalDataSize / 8; j++)
                        {
                            commonValues[reader.ReadInt32()] = reader.Read <Value32>();
                        }
                    }
                }

                // reference data
                ReferenceData refData = null;

                if (referenceDataSize > 0)
                {
                    refData = new ReferenceData
                    {
                        NumRecords = reader.ReadInt32(),
                        MinId      = reader.ReadInt32(),
                        MaxId      = reader.ReadInt32()
                    };

                    ReferenceEntry[] entries = reader.ReadArray <ReferenceEntry>(refData.NumRecords);
                    refData.Entries = entries.ToDictionary(e => e.Index, e => e.Id);
                }
                else
                {
                    refData = new ReferenceData
                    {
                        Entries = new Dictionary <int, int>()
                    };
                }

                BitReader bitReader = new BitReader(recordsData);

                for (int i = 0; i < RecordsCount; ++i)
                {
                    bitReader.Position = 0;
                    bitReader.Offset   = i * RecordSize;

                    bool hasRef = refData.Entries.TryGetValue(i, out int refId);

                    WDC1Row rec = new WDC1Row(this, bitReader, indexDataSize != 0 ? indexData[i] : -1, hasRef ? refId : -1, stringsTable);

                    if (indexDataSize != 0)
                    {
                        _Records.Add(indexData[i], rec);
                    }
                    else
                    {
                        _Records.Add(rec.GetId(), rec);
                    }

                    if (i % 1000 == 0)
                    {
                        Console.Write("\r{0} records read", i);
                    }
                }

                foreach (var copyRow in copyData)
                {
                    WDC1Row rec = (WDC1Row)_Records[copyRow.Value].Clone();
                    rec.SetId(copyRow.Key);
                    _Records.Add(copyRow.Key, rec);
                }
            }
        }