Skip to content

Commit

Permalink
AURORA: Restructure GFF3List handling
Browse files Browse the repository at this point in the history
The GFF3List is now its own class instead of a typedef to a
std::vector. Like the GFF3Struct, it now also carries a UID that's
unique to the GFF3.
  • Loading branch information
DrMcCoy committed Mar 3, 2016
1 parent 4fbd7d8 commit 3469bbc
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 28 deletions.
101 changes: 79 additions & 22 deletions src/aurora/gff3file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ void GFF3File::Header::read(Common::SeekableReadStream &gff3) {


GFF3File::GFF3File(Common::SeekableReadStream *gff3, uint32 id, bool repairNWNPremium) :
_stream(gff3), _repairNWNPremium(repairNWNPremium), _offsetCorrection(0), _nextStructUID(0) {
_stream(gff3), _repairNWNPremium(repairNWNPremium), _offsetCorrection(0),
_nextStructUID(0), _nextListUID(0) {

load(id);
}
Expand Down Expand Up @@ -240,19 +241,20 @@ void GFF3File::loadLists() {
listCount++;
}

_lists.resize(listCount);
_listOffsetToIndex.resize(rawLists.size(), 0xFFFFFFFF);
_listOffsetToUID.resize(rawLists.size(), 0xFFFFFFFF);

// Converting the raw list array into real, usable lists
uint32 listIndex = 0;
for (size_t i = 0; i < rawLists.size(); listIndex++) {
_listOffsetToIndex[i] = listIndex;
for (size_t i = 0; i < rawLists.size(); ) {
const uint32 listUID = _nextListUID++;

_listOffsetToUID[i] = listUID;

const uint32 n = rawLists[i++];
if ((i + n) > rawLists.size())
throw Common::Exception("GFF3: List indices broken during conversion");

_lists[listIndex].resize(n);
std::vector<const GFF3Struct *> list(n);

for (uint32 j = 0; j < n; j++, i++) {
const uint32 structUID = rawLists[i];

Expand All @@ -261,13 +263,33 @@ void GFF3File::loadLists() {
throw Common::Exception("GFF3: List struct UID doesn't exist (%u, %u)",
structUID, _nextStructUID);

_lists[listIndex][j] = strct->second;
list[j] = strct->second;
}

_lists.insert(std::make_pair(listUID, GFF3List(*this, listUID, list)));
}
}

// --- Helpers for GFF3Struct ---

uint32 GFF3File::getListUID(uint32 offset) const {
if ((offset % 4) != 0)
throw Common::Exception("GFF3: Invalid list offset");

offset /= 4;

if (offset >= _listOffsetToUID.size())
throw Common::Exception("GFF3: List offset out of range (%u >= %u)",
offset, (uint) _listOffsetToUID.size());

const uint32 listUID = _listOffsetToUID[offset];

if (listUID == 0xFFFFFFFF)
throw Common::Exception("GFF3: Empty list at %u", offset);

return listUID;
}

const GFF3Struct &GFF3File::getStruct(uint32 uid) const {
StructMap::const_iterator strct = _structs.find(uid);
if ((strct == _structs.end()) || !strct->second)
Expand All @@ -276,19 +298,12 @@ const GFF3Struct &GFF3File::getStruct(uint32 uid) const {
return *strct->second;
}

const GFF3List &GFF3File::getList(uint32 i) const {
if (i >= _listOffsetToIndex.size())
throw Common::Exception("GFF3: List offset index out of range (%u >= %u)",
i, (uint) _listOffsetToIndex.size());
const GFF3List &GFF3File::getList(uint32 uid) const {
ListMap::const_iterator list = _lists.find(uid);
if (list == _lists.end())
throw Common::Exception("GFF3: List UID doesn't exist (%u)", uid);

const uint32 listIndex = _listOffsetToIndex[i];

if (listIndex == 0xFFFFFFFF)
throw Common::Exception("GFF3: Empty list index at %u", i);

assert(listIndex < _lists.size());

return _lists[listIndex];
return list->second;
}

Common::SeekableReadStream &GFF3File::getStream(uint32 offset) const {
Expand Down Expand Up @@ -783,8 +798,9 @@ const GFF3List &GFF3Struct::getList(const Common::UString &field) const {
if (f->type != kFieldTypeList)
throw Common::Exception("GFF3: Field is not a list type");

// Byte offset into the list area, all 32bit values.
return _parent->getList(f->data / 4);
const uint32 uid = f->ownData ? f->data : _parent->getListUID(f->data);

return _parent->getList(uid);
}

// --- Field adding and deleting ---
Expand Down Expand Up @@ -1118,4 +1134,45 @@ void GFF3Struct::setString(const Common::UString &field, Common::SeekableReadStr
}
}


GFF3List::GFF3List(const GFF3File &parent, uint32 uid, const std::vector<const GFF3Struct *> &list) :
_parent(&parent), _uid(uid), _list(list) {

}

GFF3List::~GFF3List() {
}

uint32 GFF3List::getUID() const {
return _uid;
}

bool GFF3List::empty() const {
return _list.empty();
}

size_t GFF3List::size() const {
return _list.size();
}

GFF3List::const_iterator GFF3List::begin() const {
return _list.begin();
}

GFF3List::const_iterator GFF3List::end() const {
return _list.end();
}

GFF3List::const_reverse_iterator GFF3List::rbegin() const {
return _list.rbegin();
}

GFF3List::const_reverse_iterator GFF3List::rend() const {
return _list.rend();
}

const GFF3Struct *GFF3List::operator[](size_t i) const {
return _list[i];
}

} // End of namespace Aurora
52 changes: 47 additions & 5 deletions src/aurora/gff3file.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace Aurora {

class LocString;
class GFF3Struct;
class GFF3List;

/** A GFF (generic file format) V3.2/V3.3 file, found in all Aurora games
* except Sonic Chronicles: The Dark Brotherhood. Even games that have
Expand Down Expand Up @@ -115,7 +116,7 @@ class GFF3File : public AuroraFile {
};

typedef std::map<uint32, GFF3Struct *> StructMap;
typedef std::vector<GFF3List> ListArray;
typedef std::map<uint32, GFF3List > ListMap;


Common::SeekableReadStream *_stream;
Expand All @@ -128,13 +129,15 @@ class GFF3File : public AuroraFile {
uint32 _offsetCorrection;

StructMap _structs; ///< Our structs.
ListArray _lists; ///< Our lists.
ListMap _lists; ///< Our lists.

/** To convert list offsets found in GFF3 to real indices. */
std::vector<uint32> _listOffsetToIndex;
/** To convert list offsets found in GFF3 to list UIDs. */
std::vector<uint32> _listOffsetToUID;

/** The unique ID to give the next struct. */
uint32 _nextStructUID;
/** The unique ID to give the next list. */
uint32 _nextListUID;


// .--- Loading helpers
Expand All @@ -152,10 +155,13 @@ class GFF3File : public AuroraFile {
/** Return the GFF3 stream seeked to the start of the field data. */
Common::SeekableReadStream &getFieldData() const;

/** Return the list UID from a list offset found in a GFF3 field. */
uint32 getListUID(uint32 offset) const;

/** Return a struct within the GFF3. */
const GFF3Struct &getStruct(uint32 uid) const;
/** Return a list within the GFF3. */
const GFF3List &getList (uint32 i) const;
const GFF3List &getList (uint32 uid) const;
// '---

friend class GFF3Struct;
Expand Down Expand Up @@ -354,6 +360,42 @@ class GFF3Struct {
friend class GFF3File;
};

class GFF3List {
public:
typedef std::vector<const GFF3Struct *>::const_iterator const_iterator;
typedef std::vector<const GFF3Struct *>::const_reverse_iterator const_reverse_iterator;

~GFF3List();

/** Return the list's unique ID within the GFF3. */
uint32 getUID() const;

bool empty() const;
size_t size() const;

const_iterator begin() const;
const_iterator end() const;

const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;

const GFF3Struct *operator[](size_t i) const;


private:
const GFF3File *_parent; ///< The parent GFF3.

uint32 _uid; ///< The lists's unique ID within the GFF3.

/** The actual list of GFF3Structs. */
std::vector<const GFF3Struct *> _list;


GFF3List(const GFF3File &parent, uint32 uid, const std::vector<const GFF3Struct *> &list);

friend class GFF3File;
};

} // End of namespace Aurora

#endif // AURORA_GFF3FILE_H
2 changes: 1 addition & 1 deletion src/aurora/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ class TwoDAFile;
class TwoDARow;

class GFF3Struct;
typedef std::vector<const GFF3Struct *> GFF3List;
class GFF3List;
class GFF3File;

class GFF4Struct;
Expand Down

0 comments on commit 3469bbc

Please sign in to comment.