TrinityCore
Loading...
Searching...
No Matches
DB2FileLoader.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "DB2FileLoader.h"
19#include "ByteConverter.h"
20#include "DB2Meta.h"
21#include "Errors.h"
22#include "StringFormat.h"
23#include <fmt/ranges.h>
24#include <limits>
25#include <memory>
26#include <system_error>
27#include <unordered_map>
28#include <utility>
29#include <vector>
30#include <cstring>
31
41
42#pragma pack(push, 1)
43
49
55
84
90
95
102
108
109#pragma pack(pop)
110
112{
113 std::vector<DB2IndexEntry> Entries;
114};
115
116static bool IsKnownTactId(uint64 tactId)
117{
118 return tactId == 0 || tactId == DUMMY_KNOWN_TACT_ID;
119}
120
122{
123 uint32 stringFields = 0;
124 for (std::size_t i = 0; i < FieldCount; ++i)
125 if (Fields[i].Type == FT_STRING || (Fields[i].Type == FT_STRING_NOT_LOCALIZED && !localizedOnly))
126 ++stringFields;
127
128 return stringFields;
129}
130
131std::pair<int32, int32> DB2FileLoadInfo::GetFieldIndexByName(char const* fieldName) const
132{
133 std::size_t ourIndex = Meta->HasIndexFieldInData() ? 0 : 1;
134 for (uint32 i = 0; i < Meta->FieldCount; ++i)
135 {
136 for (uint8 arr = 0; arr < Meta->Fields[i].ArraySize; ++arr)
137 {
138 if (!strcmp(Fields[ourIndex].Name, fieldName))
139 return std::make_pair(int32(i), int32(arr));
140
141 ++ourIndex;
142 }
143 }
144
145 return std::make_pair(-1, -1);
146}
147
149{
150 ASSERT(metaIndex < Meta->FieldCount);
151 int32 ourIndex = Meta->HasIndexFieldInData() ? 0 : 1;
152 for (uint32 i = 0; i < metaIndex; ++i)
153 ourIndex += Meta->Fields[i].ArraySize;
154
155 return ourIndex;
156}
157
160
162{
163public:
164 DB2FileLoaderImpl() = default;
165 DB2FileLoaderImpl(DB2FileLoaderImpl const& other) = delete;
166 DB2FileLoaderImpl(DB2FileLoaderImpl&& other) noexcept = delete;
168 DB2FileLoaderImpl& operator=(DB2FileLoaderImpl&& other) noexcept = delete;
169 virtual ~DB2FileLoaderImpl() = default;
170 virtual void LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
171 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
172 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues) = 0;
173 virtual void SkipEncryptedSection(uint32 section) = 0;
174 virtual bool LoadTableData(DB2FileSource* source, uint32 section) = 0;
175 virtual bool LoadCatalogData(DB2FileSource* source, uint32 section) = 0;
176 virtual void SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes) = 0;
177 virtual char* AutoProduceData(uint32& indexTableSize, char**& indexTable) = 0;
178 virtual char* AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale) = 0;
179 virtual void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) = 0;
180 virtual DB2Record GetRecord(uint32 recordNumber) const = 0;
181 virtual DB2RecordCopy GetRecordCopy(uint32 copyNumber) const = 0;
182 virtual uint32 GetRecordCount() const = 0;
183 virtual uint32 GetRecordCopyCount() const = 0;
184 virtual uint32 GetMinId() const = 0;
185 virtual uint32 GetMaxId() const = 0;
186 virtual DB2FileLoadInfo const* GetLoadInfo() const = 0;
187 virtual DB2SectionHeader& GetSection(uint32 section) const = 0;
188
189private:
190 friend class DB2Record;
191 virtual unsigned char const* GetRawRecordData(uint32 recordNumber, uint32 const* section) const = 0;
192 virtual uint32 RecordGetId(uint8 const* record, uint32 recordIndex) const = 0;
193 virtual uint8 RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
194 virtual uint16 RecordGetUInt16(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
195 virtual uint32 RecordGetUInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
196 virtual int32 RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
197 virtual uint64 RecordGetUInt64(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
198 virtual float RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
199 virtual char const* RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const = 0;
200 virtual std::size_t* RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const = 0;
201 virtual std::size_t* RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const = 0;
202 virtual void RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const = 0;
203};
204
206{
207public:
208 DB2FileLoaderRegularImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header);
214
215 void LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
216 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
217 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues) override;
218 void SkipEncryptedSection(uint32 /*section*/) override { }
219 bool LoadTableData(DB2FileSource* source, uint32 section) override;
220 bool LoadCatalogData(DB2FileSource* /*source*/, uint32 /*section*/) override { return true; }
221 void SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes) override;
222 char* AutoProduceData(uint32& indexTableSize, char**& indexTable) override;
223 char* AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale) override;
224 void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) override;
225 DB2Record GetRecord(uint32 recordNumber) const override;
226 DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override;
227 uint32 GetRecordCount() const override;
228 uint32 GetRecordCopyCount() const override;
229 uint32 GetMinId() const override;
230 uint32 GetMaxId() const override;
231 DB2FileLoadInfo const* GetLoadInfo() const override;
232 DB2SectionHeader& GetSection(uint32 section) const override;
233
234private:
235 void FillParentLookup(char* dataTable);
236 uint32 GetRecordSection(uint32 recordNumber) const;
237 unsigned char const* GetRawRecordData(uint32 recordNumber, uint32 const* section) const override;
238 uint32 RecordGetId(uint8 const* record, uint32 recordIndex) const override;
239 uint8 RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
240 uint16 RecordGetUInt16(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
241 uint32 RecordGetUInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
242 int32 RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
243 uint64 RecordGetUInt64(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
244 float RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
245 char const* RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
246 template<typename T>
247 T RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex) const;
248 uint64 RecordGetPackedValue(uint8 const* packedRecordData, uint32 bitWidth, uint32 bitOffset) const;
249 uint16 GetFieldOffset(uint32 field) const;
250 std::size_t* RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const override;
251 std::size_t* RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const override;
252 void RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const override;
253
254 char const* _fileName;
257 std::unique_ptr<uint8[]> _data;
259 std::unique_ptr<DB2SectionHeader[]> _sections;
260 std::unique_ptr<DB2ColumnMeta[]> _columnMeta;
261 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> _palletValues;
262 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> _palletArrayValues;
263 std::unique_ptr<std::unordered_map<uint32, uint32>[]> _commonValues;
264 std::vector<uint32> _idTable;
265 std::vector<DB2RecordCopy> _copyTable;
266 std::vector<std::vector<DB2IndexData>> _parentIndexes;
267};
268
270{
271public:
272 DB2FileLoaderSparseImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header, DB2FileSource* source);
278
279 void LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
280 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
281 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues) override;
282 void SkipEncryptedSection(uint32 section) override;
283 bool LoadTableData(DB2FileSource* /*source*/, uint32 /*section*/) override { return true; }
284 bool LoadCatalogData(DB2FileSource* source, uint32 section) override;
285 void SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes) override;
286 char* AutoProduceData(uint32& indexTableSize, char**& indexTable) override;
287 char* AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale) override;
288 void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) override;
289 DB2Record GetRecord(uint32 recordNumber) const override;
290 DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override;
291 uint32 GetRecordCount() const override;
292 uint32 GetRecordCopyCount() const override;
293 uint32 GetMinId() const override;
294 uint32 GetMaxId() const override;
295 DB2FileLoadInfo const* GetLoadInfo() const override;
296 DB2SectionHeader& GetSection(uint32 section) const override;
297
298private:
299 void FillParentLookup(char* dataTable);
300 uint32 GetRecordSection(uint32 recordNumber) const;
301 unsigned char const* GetRawRecordData(uint32 recordNumber, uint32 const* section) const override;
302 uint32 RecordGetId(uint8 const* record, uint32 recordIndex) const override;
303 uint8 RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
304 uint16 RecordGetUInt16(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
305 uint32 RecordGetUInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
306 int32 RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
307 uint64 RecordGetUInt64(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
308 float RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
309 char const* RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const override;
310 uint32 RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex, bool isSigned) const;
311 uint16 GetFieldOffset(uint32 field, uint32 arrayIndex) const;
312 uint16 GetFieldSize(uint32 field) const;
313 std::size_t* RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const override;
314 std::size_t* RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const override;
315 void RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const override;
316 void CalculateAndStoreFieldOffsets(uint8 const* rawRecord) const;
317
318 char const* _fileName;
322 std::size_t _totalRecordSize;
324 std::unique_ptr<uint8[]> _recordBuffer;
325 std::unique_ptr<DB2SectionHeader[]> _sections;
326 std::unique_ptr<DB2FieldEntry[]> _fields;
327 std::unique_ptr<std::size_t[]> _fieldAndArrayOffsets;
328 std::vector<uint32> _catalogIds;
329 std::vector<DB2CatalogEntry> _catalog;
330 std::vector<DB2RecordCopy> _copyTable;
331 std::vector<std::vector<DB2IndexData>> _parentIndexes;
332};
333
334DB2FileLoaderRegularImpl::DB2FileLoaderRegularImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header) :
335 _fileName(fileName),
336 _loadInfo(loadInfo),
337 _header(header),
338 _stringTable(nullptr)
339{
340}
341
342void DB2FileLoaderRegularImpl::LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> /*fields*/, std::unique_ptr<DB2ColumnMeta[]> columnMeta,
343 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues,
344 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues)
345{
346 _sections = std::move(sections);
347 _columnMeta = std::move(columnMeta);
348 _palletValues = std::move(palletValues);
349 _palletArrayValues = std::move(palletArrayValues);
350 _commonValues = std::move(commonValues);
351}
352
354{
355 if (!_data)
356 {
357 _data = std::make_unique<uint8[]>(_header->RecordSize * _header->RecordCount + _header->StringTableSize + 8);
359 }
360
361 uint32 sectionDataStart = 0;
362 uint32 sectionStringTableStart = 0;
363 for (uint32 i = 0; i < section; ++i)
364 {
365 sectionDataStart += _header->RecordSize * _sections[i].RecordCount;
366 sectionStringTableStart += _sections[i].StringTableSize;
367 }
368
369 if (_sections[section].RecordCount && !source->Read(&_data[sectionDataStart], _header->RecordSize * _sections[section].RecordCount))
370 return false;
371
372 if (_sections[section].StringTableSize && !source->Read(&_stringTable[sectionStringTableStart], _sections[section].StringTableSize))
373 return false;
374
375 return true;
376}
377
378void DB2FileLoaderRegularImpl::SetAdditionalData(std::vector<uint32> idTable, std::vector<DB2RecordCopy> copyTable, std::vector<std::vector<DB2IndexData>> parentIndexes)
379{
380 _idTable = std::move(idTable);
381 _copyTable = std::move(copyTable);
382 _parentIndexes = std::move(parentIndexes);
383}
384
386
387static char const* const EmptyDb2String = "";
388
389char* DB2FileLoaderRegularImpl::AutoProduceData(uint32& indexTableSize, char**& indexTable)
390{
391 //get struct size and index pos
392 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
393
394 uint32 maxi = GetMaxId() + 1;
395
396 using index_entry_t = char*;
397
398 indexTableSize = maxi;
399 indexTable = new index_entry_t[maxi];
400 memset(indexTable, 0, maxi * sizeof(index_entry_t));
401
402 char* dataTable = new char[(_header->RecordCount + _copyTable.size()) * recordsize];
403
404 uint32 offset = 0;
405 uint32 recordIndex = 0;
406
407 for (uint32 section = 0; section < _header->SectionCount; ++section)
408 {
409 DB2SectionHeader const& sectionHeader = GetSection(section);
410 if (!IsKnownTactId(sectionHeader.TactId))
411 {
412 offset += recordsize * sectionHeader.RecordCount;
413 recordIndex += sectionHeader.RecordCount;
414 continue;
415 }
416
417 for (uint32 sr = 0; sr < sectionHeader.RecordCount; ++sr, ++recordIndex)
418 {
419 unsigned char const* rawRecord = GetRawRecordData(recordIndex, &section);
420 if (!rawRecord)
421 continue;
422
423 uint32 indexVal = RecordGetId(rawRecord, recordIndex);
424
425 indexTable[indexVal] = &dataTable[offset];
426
427 uint32 fieldIndex = 0;
429 {
430 *reinterpret_cast<uint32*>(&dataTable[offset]) = indexVal;
431 offset += 4;
432 ++fieldIndex;
433 }
434
435 for (uint32 x = 0; x < _header->FieldCount; ++x)
436 {
437 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
438 {
439 switch (_loadInfo->Fields[fieldIndex].Type)
440 {
441 case FT_FLOAT:
442 *reinterpret_cast<float*>(&dataTable[offset]) = RecordGetFloat(rawRecord, x, z);
443 offset += 4;
444 break;
445 case FT_INT:
446 *reinterpret_cast<uint32*>(&dataTable[offset]) = RecordGetVarInt<uint32>(rawRecord, x, z);
447 offset += 4;
448 break;
449 case FT_BYTE:
450 *reinterpret_cast<uint8*>(&dataTable[offset]) = RecordGetUInt8(rawRecord, x, z);
451 offset += 1;
452 break;
453 case FT_SHORT:
454 *reinterpret_cast<uint16*>(&dataTable[offset]) = RecordGetUInt16(rawRecord, x, z);
455 offset += 2;
456 break;
457 case FT_LONG:
458 *reinterpret_cast<uint64*>(&dataTable[offset]) = RecordGetUInt64(rawRecord, x, z);
459 offset += 8;
460 break;
461 case FT_STRING:
462 for (char const*& localeStr : reinterpret_cast<LocalizedString*>(&dataTable[offset])->Str)
463 localeStr = EmptyDb2String;
464
465 offset += sizeof(LocalizedString);
466 break;
468 *reinterpret_cast<char const**>(&dataTable[offset]) = EmptyDb2String;
469 offset += sizeof(char*);
470 break;
471 default:
472 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
473 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
474 break;
475 }
476 ++fieldIndex;
477 }
478 }
479
480 for (uint32 x = _header->FieldCount; x < _loadInfo->Meta->FieldCount; ++x)
481 {
482 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
483 {
484 switch (_loadInfo->Fields[fieldIndex].Type)
485 {
486 case FT_INT:
487 *reinterpret_cast<uint32*>(&dataTable[offset]) = 0;
488 offset += 4;
489 break;
490 case FT_BYTE:
491 *reinterpret_cast<uint8*>(&dataTable[offset]) = 0;
492 offset += 1;
493 break;
494 case FT_SHORT:
495 *reinterpret_cast<uint16*>(&dataTable[offset]) = 0;
496 offset += 2;
497 break;
498 default:
499 ABORT_MSG("Unknown format character '%c' found in %s meta for parent field %s",
500 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
501 break;
502 }
503 ++fieldIndex;
504 }
505 }
506 }
507 }
508
509 if (!_parentIndexes.empty())
510 FillParentLookup(dataTable);
511
512 return dataTable;
513}
514
515char* DB2FileLoaderRegularImpl::AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale)
516{
517 if (!(_header->Locale & (1 << locale)))
518 {
519 std::array<char const*, TOTAL_LOCALES> detectedLocales;
520 auto itr = detectedLocales.begin();
521 for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
522 if (_header->Locale & (1 << i))
523 *itr++ = localeNames[i];
524
525 throw DB2FileLoadException(Trinity::StringFormat("Attempted to load {} which has locales {} as {}. Check if you placed your localized db2 files in correct directory.",
526 _fileName, fmt::join(detectedLocales.begin(), itr, ", "), localeNames[locale]));
527 }
528
529 if (!_loadInfo->GetStringFieldCount(false))
530 return nullptr;
531
532 char* stringPool = new char[_header->StringTableSize];
533 memcpy(stringPool, _stringTable, _header->StringTableSize);
534
535 uint32 y = 0;
536
537 for (uint32 section = 0; section < _header->SectionCount; ++section)
538 {
539 DB2SectionHeader const& sectionHeader = GetSection(section);
540 if (!IsKnownTactId(sectionHeader.TactId))
541 {
542 y += sectionHeader.RecordCount;
543 continue;
544 }
545
546 for (uint32 sr = 0; sr < sectionHeader.RecordCount; ++sr, ++y)
547 {
548 unsigned char const* rawRecord = GetRawRecordData(y, &section);
549 if (!rawRecord)
550 continue;
551
552 uint32 indexVal = RecordGetId(rawRecord, y);
553 if (indexVal >= indexTableSize)
554 continue;
555
556 char* recordData = indexTable[indexVal];
557 if (!recordData)
558 continue;
559
560 uint32 offset = 0;
561 uint32 fieldIndex = 0;
563 {
564 offset += 4;
565 ++fieldIndex;
566 }
567
568 for (uint32 x = 0; x < _loadInfo->Meta->FieldCount; ++x)
569 {
570 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
571 {
572 switch (_loadInfo->Fields[fieldIndex].Type)
573 {
574 case FT_FLOAT:
575 case FT_INT:
576 offset += 4;
577 break;
578 case FT_BYTE:
579 offset += 1;
580 break;
581 case FT_SHORT:
582 offset += 2;
583 break;
584 case FT_LONG:
585 offset += 8;
586 break;
587 case FT_STRING:
588 if (char const* string = RecordGetString(rawRecord, x, z))
589 reinterpret_cast<LocalizedString*>(&recordData[offset])->Str[locale] = stringPool + (string - reinterpret_cast<char const*>(_stringTable));
590
591 offset += sizeof(LocalizedString);
592 break;
594 if (char const* string = RecordGetString(rawRecord, x, z))
595 *reinterpret_cast<char**>(&recordData[offset]) = stringPool + (string - reinterpret_cast<char const*>(_stringTable));
596
597 offset += sizeof(char*);
598 break;
599 default:
600 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
601 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
602 break;
603 }
604 ++fieldIndex;
605 }
606 }
607 }
608 }
609
610 return stringPool;
611}
612
613void DB2FileLoaderRegularImpl::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
614{
615 uint32 recordCopies = GetRecordCopyCount();
616 if (!recordCopies)
617 return;
618
619 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
620 uint32 offset = _header->RecordCount * recordsize;
622 for (uint32 c = 0; c < recordCopies; ++c)
623 {
625 if (copy.SourceRowId && copy.SourceRowId < records && copy.NewRowId < records && indexTable[copy.SourceRowId])
626 {
627 indexTable[copy.NewRowId] = &dataTable[offset];
628 memcpy(indexTable[copy.NewRowId], indexTable[copy.SourceRowId], recordsize);
629 *reinterpret_cast<uint32*>(&dataTable[offset + idFieldOffset]) = copy.NewRowId;
630 offset += recordsize;
631 }
632 }
633}
634
636{
637 int32 parentIdOffset = _loadInfo->Meta->GetParentIndexFieldOffset();
638 uint32 recordSize = _loadInfo->Meta->GetRecordSize();
639 uint32 recordIndexOffset = 0;
640 for (uint32 i = 0; i < _header->SectionCount; ++i)
641 {
642 DB2SectionHeader const& section = GetSection(i);
643 if (IsKnownTactId(section.TactId))
644 {
645 for (std::size_t j = 0; j < _parentIndexes[i][0].Entries.size(); ++j)
646 {
647 uint32 parentId = _parentIndexes[i][0].Entries[j].ParentId;
648 uint32 recordIndex = _parentIndexes[i][0].Entries[j].RecordIndex + recordIndexOffset;
649 char* recordData = &dataTable[recordIndex * recordSize];
650
652 {
653 case FT_SHORT:
654 {
656 {
657 // extra field at the end
658 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
659 }
660 else
661 {
662 // in data block, must fit
663 ASSERT(parentId <= std::numeric_limits<uint16>::max(), "ParentId value %u does not fit into uint16 field (%s in %s)",
665 *reinterpret_cast<uint16*>(&recordData[parentIdOffset]) = parentId;
666 }
667 break;
668 }
669 case FT_BYTE:
670 {
672 {
673 // extra field at the end
674 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
675 }
676 else
677 {
678 // in data block, must fit
679 ASSERT(parentId <= std::numeric_limits<uint8>::max(), "ParentId value %u does not fit into uint8 field (%s in %s)",
681 *reinterpret_cast<uint8*>(&recordData[parentIdOffset]) = parentId;
682 }
683 break;
684 }
685 case FT_INT:
686 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
687 break;
688 default:
689 ABORT_MSG("Unhandled parent id type '%c' found in %s", _loadInfo->Meta->Fields[_loadInfo->Meta->ParentIndexField].Type, _fileName);
690 break;
691 }
692 }
693 }
694 recordIndexOffset += section.RecordCount;
695 }
696}
697
699{
700 return DB2Record(*this, recordNumber, nullptr);
701}
702
704{
705 if (copyNumber >= GetRecordCopyCount())
706 return DB2RecordCopy{};
707
708 return _copyTable[copyNumber];
709}
710
715
720
722{
723 uint32 section = 0;
724 for (; section < _header->SectionCount; ++section)
725 {
726 DB2SectionHeader const& sectionHeader = GetSection(section);
727 if (recordNumber < sectionHeader.RecordCount)
728 break;
729
730 recordNumber -= sectionHeader.RecordCount;
731 }
732
733 return section;
734}
735
736unsigned char const* DB2FileLoaderRegularImpl::GetRawRecordData(uint32 recordNumber, uint32 const* section) const
737{
738 if (recordNumber >= _header->RecordCount)
739 return nullptr;
740
741 if (!IsKnownTactId(GetSection(section ? *section : GetRecordSection(recordNumber)).TactId))
742 return nullptr;
743
744 return &_data[recordNumber * _header->RecordSize];
745}
746
748{
750 {
751 uint32 indexField = _loadInfo->Meta->GetIndexField();
752 switch (_loadInfo->Meta->Fields[indexField].Type)
753 {
754 case FT_INT:
755 return RecordGetVarInt<uint32>(record, indexField, 0);
756 case FT_BYTE:
757 return RecordGetVarInt<uint8>(record, indexField, 0);
758 case FT_SHORT:
759 return RecordGetVarInt<uint16>(record, indexField, 0);
760 default:
761 ABORT_MSG("Unhandled ID type %u in %s", uint32(_loadInfo->Meta->Fields[indexField].Type), _fileName);
762 }
763 }
764
765 return _idTable[recordIndex];
766}
767
768uint8 DB2FileLoaderRegularImpl::RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const
769{
770 return RecordGetVarInt<uint8>(record, field, arrayIndex);
771}
772
774{
775 return RecordGetVarInt<uint16>(record, field, arrayIndex);
776}
777
779{
780 return RecordGetVarInt<uint32>(record, field, arrayIndex);
781}
782
783int32 DB2FileLoaderRegularImpl::RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const
784{
785 return RecordGetVarInt<int32>(record, field, arrayIndex);
786}
787
789{
790 return RecordGetVarInt<uint64>(record, field, arrayIndex);
791}
792
793float DB2FileLoaderRegularImpl::RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const
794{
795 return RecordGetVarInt<float>(record, field, arrayIndex);
796}
797
798char const* DB2FileLoaderRegularImpl::RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const
799{
800 uint32 fieldOffset = GetFieldOffset(field) + sizeof(uint32) * arrayIndex;
801 uint32 stringOffset = RecordGetVarInt<uint32>(record, field, arrayIndex);
802 ASSERT(stringOffset < _header->RecordSize * _header->RecordCount + _header->StringTableSize);
803 return stringOffset ? reinterpret_cast<char const*>(record + fieldOffset + stringOffset) : nullptr;
804}
805
806template<typename T>
807T DB2FileLoaderRegularImpl::RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex) const
808{
809 ASSERT(field < _header->FieldCount);
810 DB2ColumnCompression compressionType = _columnMeta ? _columnMeta[field].CompressionType : DB2ColumnCompression::None;
811 switch (compressionType)
812 {
814 {
815 T val = *reinterpret_cast<T const*>(record + GetFieldOffset(field) + sizeof(T) * arrayIndex);
816 EndianConvert(val);
817 return val;
818 }
820 {
821 ASSERT(arrayIndex == 0);
822 uint64 immediateValue = RecordGetPackedValue(record + GetFieldOffset(field),
823 _columnMeta[field].CompressionData.immediate.BitWidth, _columnMeta[field].CompressionData.immediate.BitOffset);
824 EndianConvert(immediateValue);
825 T value;
826 memcpy(&value, &immediateValue, std::min(sizeof(T), sizeof(immediateValue)));
827 return value;
828 }
830 {
831 uint32 id = RecordGetId(record, (record - _data.get()) / _header->RecordSize);
832 T value;
833 auto valueItr = _commonValues[field].find(id);
834 if (valueItr != _commonValues[field].end())
835 memcpy(&value, &valueItr->second, std::min(sizeof(T), sizeof(uint32)));
836 else
837 memcpy(&value, &_columnMeta[field].CompressionData.commonData.Value, std::min(sizeof(T), sizeof(uint32)));
838 return value;
839 }
841 {
842 ASSERT(arrayIndex == 0);
843 uint64 palletIndex = RecordGetPackedValue(record + GetFieldOffset(field),
844 _columnMeta[field].CompressionData.pallet.BitWidth, _columnMeta[field].CompressionData.pallet.BitOffset);
845 EndianConvert(palletIndex);
846 uint32 palletValue = _palletValues[field][palletIndex].Value;
847 EndianConvert(palletValue);
848 T value;
849 memcpy(&value, &palletValue, std::min(sizeof(T), sizeof(palletValue)));
850 return value;
851 }
853 {
854 uint64 palletIndex = RecordGetPackedValue(record + GetFieldOffset(field),
855 _columnMeta[field].CompressionData.pallet.BitWidth, _columnMeta[field].CompressionData.pallet.BitOffset);
856 EndianConvert(palletIndex);
857 uint32 palletValue = _palletArrayValues[field][palletIndex * _columnMeta[field].CompressionData.pallet.ArraySize + arrayIndex].Value;
858 EndianConvert(palletValue);
859 T value;
860 memcpy(&value, &palletValue, std::min(sizeof(T), sizeof(palletValue)));
861 return value;
862 }
864 {
865 ASSERT(arrayIndex == 0);
866 uint64 immediateValue = RecordGetPackedValue(record + GetFieldOffset(field),
867 _columnMeta[field].CompressionData.immediate.BitWidth, _columnMeta[field].CompressionData.immediate.BitOffset);
868 EndianConvert(immediateValue);
869 uint64 mask = UI64LIT(1) << (_columnMeta[field].CompressionData.immediate.BitWidth - 1);
870 immediateValue = (immediateValue ^ mask) - mask;
871 T value;
872 memcpy(&value, &immediateValue, std::min(sizeof(T), sizeof(immediateValue)));
873 return value;
874 }
875 default:
876 ABORT_MSG("Unhandled compression type %u in %s", uint32(_columnMeta[field].CompressionType), _fileName);
877 break;
878 }
879
880 return 0;
881}
882
883uint64 DB2FileLoaderRegularImpl::RecordGetPackedValue(uint8 const* packedRecordData, uint32 bitWidth, uint32 bitOffset) const
884{
885 uint32 bitsToRead = bitOffset & 7;
886 return *reinterpret_cast<uint64 const*>(packedRecordData) << (64 - bitsToRead - bitWidth) >> (64 - bitWidth);
887}
888
890{
891 ASSERT(field < _header->FieldCount);
892 DB2ColumnCompression compressionType = _columnMeta ? _columnMeta[field].CompressionType : DB2ColumnCompression::None;
893 switch (compressionType)
894 {
896 return _columnMeta[field].BitOffset / 8;
899 return _columnMeta[field].CompressionData.immediate.BitOffset / 8 + _header->PackedDataOffset;
901 return 0xFFFF;
904 return _columnMeta[field].CompressionData.pallet.BitOffset / 8 + _header->PackedDataOffset;
905 default:
906 ABORT_MSG("Unhandled compression type %u in %s", uint32(_columnMeta[field].CompressionType), _fileName);
907 break;
908 }
909
910 return 0;
911}
912
913std::size_t* DB2FileLoaderRegularImpl::RecordCreateDetachedFieldOffsets(std::size_t* /*oldOffsets*/) const
914{
915 return nullptr;
916}
917
918std::size_t* DB2FileLoaderRegularImpl::RecordCopyDetachedFieldOffsets(std::size_t* /*oldOffsets*/) const
919{
920 return nullptr;
921}
922
923void DB2FileLoaderRegularImpl::RecordDestroyFieldOffsets(std::size_t*& /*fieldOffsets*/) const
924{
925}
926
928{
929 uint32 minId = std::numeric_limits<uint32>::max();
930 for (uint32 row = 0; row < _header->RecordCount; ++row)
931 {
932 unsigned char const* rawRecord = GetRawRecordData(row, nullptr);
933 if (!rawRecord)
934 continue;
935
936 uint32 id = RecordGetId(rawRecord, row);
937 if (id < minId)
938 minId = id;
939 }
940
941 for (uint32 copy = 0; copy < GetRecordCopyCount(); ++copy)
942 {
943 uint32 id = GetRecordCopy(copy).NewRowId;
944 if (id < minId)
945 minId = id;
946 }
947
948 if (minId == std::numeric_limits<uint32>::max())
949 minId = 0;
950
951 ASSERT(minId >= _header->MinId);
952 return minId;
953}
954
956{
957 uint32 maxId = 0;
958 for (uint32 row = 0; row < _header->RecordCount; ++row)
959 {
960 unsigned char const* rawRecord = GetRawRecordData(row, nullptr);
961 if (!rawRecord)
962 continue;
963
964 uint32 id = RecordGetId(rawRecord, row);
965 if (id > maxId)
966 maxId = id;
967 }
968
969 for (uint32 copy = 0; copy < GetRecordCopyCount(); ++copy)
970 {
971 uint32 id = GetRecordCopy(copy).NewRowId;
972 if (id > maxId)
973 maxId = id;
974 }
975
976 ASSERT(maxId <= _header->MaxId);
977 return maxId;
978}
979
984
986{
987 return _sections[section];
988}
989
990DB2FileLoaderSparseImpl::DB2FileLoaderSparseImpl(char const* fileName, DB2FileLoadInfo const* loadInfo, DB2Header const* header, DB2FileSource* source) :
991 _fileName(fileName),
992 _loadInfo(loadInfo),
993 _header(header),
994 _source(source),
995 _totalRecordSize(0),
996 _maxRecordSize(0),
997 _fieldAndArrayOffsets(loadInfo ? (std::make_unique<std::size_t[]>(loadInfo->Meta->FieldCount + loadInfo->FieldCount - (!loadInfo->Meta->HasIndexFieldInData() ? 1 : 0))) : nullptr)
998{
999}
1000
1002
1003void DB2FileLoaderSparseImpl::LoadColumnData(std::unique_ptr<DB2SectionHeader[]> sections, std::unique_ptr<DB2FieldEntry[]> fields, std::unique_ptr<DB2ColumnMeta[]> /*columnMeta*/,
1004 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> /*palletValues*/, std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> /*palletArrayValues*/,
1005 std::unique_ptr<std::unordered_map<uint32, uint32>[]> /*commonValues*/)
1006{
1007 _sections = std::move(sections);
1008 _fields = std::move(fields);
1009}
1010
1012{
1013 _catalogIds.resize(_catalogIds.size() + _sections[section].CatalogDataCount);
1014 _catalog.resize(_catalog.size() + _sections[section].CatalogDataCount);
1015}
1016
1018{
1019 source->SetPosition(_sections[section].CatalogDataOffset);
1020
1021 std::size_t oldSize = _catalog.size();
1022 _catalogIds.resize(oldSize + _sections[section].CatalogDataCount);
1023 if (!source->Read(&_catalogIds[oldSize], sizeof(uint32) * _sections[section].CatalogDataCount))
1024 return false;
1025
1026 if (_sections[section].CopyTableCount)
1027 {
1028 std::size_t oldCopyTableSize = _copyTable.size();
1029 _copyTable.resize(oldCopyTableSize + _sections[section].CopyTableCount);
1030 if (!source->Read(&_copyTable[oldCopyTableSize], sizeof(DB2RecordCopy) * _sections[section].CopyTableCount))
1031 return false;
1032 }
1033
1034 _catalog.resize(oldSize + _sections[section].CatalogDataCount);
1035 if (!source->Read(&_catalog[oldSize], sizeof(DB2CatalogEntry) * _sections[section].CatalogDataCount))
1036 return false;
1037
1038 for (uint32 i = 0; i < _sections[section].CatalogDataCount; ++i)
1039 {
1040 _totalRecordSize += _catalog[oldSize + i].RecordSize;
1041 _maxRecordSize = std::max(_maxRecordSize, _catalog[oldSize + i].RecordSize);
1042 }
1043
1044 return true;
1045}
1046
1047void DB2FileLoaderSparseImpl::SetAdditionalData(std::vector<uint32> /*idTable*/, std::vector<DB2RecordCopy> /*copyTable*/, std::vector<std::vector<DB2IndexData>> parentIndexes)
1048{
1049 _parentIndexes = std::move(parentIndexes);
1050 _recordBuffer = std::make_unique<uint8[]>(_maxRecordSize);
1051}
1052
1053char* DB2FileLoaderSparseImpl::AutoProduceData(uint32& indexTableSize, char**& indexTable)
1054{
1056 throw DB2FileLoadException(Trinity::StringFormat("Found unsupported parent index in sparse db2 {}", _fileName));
1057
1058 //get struct size and index pos
1059 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
1060 uint32 records = _catalog.size();
1061
1062 using index_entry_t = char*;
1063
1064 indexTableSize = _header->MaxId + 1;
1065 indexTable = new index_entry_t[indexTableSize];
1066 memset(indexTable, 0, indexTableSize * sizeof(index_entry_t));
1067
1068 char* dataTable = new char[(records + _copyTable.size()) * recordsize];
1069 memset(dataTable, 0, (records + _copyTable.size()) * recordsize);
1070
1071 uint32 offset = 0;
1072 uint32 y = 0;
1073
1074 for (uint32 section = 0; section < _header->SectionCount; ++section)
1075 {
1076 DB2SectionHeader const& sectionHeader = GetSection(section);
1077 if (!IsKnownTactId(sectionHeader.TactId))
1078 {
1079 offset += recordsize * sectionHeader.RecordCount;
1080 y += sectionHeader.RecordCount;
1081 continue;
1082 }
1083
1084 for (uint32 sr = 0; sr < sectionHeader.CatalogDataCount; ++sr, ++y)
1085 {
1086 unsigned char const* rawRecord = GetRawRecordData(y, &section);
1087 if (!rawRecord)
1088 continue;
1089
1090 uint32 indexVal = _catalogIds[y];
1091 indexTable[indexVal] = &dataTable[offset];
1092
1093 uint32 fieldIndex = 0;
1095 {
1096 *reinterpret_cast<uint32*>(&dataTable[offset]) = indexVal;
1097 offset += 4;
1098 ++fieldIndex;
1099 }
1100
1101 for (uint32 x = 0; x < _header->FieldCount; ++x)
1102 {
1103 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
1104 {
1105 switch (_loadInfo->Fields[fieldIndex].Type)
1106 {
1107 case FT_FLOAT:
1108 *reinterpret_cast<float*>(&dataTable[offset]) = RecordGetFloat(rawRecord, x, z);
1109 offset += 4;
1110 break;
1111 case FT_INT:
1112 *reinterpret_cast<uint32*>(&dataTable[offset]) = RecordGetVarInt(rawRecord, x, z, _loadInfo->Fields[fieldIndex].IsSigned);
1113 offset += 4;
1114 break;
1115 case FT_BYTE:
1116 *reinterpret_cast<uint8*>(&dataTable[offset]) = RecordGetUInt8(rawRecord, x, z);
1117 offset += 1;
1118 break;
1119 case FT_SHORT:
1120 *reinterpret_cast<uint16*>(&dataTable[offset]) = RecordGetUInt16(rawRecord, x, z);
1121 offset += 2;
1122 break;
1123 case FT_LONG:
1124 *reinterpret_cast<uint64*>(&dataTable[offset]) = RecordGetUInt64(rawRecord, x, z);
1125 offset += 8;
1126 break;
1127 case FT_STRING:
1128 for (char const*& localeStr : reinterpret_cast<LocalizedString*>(&dataTable[offset])->Str)
1129 localeStr = EmptyDb2String;
1130
1131 offset += sizeof(LocalizedString);
1132 break;
1134 *reinterpret_cast<char const**>(&dataTable[offset]) = EmptyDb2String;
1135 offset += sizeof(char*);
1136 break;
1137 default:
1138 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
1139 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
1140 break;
1141 }
1142 ++fieldIndex;
1143 }
1144 }
1145
1146 for (uint32 x = _header->FieldCount; x < _loadInfo->Meta->FieldCount; ++x)
1147 {
1148 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
1149 {
1150 switch (_loadInfo->Fields[fieldIndex].Type)
1151 {
1152 case FT_INT:
1153 *reinterpret_cast<uint32*>(&dataTable[offset]) = 0;
1154 offset += 4;
1155 break;
1156 case FT_BYTE:
1157 *reinterpret_cast<uint8*>(&dataTable[offset]) = 0;
1158 offset += 1;
1159 break;
1160 case FT_SHORT:
1161 *reinterpret_cast<uint16*>(&dataTable[offset]) = 0;
1162 offset += 2;
1163 break;
1164 default:
1165 ABORT_MSG("Unknown format character '%c' found in %s meta for parent field %s",
1166 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
1167 break;
1168 }
1169 ++fieldIndex;
1170 }
1171 }
1172 }
1173 }
1174
1175 return dataTable;
1176}
1177
1178char* DB2FileLoaderSparseImpl::AutoProduceStrings(char** indexTable, uint32 indexTableSize, uint32 locale)
1179{
1181 throw DB2FileLoadException(Trinity::StringFormat("Found unsupported parent index in sparse db2 {}", _fileName));
1182
1183 if (!(_header->Locale & (1 << locale)))
1184 {
1185 std::array<char const*, TOTAL_LOCALES> detectedLocales;
1186 auto itr = detectedLocales.begin();
1187 for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
1188 if (_header->Locale & (1 << i))
1189 *itr++ = localeNames[i];
1190
1191 throw DB2FileLoadException(Trinity::StringFormat("Attempted to load {} which has locales {} as {}. Check if you placed your localized db2 files in correct directory.",
1192 _fileName, fmt::join(detectedLocales.begin(), itr, ", "), localeNames[locale]));
1193 }
1194
1195 uint32 records = _catalog.size();
1196 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
1197 std::size_t stringFields = _loadInfo->GetStringFieldCount(false);
1198 std::size_t localizedStringFields = _loadInfo->GetStringFieldCount(true);
1199
1200 if (!stringFields)
1201 return nullptr;
1202
1203 std::size_t stringsInRecordSize = (stringFields - localizedStringFields) * sizeof(char*);
1204 std::size_t localizedStringsInRecordSize = localizedStringFields * sizeof(LocalizedString);
1205
1206 // string table size is "total size of all records" - RecordCount * "size of record without strings"
1207 std::size_t stringTableSize = _totalRecordSize - (records * ((recordsize - (!_loadInfo->Meta->HasIndexFieldInData() ? 4 : 0)) - stringsInRecordSize - localizedStringsInRecordSize));
1208
1209 char* stringTable = new char[stringTableSize];
1210 memset(stringTable, 0, stringTableSize);
1211 char* stringPtr = stringTable;
1212
1213 uint32 y = 0;
1214
1215 for (uint32 section = 0; section < _header->SectionCount; ++section)
1216 {
1217 DB2SectionHeader const& sectionHeader = GetSection(section);
1218 if (!IsKnownTactId(sectionHeader.TactId))
1219 {
1220 y += sectionHeader.RecordCount;
1221 continue;
1222 }
1223
1224 for (uint32 sr = 0; sr < sectionHeader.CatalogDataCount; ++sr, ++y)
1225 {
1226 unsigned char const* rawRecord = GetRawRecordData(y, &section);
1227 if (!rawRecord)
1228 continue;
1229
1230 uint32 indexVal = _catalogIds[y];
1231 if (indexVal >= indexTableSize)
1232 continue;
1233
1234 char* recordData = indexTable[indexVal];
1235
1236 uint32 offset = 0;
1237 uint32 fieldIndex = 0;
1239 {
1240 offset += 4;
1241 ++fieldIndex;
1242 }
1243
1244 for (uint32 x = 0; x < _header->FieldCount; ++x)
1245 {
1246 for (uint32 z = 0; z < _loadInfo->Meta->Fields[x].ArraySize; ++z)
1247 {
1248 switch (_loadInfo->Fields[fieldIndex].Type)
1249 {
1250 case FT_FLOAT:
1251 offset += 4;
1252 break;
1253 case FT_INT:
1254 offset += 4;
1255 break;
1256 case FT_BYTE:
1257 offset += 1;
1258 break;
1259 case FT_SHORT:
1260 offset += 2;
1261 break;
1262 case FT_LONG:
1263 offset += 8;
1264 break;
1265 case FT_STRING:
1266 {
1267 LocalizedString* db2str = reinterpret_cast<LocalizedString*>(&recordData[offset]);
1268 db2str->Str[locale] = stringPtr;
1269 strcpy(stringPtr, RecordGetString(rawRecord, x, z));
1270 stringPtr += strlen(stringPtr) + 1;
1271 offset += sizeof(LocalizedString);
1272 break;
1273 }
1275 {
1276 char const** db2str = reinterpret_cast<char const**>(&recordData[offset]);
1277 *db2str = stringPtr;
1278 strcpy(stringPtr, RecordGetString(rawRecord, x, z));
1279 stringPtr += strlen(stringPtr) + 1;
1280 offset += sizeof(char*);
1281 break;
1282 }
1283 default:
1284 ABORT_MSG("Unknown format character '%c' found in %s meta for field %s",
1285 _loadInfo->Fields[fieldIndex].Type, _fileName, _loadInfo->Fields[fieldIndex].Name);
1286 break;
1287 }
1288 ++fieldIndex;
1289 }
1290 }
1291 }
1292 }
1293
1294 return stringTable;
1295}
1296
1297void DB2FileLoaderSparseImpl::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
1298{
1299 uint32 recordCopies = GetRecordCopyCount();
1300 if (!recordCopies)
1301 return;
1302
1303 uint32 recordsize = _loadInfo->Meta->GetRecordSize();
1304 uint32 offset = _header->RecordCount * recordsize;
1306 for (uint32 c = 0; c < recordCopies; ++c)
1307 {
1308 DB2RecordCopy copy = GetRecordCopy(c);
1309 if (copy.SourceRowId && copy.SourceRowId < records && copy.NewRowId < records && indexTable[copy.SourceRowId])
1310 {
1311 indexTable[copy.NewRowId] = &dataTable[offset];
1312 memcpy(indexTable[copy.NewRowId], indexTable[copy.SourceRowId], recordsize);
1313 *reinterpret_cast<uint32*>(&dataTable[offset + idFieldOffset]) = copy.NewRowId;
1314 offset += recordsize;
1315 }
1316 }
1317}
1318
1320{
1321 return DB2Record(*this, recordNumber, _fieldAndArrayOffsets.get());
1322}
1323
1325{
1326 if (copyNumber >= GetRecordCopyCount())
1327 return DB2RecordCopy{};
1328
1329 return _copyTable[copyNumber];
1330}
1331
1333{
1334 return _catalog.size();
1335}
1336
1338{
1339 return _copyTable.size();
1340}
1341
1343{
1344 int32 parentIdOffset = _loadInfo->Meta->GetParentIndexFieldOffset();
1345 uint32 recordSize = _loadInfo->Meta->GetRecordSize();
1346 uint32 recordIndexOffset = 0;
1347 for (uint32 i = 0; i < _header->SectionCount; ++i)
1348 {
1349 DB2SectionHeader const& section = GetSection(i);
1350 if (IsKnownTactId(section.TactId))
1351 {
1352 for (std::size_t j = 0; j < _parentIndexes[i][0].Entries.size(); ++j)
1353 {
1354 uint32 parentId = _parentIndexes[i][0].Entries[j].ParentId;
1355 char* recordData = &dataTable[(_parentIndexes[i][0].Entries[j].RecordIndex + recordIndexOffset) * recordSize];
1356
1358 {
1359 case FT_SHORT:
1360 {
1362 {
1363 // extra field at the end
1364 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
1365 }
1366 else
1367 {
1368 // in data block, must fit
1369 ASSERT(parentId <= 0xFFFF, "ParentId value %u does not fit into uint16 field (%s in %s)",
1371 *reinterpret_cast<uint16*>(&recordData[parentIdOffset]) = parentId;
1372 }
1373 break;
1374 }
1375 case FT_BYTE:
1376 {
1378 {
1379 // extra field at the end
1380 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
1381 }
1382 else
1383 {
1384 // in data block, must fit
1385 ASSERT(parentId <= 0xFF, "ParentId value %u does not fit into uint8 field (%s in %s)",
1387 *reinterpret_cast<uint8*>(&recordData[parentIdOffset]) = parentId;
1388 }
1389 break;
1390 }
1391 case FT_INT:
1392 *reinterpret_cast<uint32*>(&recordData[parentIdOffset]) = parentId;
1393 break;
1394 default:
1395 ABORT_MSG("Unhandled parent id type '%c' found in %s", _loadInfo->Meta->Fields[_loadInfo->Meta->ParentIndexField].Type, _fileName);
1396 break;
1397 }
1398 }
1399 }
1400 recordIndexOffset += section.RecordCount;
1401 }
1402}
1403
1405{
1406 uint32 section = 0;
1407 for (; section < _header->SectionCount; ++section)
1408 {
1409 DB2SectionHeader const& sectionHeader = GetSection(section);
1410 if (recordNumber < sectionHeader.CatalogDataCount)
1411 break;
1412
1413 recordNumber -= sectionHeader.CatalogDataCount;
1414 }
1415
1416 return section;
1417}
1418
1419unsigned char const* DB2FileLoaderSparseImpl::GetRawRecordData(uint32 recordNumber, uint32 const* section) const
1420{
1421 if (recordNumber >= _catalog.size())
1422 return nullptr;
1423
1424 if (!IsKnownTactId(GetSection(section ? *section : GetRecordSection(recordNumber)).TactId))
1425 return nullptr;
1426
1427 _source->SetPosition(_catalog[recordNumber].FileOffset);
1428 uint8* rawRecord = _recordBuffer.get();
1429 if (!_source->Read(rawRecord, _catalog[recordNumber].RecordSize))
1430 return nullptr;
1431
1433 return rawRecord;
1434}
1435
1437{
1439 return RecordGetVarInt(record, _loadInfo->Meta->GetIndexField(), 0, false);
1440
1441 return _catalogIds[recordIndex];
1442}
1443
1444uint8 DB2FileLoaderSparseImpl::RecordGetUInt8(uint8 const* record, uint32 field, uint32 arrayIndex) const
1445{
1446 ASSERT(field < _header->FieldCount);
1447 return *reinterpret_cast<uint8 const*>(record + GetFieldOffset(field, arrayIndex));
1448}
1449
1451{
1452 ASSERT(field < _header->FieldCount);
1453 uint16 val = *reinterpret_cast<uint16 const*>(record + GetFieldOffset(field, arrayIndex));
1454 EndianConvert(val);
1455 return val;
1456}
1457
1459{
1460 return RecordGetVarInt(record, field, arrayIndex, false);
1461}
1462
1463int32 DB2FileLoaderSparseImpl::RecordGetInt32(uint8 const* record, uint32 field, uint32 arrayIndex) const
1464{
1465 return int32(RecordGetVarInt(record, field, arrayIndex, true));
1466}
1467
1469{
1470 ASSERT(field < _header->FieldCount);
1471 uint64 val = *reinterpret_cast<uint64 const*>(record + GetFieldOffset(field, arrayIndex));
1472 EndianConvert(val);
1473 return val;
1474}
1475
1476float DB2FileLoaderSparseImpl::RecordGetFloat(uint8 const* record, uint32 field, uint32 arrayIndex) const
1477{
1478 ASSERT(field < _header->FieldCount);
1479 float val = *reinterpret_cast<float const*>(record + GetFieldOffset(field, arrayIndex));
1480 EndianConvert(val);
1481 return val;
1482}
1483
1484char const* DB2FileLoaderSparseImpl::RecordGetString(uint8 const* record, uint32 field, uint32 arrayIndex) const
1485{
1486 ASSERT(field < _header->FieldCount);
1487 return reinterpret_cast<char const*>(record + GetFieldOffset(field, arrayIndex));
1488}
1489
1490uint32 DB2FileLoaderSparseImpl::RecordGetVarInt(uint8 const* record, uint32 field, uint32 arrayIndex, bool isSigned) const
1491{
1492 ASSERT(field < _header->FieldCount);
1493 uint32 val = 0;
1494 memcpy(&val, record + GetFieldOffset(field, arrayIndex), GetFieldSize(field));
1495 EndianConvert(val);
1496 if (isSigned)
1497 return int32(val) << _fields[field].UnusedBits >> _fields[field].UnusedBits;
1498
1499 return val << _fields[field].UnusedBits >> _fields[field].UnusedBits;
1500}
1501
1503{
1504 return uint16(_fieldAndArrayOffsets[_fieldAndArrayOffsets[field] + arrayIndex]);
1505}
1506
1508{
1509 ASSERT(field < _header->FieldCount);
1510 return 4 - _fields[field].UnusedBits / 8;
1511}
1512
1513std::size_t* DB2FileLoaderSparseImpl::RecordCreateDetachedFieldOffsets(std::size_t* oldOffsets) const
1514{
1515 if (oldOffsets != _fieldAndArrayOffsets.get())
1516 return oldOffsets;
1517
1518 std::size_t size = _loadInfo->Meta->FieldCount + _loadInfo->FieldCount - (!_loadInfo->Meta->HasIndexFieldInData() ? 1 : 0);
1519 std::size_t* newOffsets = new std::size_t[size];
1520 memcpy(newOffsets, _fieldAndArrayOffsets.get(), size * sizeof(std::size_t));
1521 return newOffsets;
1522}
1523
1524std::size_t* DB2FileLoaderSparseImpl::RecordCopyDetachedFieldOffsets(std::size_t* oldOffsets) const
1525{
1526 if (oldOffsets == _fieldAndArrayOffsets.get())
1527 return oldOffsets;
1528
1529 std::size_t size = _loadInfo->Meta->FieldCount + _loadInfo->FieldCount - (!_loadInfo->Meta->HasIndexFieldInData() ? 1 : 0);
1530 std::size_t* newOffsets = new std::size_t[size];
1531 memcpy(newOffsets, _fieldAndArrayOffsets.get(), size * sizeof(std::size_t));
1532 return newOffsets;
1533}
1534
1535void DB2FileLoaderSparseImpl::RecordDestroyFieldOffsets(std::size_t*& fieldOffsets) const
1536{
1537 if (fieldOffsets == _fieldAndArrayOffsets.get())
1538 return;
1539
1540 delete[] fieldOffsets;
1541 fieldOffsets = nullptr;
1542}
1543
1545{
1546 std::size_t offset = 0;
1547 uint32 combinedField = _loadInfo->Meta->FieldCount;
1548 for (uint32 field = 0; field < _loadInfo->Meta->FieldCount; ++field)
1549 {
1550 _fieldAndArrayOffsets[field] = combinedField;
1551 for (uint32 arr = 0; arr < _loadInfo->Meta->Fields[field].ArraySize; ++arr)
1552 {
1553 _fieldAndArrayOffsets[combinedField] = offset;
1554 switch (_loadInfo->Meta->Fields[field].Type)
1555 {
1556 case FT_BYTE:
1557 case FT_SHORT:
1558 case FT_INT:
1559 case FT_LONG:
1560 offset += GetFieldSize(field);
1561 break;
1562 case FT_FLOAT:
1563 offset += sizeof(float);
1564 break;
1565 case FT_STRING:
1567 offset += strlen(reinterpret_cast<char const*>(rawRecord) + offset) + 1;
1568 break;
1569 default:
1570 ABORT_MSG("Unknown format character '%c' found in %s meta", _loadInfo->Meta->Fields[field].Type, _fileName);
1571 break;
1572 }
1573 ++combinedField;
1574 }
1575 }
1576}
1577
1579{
1580 return _header->MinId;
1581}
1582
1584{
1585 return _header->MaxId;
1586}
1587
1592
1594{
1595 return _sections[section];
1596}
1597
1598DB2Record::DB2Record(DB2FileLoaderImpl const& db2, uint32 recordIndex, std::size_t* fieldOffsets)
1599 : _db2(db2), _recordIndex(recordIndex), _recordData(db2.GetRawRecordData(recordIndex, nullptr)), _fieldOffsets(fieldOffsets)
1600{
1601}
1602
1604 : _db2(other._db2), _recordIndex(other._recordIndex), _recordData(other._recordData), _fieldOffsets(_db2.RecordCopyDetachedFieldOffsets(other._fieldOffsets))
1605{
1606}
1607
1609 : _db2(other._db2), _recordIndex(other._recordIndex), _recordData(other._recordData), _fieldOffsets(std::exchange(other._fieldOffsets, nullptr))
1610{
1611}
1612
1617
1618DB2Record::operator bool() const
1619{
1620 return _recordData != nullptr;
1621}
1622
1627
1628uint8 DB2Record::GetUInt8(uint32 field, uint32 arrayIndex) const
1629{
1630 return _db2.RecordGetUInt8(_recordData, field, arrayIndex);
1631}
1632
1633uint8 DB2Record::GetUInt8(char const* fieldName) const
1634{
1635 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1636 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1637 return _db2.RecordGetUInt8(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1638}
1639
1641{
1642 return _db2.RecordGetUInt16(_recordData, field, arrayIndex);
1643}
1644
1645uint16 DB2Record::GetUInt16(char const* fieldName) const
1646{
1647 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1648 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1649 return _db2.RecordGetUInt16(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1650}
1651
1653{
1654 return _db2.RecordGetUInt32(_recordData, field, arrayIndex);
1655}
1656
1657uint32 DB2Record::GetUInt32(char const* fieldName) const
1658{
1659 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1660 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1661 return _db2.RecordGetUInt32(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1662}
1663
1664int32 DB2Record::GetInt32(uint32 field, uint32 arrayIndex) const
1665{
1666 return _db2.RecordGetInt32(_recordData, field, arrayIndex);
1667}
1668
1669int32 DB2Record::GetInt32(char const* fieldName) const
1670{
1671 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1672 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1673 return _db2.RecordGetInt32(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1674}
1675
1677{
1678 return _db2.RecordGetUInt64(_recordData, field, arrayIndex);
1679}
1680
1681uint64 DB2Record::GetUInt64(char const* fieldName) const
1682{
1683 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1684 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1685 return _db2.RecordGetUInt64(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1686}
1687
1688float DB2Record::GetFloat(uint32 field, uint32 arrayIndex) const
1689{
1690 return _db2.RecordGetFloat(_recordData, field, arrayIndex);
1691}
1692
1693float DB2Record::GetFloat(char const* fieldName) const
1694{
1695 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1696 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1697 return _db2.RecordGetFloat(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1698}
1699
1700char const* DB2Record::GetString(uint32 field, uint32 arrayIndex) const
1701{
1702 return _db2.RecordGetString(_recordData, field, arrayIndex);
1703}
1704
1705char const* DB2Record::GetString(char const* fieldName) const
1706{
1707 std::pair<int32, int32> fieldIndex = _db2.GetLoadInfo()->GetFieldIndexByName(fieldName);
1708 ASSERT(fieldIndex.first != -1, "Field with name %s does not exist!", fieldName);
1709 return _db2.RecordGetString(_recordData, uint32(fieldIndex.first), uint32(fieldIndex.second));
1710}
1711
1716
1717DB2FileLoader::DB2FileLoader() : _impl(nullptr), _header()
1718{
1719}
1720
1722{
1723 delete _impl;
1724}
1725
1727{
1728 if (!source->IsOpen())
1729 throw std::system_error(std::make_error_code(std::errc::no_such_file_or_directory));
1730
1731 if (!source->Read(&_header, sizeof(DB2Header)))
1732 throw DB2FileLoadException("Failed to read header");
1733
1754
1755 if (_header.Signature != 0x35434457) //'WDC5'
1756 throw DB2FileLoadException(Trinity::StringFormat("Incorrect file signature in {}, expected 'WDC5', got {}{}{}{}", source->GetFileName(),
1757 char(_header.Signature & 0xFF), char((_header.Signature >> 8) & 0xFF), char((_header.Signature >> 16) & 0xFF), char((_header.Signature >> 24) & 0xFF)));
1758
1759 if (_header.Version != 5)
1760 throw DB2FileLoadException(Trinity::StringFormat("Incorrect version in {}, expected 5, got {} (possibly wrong client version)",
1761 source->GetFileName(), _header.Version));
1762
1763 if (loadInfo && _header.LayoutHash != loadInfo->Meta->LayoutHash)
1764 throw DB2FileLoadException(Trinity::StringFormat("Incorrect layout hash in {}, expected 0x{:08X}, got 0x{:08X} (possibly wrong client version)",
1765 source->GetFileName(), loadInfo->Meta->LayoutHash, _header.LayoutHash));
1766
1767 if (_header.ParentLookupCount > 1)
1768 throw DB2FileLoadException(Trinity::StringFormat("Too many parent lookups in {}, only one is allowed, got {}",
1770
1771 if (loadInfo && (_header.TotalFieldCount + (loadInfo->Meta->ParentIndexField >= int32(_header.TotalFieldCount) ? 1 : 0) != loadInfo->Meta->FieldCount))
1772 throw DB2FileLoadException(Trinity::StringFormat("Incorrect number of fields in {}, expected {}, got {}",
1773 source->GetFileName(), loadInfo->Meta->FieldCount, _header.TotalFieldCount + (loadInfo->Meta->ParentIndexField >= int32(_header.TotalFieldCount) ? 1 : 0)));
1774
1775 if (loadInfo && (_header.ParentLookupCount && loadInfo->Meta->ParentIndexField == -1))
1776 throw DB2FileLoadException(Trinity::StringFormat("Unexpected parent lookup found in {}", source->GetFileName()));
1777
1778 std::unique_ptr<DB2SectionHeader[]> sections = std::make_unique<DB2SectionHeader[]>(_header.SectionCount);
1779 if (_header.SectionCount && !source->Read(sections.get(), sizeof(DB2SectionHeader) * _header.SectionCount))
1780 throw DB2FileLoadException(Trinity::StringFormat("Unable to read section headers from {}", source->GetFileName()));
1781
1782 std::unique_ptr<DB2FieldEntry[]> fieldData = std::make_unique<DB2FieldEntry[]>(_header.FieldCount);
1783 if (!source->Read(fieldData.get(), sizeof(DB2FieldEntry) * _header.FieldCount))
1784 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field information from {}", source->GetFileName()));
1785
1786 std::unique_ptr<DB2ColumnMeta[]> columnMeta;
1787 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletValues;
1788 std::unique_ptr<std::unique_ptr<DB2PalletValue[]>[]> palletArrayValues;
1789 std::unique_ptr<std::unordered_map<uint32, uint32>[]> commonValues;
1791 {
1792 columnMeta = std::make_unique<DB2ColumnMeta[]>(_header.TotalFieldCount);
1793 if (!source->Read(columnMeta.get(), _header.ColumnMetaSize))
1794 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field metadata from {}", source->GetFileName()));
1795
1796 if (loadInfo && loadInfo->Meta->HasIndexFieldInData())
1797 {
1798 if (columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::None
1799 && columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::Immediate
1800 && columnMeta[loadInfo->Meta->IndexField].CompressionType != DB2ColumnCompression::SignedImmediate)
1801 throw DB2FileLoadException(Trinity::StringFormat("Invalid compression type for index field in {}, expected one of None (0), Immediate (1), SignedImmediate (5), got {}",
1802 source->GetFileName(), uint32(columnMeta[loadInfo->Meta->IndexField].CompressionType)));
1803 }
1804
1805 palletValues = std::make_unique<std::unique_ptr<DB2PalletValue[]>[]>(_header.TotalFieldCount);
1806 for (uint32 i = 0; i < _header.TotalFieldCount; ++i)
1807 {
1808 if (columnMeta[i].CompressionType != DB2ColumnCompression::Pallet)
1809 continue;
1810
1811 palletValues[i] = std::make_unique<DB2PalletValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2PalletValue));
1812 if (!source->Read(palletValues[i].get(), columnMeta[i].AdditionalDataSize))
1813 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field pallet values from {} for field {}", source->GetFileName(), i));
1814 }
1815
1816 palletArrayValues = std::make_unique<std::unique_ptr<DB2PalletValue[]>[]>(_header.TotalFieldCount);
1817 for (uint32 i = 0; i < _header.TotalFieldCount; ++i)
1818 {
1819 if (columnMeta[i].CompressionType != DB2ColumnCompression::PalletArray)
1820 continue;
1821
1822 palletArrayValues[i] = std::make_unique<DB2PalletValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2PalletValue));
1823 if (!source->Read(palletArrayValues[i].get(), columnMeta[i].AdditionalDataSize))
1824 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field pallet array values from {} for field {}", source->GetFileName(), i));
1825 }
1826
1827 std::unique_ptr<std::unique_ptr<DB2CommonValue[]>[]> commonData = std::make_unique<std::unique_ptr<DB2CommonValue[]>[]>(_header.TotalFieldCount);
1828 commonValues = std::make_unique<std::unordered_map<uint32, uint32>[]>(_header.TotalFieldCount);
1829 for (uint32 i = 0; i < _header.TotalFieldCount; ++i)
1830 {
1831 if (columnMeta[i].CompressionType != DB2ColumnCompression::CommonData)
1832 continue;
1833
1834 if (!columnMeta[i].AdditionalDataSize)
1835 continue;
1836
1837 commonData[i] = std::make_unique<DB2CommonValue[]>(columnMeta[i].AdditionalDataSize / sizeof(DB2CommonValue));
1838 if (!source->Read(commonData[i].get(), columnMeta[i].AdditionalDataSize))
1839 throw DB2FileLoadException(Trinity::StringFormat("Unable to read field common values from {} for field {}", source->GetFileName(), i));
1840
1841 uint32 numExtraValuesForField = columnMeta[i].AdditionalDataSize / sizeof(DB2CommonValue);
1842 for (uint32 record = 0; record < numExtraValuesForField; ++record)
1843 {
1844 uint32 recordId = commonData[i][record].RecordId;
1845 uint32 value = commonData[i][record].Value;
1846 EndianConvert(value);
1847 commonValues[i][recordId] = value;
1848 }
1849 }
1850 }
1851
1852 if (!(_header.Flags & 0x1))
1853 _impl = new DB2FileLoaderRegularImpl(source->GetFileName(), loadInfo, &_header);
1854 else
1855 _impl = new DB2FileLoaderSparseImpl(source->GetFileName(), loadInfo, &_header, source);
1856
1857 _impl->LoadColumnData(std::move(sections), std::move(fieldData), std::move(columnMeta), std::move(palletValues), std::move(palletArrayValues), std::move(commonValues));
1858}
1859
1861{
1862 LoadHeaders(source, loadInfo);
1863
1864 std::vector<uint32> idTable;
1865 std::vector<DB2RecordCopy> copyTable;
1866 std::vector<std::vector<DB2IndexData>> parentIndexes;
1867 if (loadInfo && !loadInfo->Meta->HasIndexFieldInData() && _header.RecordCount)
1868 idTable.reserve(_header.RecordCount);
1869
1871 {
1872 parentIndexes.resize(_header.SectionCount);
1873 for (std::vector<DB2IndexData>& parentIndexesForSection : parentIndexes)
1874 parentIndexesForSection.resize(_header.ParentLookupCount);
1875 }
1876
1877 for (uint32 i = 0; i < _header.SectionCount; ++i)
1878 {
1879 DB2SectionHeader& section = _impl->GetSection(i);
1880
1881 if (section.TactId)
1882 {
1883 uint32 encryptedIdCount;
1884 if (!source->Read(&encryptedIdCount, sizeof(encryptedIdCount)))
1885 throw DB2FileLoadException(Trinity::StringFormat("Unable to read number of encrypted records in {} for section {}", source->GetFileName(), i));
1886
1887 // it doesnt matter what the encrypted ids are, we have no use for them
1888 source->SetPosition(source->GetPosition() + sizeof(uint32) * encryptedIdCount);
1889 }
1890 }
1891
1892 if (loadInfo && !(_header.Flags & 0x1))
1893 {
1894 uint32 totalCopyTableSize = 0;
1895 uint32 totalParentLookupDataSize = 0;
1896 for (uint32 i = 0; i < _header.SectionCount; ++i)
1897 {
1898 DB2SectionHeader& section = _impl->GetSection(i);
1899 totalCopyTableSize += section.CopyTableCount * sizeof(DB2RecordCopy);
1900 totalParentLookupDataSize += section.ParentLookupDataSize;
1901 }
1902
1903 int64 expectedFileSize =
1904 source->GetPosition() +
1907 (loadInfo->Meta->IndexField == -1 ? sizeof(uint32) * _header.RecordCount : 0) +
1908 totalCopyTableSize +
1909 totalParentLookupDataSize;
1910
1911 if (source->GetFileSize() != expectedFileSize)
1912 throw DB2FileLoadException(Trinity::StringFormat("{} failed size consistency check, expected {}, got {}", source->GetFileName(), expectedFileSize, source->GetFileSize()));
1913 }
1914
1915 for (uint32 i = 0; i < _header.SectionCount; ++i)
1916 {
1917 DB2SectionHeader& section = _impl->GetSection(i);
1918
1919 if (!IsKnownTactId(section.TactId))
1920 {
1921 switch (source->HandleEncryptedSection(section))
1922 {
1925 idTable.resize(idTable.size() + section.IdTableSize / sizeof(uint32));
1926 continue;
1928 section.TactId = DUMMY_KNOWN_TACT_ID;
1929 break;
1930 default:
1931 break;
1932 }
1933 }
1934
1935 if (!source->SetPosition(section.FileOffset))
1936 throw DB2FileLoadException(Trinity::StringFormat("Unable to change {} read position for section {}", source->GetFileName(), i));
1937
1938 if (!_impl->LoadTableData(source, i))
1939 throw DB2FileLoadException(Trinity::StringFormat("Unable to read section table data from {} for section {}", source->GetFileName(), i));
1940
1941 if (!_impl->LoadCatalogData(source, i))
1942 throw DB2FileLoadException(Trinity::StringFormat("Unable to read section catalog data from {} for section {}", source->GetFileName(), i));
1943
1944 if (loadInfo)
1945 {
1946 if (loadInfo->Meta->HasIndexFieldInData())
1947 {
1948 if (section.IdTableSize != 0)
1949 throw DB2FileLoadException(Trinity::StringFormat("Unexpected id table found in {} for section {}", source->GetFileName(), i));
1950 }
1951 else if (section.IdTableSize != 4 * section.RecordCount)
1952 throw DB2FileLoadException(Trinity::StringFormat("Unexpected id table size in {} for section {}, expected {}, got {}",
1953 source->GetFileName(), i, 4 * section.RecordCount, section.IdTableSize));
1954 }
1955
1956 if (section.IdTableSize)
1957 {
1958 std::size_t idTableSize = idTable.size();
1959 idTable.resize(idTableSize + section.IdTableSize / sizeof(uint32));
1960 if (!source->Read(&idTable[idTableSize], section.IdTableSize))
1961 throw DB2FileLoadException(Trinity::StringFormat("Unable to read non-inline record ids from {} for section {}", source->GetFileName(), i));
1962
1963 // This is a hack fix for broken db2 files that have invalid id tables
1964 for (std::size_t i = idTableSize; i < idTable.size(); ++i)
1965 if (idTable[i] <= _header.MinId)
1966 idTable[i] = _header.MinId + i;
1967 }
1968
1969 if (!(_header.Flags & 0x1) && section.CopyTableCount)
1970 {
1971 std::size_t copyTableSize = copyTable.size();
1972 copyTable.resize(copyTableSize + section.CopyTableCount);
1973 if (!source->Read(&copyTable[copyTableSize], section.CopyTableCount * sizeof(DB2RecordCopy)))
1974 throw DB2FileLoadException(Trinity::StringFormat("Unable to read record copies from {} for section {}", source->GetFileName(), i));
1975 }
1976
1978 {
1979 std::vector<DB2IndexData>& parentIndexesForSection = parentIndexes[i];
1980 for (uint32 j = 0; j < _header.ParentLookupCount; ++j)
1981 {
1982 DB2IndexDataInfo indexInfo;
1983 if (!source->Read(&indexInfo, sizeof(DB2IndexDataInfo)))
1984 throw DB2FileLoadException(Trinity::StringFormat("Unable to read parent lookup info from {} for section {}", source->GetFileName(), i));
1985
1986 if (!indexInfo.NumEntries)
1987 continue;
1988
1989 parentIndexesForSection[j].Entries.resize(indexInfo.NumEntries);
1990 if (!source->Read(parentIndexesForSection[j].Entries.data(), sizeof(DB2IndexEntry) * indexInfo.NumEntries))
1991 throw DB2FileLoadException(Trinity::StringFormat("Unable to read parent lookup content from {} for section {}", source->GetFileName(), i));
1992 }
1993 }
1994 }
1995
1996 _impl->SetAdditionalData(std::move(idTable), std::move(copyTable), std::move(parentIndexes));
1997
1998 if (loadInfo)
1999 {
2000 uint32 fieldIndex = 0;
2001 std::vector<std::string> signValidationResult;
2002 if (!loadInfo->Meta->HasIndexFieldInData())
2003 {
2004 if (loadInfo->Fields[0].IsSigned)
2005 signValidationResult.emplace_back(Trinity::StringFormat("ID must be unsigned in {}", source->GetFileName()));
2006 ++fieldIndex;
2007 }
2008 for (uint32 f = 0; f < loadInfo->Meta->FieldCount; ++f)
2009 {
2010 if (loadInfo->Fields[fieldIndex].IsSigned != loadInfo->Meta->IsSignedField(f))
2011 {
2012 signValidationResult.emplace_back(Trinity::StringFormat("Field {} in {} must be {}", loadInfo->Fields[fieldIndex].Name,
2013 source->GetFileName(), loadInfo->Meta->IsSignedField(f) ? "signed" : "unsigned"));
2014
2015 if (int32(f) == loadInfo->Meta->IndexField)
2016 signValidationResult.back() += " (IndexField must always be unsigned)";
2017 if (int32(f) == loadInfo->Meta->ParentIndexField)
2018 signValidationResult.back() += " (ParentIndexField must always be unsigned)";
2019 }
2020
2021 fieldIndex += loadInfo->Meta->Fields[f].ArraySize;
2022 }
2023 if (!signValidationResult.empty())
2024 throw DB2FileLoadException(Trinity::StringFormat("{}", fmt::join(signValidationResult, "\n")));
2025 }
2026}
2027
2028char* DB2FileLoader::AutoProduceData(uint32& indexTableSize, char**& indexTable)
2029{
2030 return _impl->AutoProduceData(indexTableSize, indexTable);
2031}
2032
2033char* DB2FileLoader::AutoProduceStrings(char** indexTable, uint32 indexTableSize, LocaleConstant locale)
2034{
2035 return _impl->AutoProduceStrings(indexTable, indexTableSize, locale);
2036}
2037
2038void DB2FileLoader::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
2039{
2040 _impl->AutoProduceRecordCopies(records, indexTable, dataTable);
2041}
2042
2044{
2045 return _impl->GetRecordCount();
2046}
2047
2052
2054{
2055 return _impl->GetMinId();
2056}
2057
2059{
2060 return _impl->GetMaxId();
2061}
2062
2064{
2065 return _impl->GetSection(section);
2066}
2067
2069{
2070 return _impl->GetRecord(recordNumber);
2071}
2072
2074{
2075 return _impl->GetRecordCopy(copyNumber);
2076}
void EndianConvert(T &val)
char const * localeNames[TOTAL_LOCALES]
Definition Common.cpp:20
LocaleConstant
Definition Common.h:51
@ TOTAL_LOCALES
Definition Common.h:65
DB2ColumnCompression
static bool IsKnownTactId(uint64 tactId)
static char const *const EmptyDb2String
constinit uint64 DUMMY_KNOWN_TACT_ID
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int16_t int16
Definition Define.h:151
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
#define UI64LIT(N)
Definition Define.h:139
uint16_t uint16
Definition Define.h:155
@ FT_FLOAT
Definition Define.h:162
@ FT_SHORT
Definition Define.h:165
@ FT_STRING
Definition Define.h:160
@ FT_INT
Definition Define.h:163
@ FT_STRING_NOT_LOCALIZED
Definition Define.h:161
@ FT_BYTE
Definition Define.h:164
@ FT_LONG
Definition Define.h:166
uint32_t uint32
Definition Define.h:154
#define ABORT_MSG
Definition Errors.h:88
#define ASSERT
Definition Errors.h:80
virtual char * AutoProduceData(uint32 &indexTableSize, char **&indexTable)=0
virtual uint64 RecordGetUInt64(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual uint32 GetMaxId() const =0
virtual uint32 GetRecordCopyCount() const =0
virtual DB2SectionHeader & GetSection(uint32 section) const =0
DB2FileLoaderImpl()=default
virtual ~DB2FileLoaderImpl()=default
virtual DB2FileLoadInfo const * GetLoadInfo() const =0
virtual uint32 RecordGetId(uint8 const *record, uint32 recordIndex) const =0
virtual float RecordGetFloat(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual void SetAdditionalData(std::vector< uint32 > idTable, std::vector< DB2RecordCopy > copyTable, std::vector< std::vector< DB2IndexData > > parentIndexes)=0
virtual void LoadColumnData(std::unique_ptr< DB2SectionHeader[]> sections, std::unique_ptr< DB2FieldEntry[]> fields, std::unique_ptr< DB2ColumnMeta[]> columnMeta, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletValues, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletArrayValues, std::unique_ptr< std::unordered_map< uint32, uint32 >[]> commonValues)=0
virtual std::size_t * RecordCopyDetachedFieldOffsets(std::size_t *oldOffsets) const =0
virtual std::size_t * RecordCreateDetachedFieldOffsets(std::size_t *oldOffsets) const =0
virtual uint32 GetMinId() const =0
virtual DB2Record GetRecord(uint32 recordNumber) const =0
virtual DB2RecordCopy GetRecordCopy(uint32 copyNumber) const =0
virtual uint32 RecordGetUInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual char const * RecordGetString(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
DB2FileLoaderImpl(DB2FileLoaderImpl const &other)=delete
virtual bool LoadCatalogData(DB2FileSource *source, uint32 section)=0
virtual bool LoadTableData(DB2FileSource *source, uint32 section)=0
DB2FileLoaderImpl(DB2FileLoaderImpl &&other) noexcept=delete
virtual void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable)=0
virtual void SkipEncryptedSection(uint32 section)=0
friend class DB2Record
virtual int32 RecordGetInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual uint32 GetRecordCount() const =0
virtual uint8 RecordGetUInt8(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
virtual unsigned char const * GetRawRecordData(uint32 recordNumber, uint32 const *section) const =0
virtual void RecordDestroyFieldOffsets(std::size_t *&fieldOffsets) const =0
virtual char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, uint32 locale)=0
virtual uint16 RecordGetUInt16(uint8 const *record, uint32 field, uint32 arrayIndex) const =0
DB2FileLoaderImpl & operator=(DB2FileLoaderImpl const &other)=delete
DB2FileLoaderImpl & operator=(DB2FileLoaderImpl &&other) noexcept=delete
std::unique_ptr< DB2ColumnMeta[]> _columnMeta
void FillParentLookup(char *dataTable)
char * AutoProduceData(uint32 &indexTableSize, char **&indexTable) override
DB2FileLoadInfo const * _loadInfo
uint64 RecordGetPackedValue(uint8 const *packedRecordData, uint32 bitWidth, uint32 bitOffset) const
DB2FileLoaderRegularImpl(char const *fileName, DB2FileLoadInfo const *loadInfo, DB2Header const *header)
DB2FileLoaderRegularImpl & operator=(DB2FileLoaderRegularImpl &&other) noexcept=delete
DB2Header const * _header
uint32 GetRecordSection(uint32 recordNumber) const
DB2SectionHeader & GetSection(uint32 section) const override
std::size_t * RecordCreateDetachedFieldOffsets(std::size_t *oldOffsets) const override
bool LoadCatalogData(DB2FileSource *, uint32) override
std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> _palletArrayValues
uint32 GetMaxId() const override
uint8 RecordGetUInt8(uint8 const *record, uint32 field, uint32 arrayIndex) const override
unsigned char const * GetRawRecordData(uint32 recordNumber, uint32 const *section) const override
uint32 GetRecordCopyCount() const override
std::unique_ptr< DB2SectionHeader[]> _sections
uint32 RecordGetUInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
float RecordGetFloat(uint8 const *record, uint32 field, uint32 arrayIndex) const override
void SkipEncryptedSection(uint32) override
void SetAdditionalData(std::vector< uint32 > idTable, std::vector< DB2RecordCopy > copyTable, std::vector< std::vector< DB2IndexData > > parentIndexes) override
void LoadColumnData(std::unique_ptr< DB2SectionHeader[]> sections, std::unique_ptr< DB2FieldEntry[]> fields, std::unique_ptr< DB2ColumnMeta[]> columnMeta, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletValues, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletArrayValues, std::unique_ptr< std::unordered_map< uint32, uint32 >[]> commonValues) override
char const * RecordGetString(uint8 const *record, uint32 field, uint32 arrayIndex) const override
void RecordDestroyFieldOffsets(std::size_t *&fieldOffsets) const override
std::vector< DB2RecordCopy > _copyTable
std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> _palletValues
DB2Record GetRecord(uint32 recordNumber) const override
std::unique_ptr< uint8[]> _data
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override
DB2FileLoaderRegularImpl & operator=(DB2FileLoaderRegularImpl const &other)=delete
DB2FileLoadInfo const * GetLoadInfo() const override
uint32 RecordGetId(uint8 const *record, uint32 recordIndex) const override
char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, uint32 locale) override
uint16 GetFieldOffset(uint32 field) const
uint64 RecordGetUInt64(uint8 const *record, uint32 field, uint32 arrayIndex) const override
DB2FileLoaderRegularImpl(DB2FileLoaderRegularImpl const &other)=delete
std::vector< std::vector< DB2IndexData > > _parentIndexes
uint32 GetRecordCount() const override
void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable) override
std::size_t * RecordCopyDetachedFieldOffsets(std::size_t *oldOffsets) const override
DB2FileLoaderRegularImpl(DB2FileLoaderRegularImpl &&other) noexcept=delete
int32 RecordGetInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
std::vector< uint32 > _idTable
std::unique_ptr< std::unordered_map< uint32, uint32 >[]> _commonValues
uint16 RecordGetUInt16(uint8 const *record, uint32 field, uint32 arrayIndex) const override
bool LoadTableData(DB2FileSource *source, uint32 section) override
uint32 GetMinId() const override
T RecordGetVarInt(uint8 const *record, uint32 field, uint32 arrayIndex) const
std::unique_ptr< uint8[]> _recordBuffer
DB2FileSource *const _source
void FillParentLookup(char *dataTable)
void CalculateAndStoreFieldOffsets(uint8 const *rawRecord) const
DB2FileLoaderSparseImpl(DB2FileLoaderSparseImpl const &other)=delete
bool LoadTableData(DB2FileSource *, uint32) override
void RecordDestroyFieldOffsets(std::size_t *&fieldOffsets) const override
DB2FileLoadInfo const * _loadInfo
std::vector< DB2RecordCopy > _copyTable
DB2SectionHeader & GetSection(uint32 section) const override
uint32 GetRecordSection(uint32 recordNumber) const
uint32 GetMinId() const override
std::vector< std::vector< DB2IndexData > > _parentIndexes
uint32 GetMaxId() const override
std::unique_ptr< DB2FieldEntry[]> _fields
unsigned char const * GetRawRecordData(uint32 recordNumber, uint32 const *section) const override
DB2Record GetRecord(uint32 recordNumber) const override
uint32 GetRecordCopyCount() const override
char * AutoProduceData(uint32 &indexTableSize, char **&indexTable) override
char const * RecordGetString(uint8 const *record, uint32 field, uint32 arrayIndex) const override
DB2FileLoaderSparseImpl(char const *fileName, DB2FileLoadInfo const *loadInfo, DB2Header const *header, DB2FileSource *source)
void SkipEncryptedSection(uint32 section) override
uint32 RecordGetVarInt(uint8 const *record, uint32 field, uint32 arrayIndex, bool isSigned) const
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const override
float RecordGetFloat(uint8 const *record, uint32 field, uint32 arrayIndex) const override
uint64 RecordGetUInt64(uint8 const *record, uint32 field, uint32 arrayIndex) const override
bool LoadCatalogData(DB2FileSource *source, uint32 section) override
DB2FileLoaderSparseImpl(DB2FileLoaderSparseImpl &&other) noexcept=delete
uint32 RecordGetId(uint8 const *record, uint32 recordIndex) const override
uint32 RecordGetUInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
DB2Header const * _header
DB2FileLoadInfo const * GetLoadInfo() const override
DB2FileLoaderSparseImpl & operator=(DB2FileLoaderSparseImpl const &other)=delete
std::unique_ptr< DB2SectionHeader[]> _sections
std::size_t * RecordCopyDetachedFieldOffsets(std::size_t *oldOffsets) const override
DB2FileLoaderSparseImpl & operator=(DB2FileLoaderSparseImpl &&other) noexcept=delete
std::unique_ptr< std::size_t[]> _fieldAndArrayOffsets
void SetAdditionalData(std::vector< uint32 > idTable, std::vector< DB2RecordCopy > copyTable, std::vector< std::vector< DB2IndexData > > parentIndexes) override
std::vector< DB2CatalogEntry > _catalog
std::vector< uint32 > _catalogIds
uint16 GetFieldOffset(uint32 field, uint32 arrayIndex) const
uint8 RecordGetUInt8(uint8 const *record, uint32 field, uint32 arrayIndex) const override
int32 RecordGetInt32(uint8 const *record, uint32 field, uint32 arrayIndex) const override
std::size_t * RecordCreateDetachedFieldOffsets(std::size_t *oldOffsets) const override
void LoadColumnData(std::unique_ptr< DB2SectionHeader[]> sections, std::unique_ptr< DB2FieldEntry[]> fields, std::unique_ptr< DB2ColumnMeta[]> columnMeta, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletValues, std::unique_ptr< std::unique_ptr< DB2PalletValue[]>[]> palletArrayValues, std::unique_ptr< std::unordered_map< uint32, uint32 >[]> commonValues) override
uint16 GetFieldSize(uint32 field) const
uint32 GetRecordCount() const override
uint16 RecordGetUInt16(uint8 const *record, uint32 field, uint32 arrayIndex) const override
char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, uint32 locale) override
void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable) override
DB2Header _header
uint32 GetMaxId() const
uint32 GetMinId() const
void Load(DB2FileSource *source, DB2FileLoadInfo const *loadInfo)
DB2Record GetRecord(uint32 recordNumber) const
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const
char * AutoProduceData(uint32 &indexTableSize, char **&indexTable)
char * AutoProduceStrings(char **indexTable, uint32 indexTableSize, LocaleConstant locale)
void LoadHeaders(DB2FileSource *source, DB2FileLoadInfo const *loadInfo)
DB2SectionHeader const & GetSectionHeader(uint32 section) const
uint32 GetRecordCopyCount() const
DB2FileLoaderImpl * _impl
void AutoProduceRecordCopies(uint32 records, char **indexTable, char *dataTable)
uint32 GetRecordCount() const
uint64 GetUInt64(uint32 field, uint32 arrayIndex) const
float GetFloat(uint32 field, uint32 arrayIndex) const
DB2Record(DB2FileLoaderImpl const &db2, uint32 recordIndex, std::size_t *fieldOffsets)
DB2FileLoaderImpl const & _db2
int32 GetInt32(uint32 field, uint32 arrayIndex) const
std::size_t * _fieldOffsets
uint32 GetUInt32(uint32 field, uint32 arrayIndex) const
uint16 GetUInt16(uint32 field, uint32 arrayIndex) const
uint8 GetUInt8(uint32 field, uint32 arrayIndex) const
uint32 GetId() const
char const * GetString(uint32 field, uint32 arrayIndex) const
unsigned char const * _recordData
uint32 _recordIndex
void MakePersistent()
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
STL namespace.
struct DB2ColumnMeta::@1::@2 immediate
union DB2ColumnMeta::@1 CompressionData
DB2ColumnCompression CompressionType
struct DB2ColumnMeta::@1::@3 commonData
uint32 AdditionalDataSize
struct DB2ColumnMeta::@1::@4 pallet
char const * Name
DBCFormer Type
std::size_t FieldCount
std::pair< int32, int32 > GetFieldIndexByName(char const *fieldName) const
DB2Meta const * Meta
uint32 GetStringFieldCount(bool localizedOnly) const
int32 GetFieldIndexByMetaIndex(uint32 metaIndex) const
DB2FieldMeta const * Fields
virtual int64 GetFileSize() const =0
virtual DB2EncryptedSectionHandling HandleEncryptedSection(DB2SectionHeader const &sectionHeader) const =0
virtual char const * GetFileName() const =0
virtual bool IsOpen() const =0
virtual bool SetPosition(int64 position)=0
virtual ~DB2FileSource()
virtual bool Read(void *buffer, std::size_t numBytes)=0
virtual int64 GetPosition() const =0
uint32 TotalFieldCount
uint32 SectionCount
uint32 RecordCount
uint32 PackedDataOffset
uint32 CommonDataSize
uint32 StringTableSize
uint32 MaxId
uint32 PalletDataSize
uint32 ColumnMetaSize
uint32 Signature
uint16 Flags
uint32 TableHash
uint32 FieldCount
uint32 LayoutHash
uint32 RecordSize
int16 IndexField
uint32 ParentLookupCount
uint32 MinId
uint32 Version
uint32 Locale
std::vector< DB2IndexEntry > Entries
uint8 ArraySize
Definition DB2Meta.h:26
DBCFormer Type
Definition DB2Meta.h:25
uint32 FileFieldCount
Definition DB2Meta.h:52
int32 IndexField
Definition DB2Meta.h:49
DB2MetaField const * Fields
Definition DB2Meta.h:54
uint32 GetIndexField() const
Definition DB2Meta.cpp:27
uint32 GetRecordSize() const
Definition DB2Meta.cpp:32
bool HasIndexFieldInData() const
Definition DB2Meta.cpp:22
uint32 GetIndexFieldOffset() const
Definition DB2Meta.cpp:79
uint32 FieldCount
Definition DB2Meta.h:51
uint32 LayoutHash
Definition DB2Meta.h:53
bool IsSignedField(uint32 field) const
Definition DB2Meta.cpp:195
int32 ParentIndexField
Definition DB2Meta.h:50
int32 GetParentIndexFieldOffset() const
Definition DB2Meta.cpp:127
uint32 ParentLookupDataSize
std::array< char const *, TOTAL_LOCALES > Str
Definition Common.h:112