xoreos  0.0.5
gff3writer.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <algorithm>
26 
27 #include <boost/make_shared.hpp>
28 
29 #include "src/common/writestream.h"
31 
32 #include "src/aurora/gff3writer.h"
33 
34 namespace Aurora {
35 
36 GFF3Writer::GFF3Writer(uint32 id, uint32 version) : _id(id), _version(version) {
37  _structs.push_back(boost::make_shared<GFF3WriterStruct>(this));
38 }
39 
41  return _structs[0];
42 }
43 
45  stream.writeUint32BE(_id);
46  stream.writeUint32BE(_version);
47 
48  uint32 structOffset = 56; // ID + version + header
49  uint32 structCount = static_cast<uint32>(_structs.size());
50 
51  uint32 fieldOffset = structOffset + structCount * 12;
52  uint32 fieldCount = static_cast<uint32>(_fields.size());
53 
54  uint32 labelOffset = fieldOffset + fieldCount * 12;
55  uint32 labelCount = static_cast<uint32>(_labels.size());
56 
57  uint32 fieldDataOffset = labelOffset + labelCount * 16;
58  uint32 fieldDataCount = 0;
59 
60  // Count the total size of field data
61  for (size_t i = 0; i < _fields.size(); ++i)
62  fieldDataCount += getFieldDataSize(_fields[i]);
63 
64  uint32 fieldIndicesOffset = fieldDataOffset + fieldDataCount;
65  uint32 fieldIndicesCount = 0;
66 
67  // Count all fields of structs with more than one field
68  for (size_t i = 0; i < _structs.size(); ++i) {
69  const GFF3WriterStructPtr strct = _structs[i];
70  if (strct->getFieldCount() <= 1)
71  continue;
72 
73  fieldIndicesCount += strct->getFieldCount() * 4;
74  }
75 
76  uint32 listIndicesOffset = fieldIndicesOffset + fieldIndicesCount;
77  uint32 listIndicesCount = 0;
78 
79  // Count all lists elements plus their size as int
80  for (size_t i = 0; i < _lists.size(); ++i) {
81  listIndicesCount += (_lists[i]->getSize() + 1) * 4;
82  }
83 
84  // Write the header
85  stream.writeUint32LE(structOffset);
86  stream.writeUint32LE(structCount);
87  stream.writeUint32LE(fieldOffset);
88  stream.writeUint32LE(fieldCount);
89  stream.writeUint32LE(labelOffset);
90  stream.writeUint32LE(labelCount);
91  stream.writeUint32LE(fieldDataOffset);
92  stream.writeUint32LE(fieldDataCount);
93  stream.writeUint32LE(fieldIndicesOffset);
94  stream.writeUint32LE(fieldIndicesCount);
95  stream.writeUint32LE(listIndicesOffset);
96  stream.writeUint32LE(listIndicesCount);
97 
98  // Write structs data
99  size_t structFieldIndicesIndex = 0;
100  for (size_t i = 0; i < _structs.size(); ++i) {
101  GFF3WriterStructPtr strct = _structs[i];
102 
103  // Struct ID
104  stream.writeUint32LE(strct->getID());
105 
106  // Field index
107  if (strct->getFieldCount() > 1) {
108  stream.writeUint32LE(structFieldIndicesIndex * 4);
109  structFieldIndicesIndex += strct->getFieldCount();
110  } else {
111  if (strct->getFieldCount() != 0)
112  stream.writeUint32LE(strct->_fieldIndices[0]);
113  else
114  stream.writeUint32LE(0);
115  }
116 
117  // Field count
118  stream.writeUint32LE(strct->getFieldCount());
119  }
120 
121  // Write fields
122  size_t fieldDataIndex = 0;
123  size_t listDataIndex = 0;
124  for (size_t i = 0; i < _fields.size(); ++i) {
125  FieldPtr field = _fields[i];
126  stream.writeUint32LE(field->type);
127  stream.writeUint32LE(field->labelIndex);
128 
129  /* Determine if this field has simple values (less equal 32 bit) which are written in the field
130  * or complex values, bigger than 32bit like strings written in the field data section. */
131  const bool simple =
132  field->type == GFF3Struct::kFieldTypeByte ||
133  field->type == GFF3Struct::kFieldTypeChar ||
134  field->type == GFF3Struct::kFieldTypeUint16 ||
135  field->type == GFF3Struct::kFieldTypeUint32 ||
136  field->type == GFF3Struct::kFieldTypeStruct ||
137  field->type == GFF3Struct::kFieldTypeSint16 ||
138  field->type == GFF3Struct::kFieldTypeSint32 ||
139  field->type == GFF3Struct::kFieldTypeFloat ||
140  field->type == GFF3Struct::kFieldTypeList;
141 
142  if (simple) {
143  // If the values are simple (less equal 4 bytes) write them to the field
144  switch (field->type) {
149  stream.writeUint32LE(field->uint32Value);
150  break;
152  stream.writeUint32LE(listDataIndex * 4);
153  listDataIndex += 1 + _lists[field->uint32Value]->getSize();
154  break;
158  stream.writeSint32LE(field->int32Value);
159  break;
161  stream.writeIEEEFloatLE(field->floatValue);
162  break;
163  default:
164  throw Common::Exception("Invalid Field type");
165  }
166  } else {
167  // If the values are complex (greater then 4 bytes) write the index to the field data
168  stream.writeUint32LE(fieldDataIndex);
169  fieldDataIndex += getFieldDataSize(field);
170  }
171  }
172 
173  // Write labels
174  for (size_t i = 0; i < _labels.size(); ++i) {
175  const Common::UString &label = _labels[i];
176  stream.write(label.c_str(), MIN<size_t>(label.size(), 16));
177  stream.writeZeros(16 - MIN<size_t>(label.size(), 16));
178  }
179 
180  // Write field data
181  for (size_t i = 0; i < _fields.size(); ++i) {
182  FieldPtr field = _fields[i];
183  switch (field->type) {
185  stream.writeUint64LE(field->uint64Value);
186  break;
188  stream.writeSint64LE(field->int64Value);
189  break;
191  stream.writeIEEEDoubleLE(field->doubleValue);
192  break;
194  stream.writeUint32LE(4);
195  stream.writeUint32LE(field->uint32Value);
196  break;
198  stream.writeByte(MIN<byte>(16, field->stringValue.size()));
199  stream.write(field->stringValue.c_str(), MIN<size_t>(field->stringValue.size(), 16));
200  break;
202  stream.writeUint32LE(static_cast<uint32>(field->stringValue.size()));
203  stream.writeString(field->stringValue);
204  break;
206  stream.writeUint32LE(field->locStringValue.getWrittenSize() + 8);
207  stream.writeUint32LE(field->locStringValue.getID());
208  stream.writeUint32LE(field->locStringValue.getNumStrings());
209  field->locStringValue.writeLocString(stream);
210  break;
212  stream.writeUint32LE(static_cast<uint32>(field->voidSize));
213  stream.write(field->voidData.get(), field->voidSize);
214  break;
216  stream.writeIEEEFloatLE(field->vectorValue.x);
217  stream.writeIEEEFloatLE(field->vectorValue.y);
218  stream.writeIEEEFloatLE(field->vectorValue.z);
219  break;
221  stream.writeIEEEFloatLE(field->vectorValue.x);
222  stream.writeIEEEFloatLE(field->vectorValue.y);
223  stream.writeIEEEFloatLE(field->vectorValue.z);
224  stream.writeIEEEFloatLE(field->vectorValue.w);
225  break;
226  default:
227  break;
228  }
229  }
230 
231  // Write field indices of every struct with more than one field
232  for (size_t i = 0; i < _structs.size(); ++i) {
233  GFF3WriterStructPtr strct = _structs[i];
234  if (strct->getFieldCount() <= 1)
235  continue;
236 
237  for (size_t j = 0; j < strct->getFieldCount(); ++j) {
238  stream.writeUint32LE(strct->_fieldIndices[j]);
239  }
240  }
241 
242  // Write list indices
243  for (size_t i = 0; i < _lists.size(); ++i) {
244  GFF3WriterListPtr list = _lists[i];
245  stream.writeUint32LE(list->getSize());
246  for (size_t j = 0; j < list->_strcts.size(); ++j) {
247  stream.writeUint32LE(list->_strcts[j]);
248  }
249  }
250 }
251 
253  std::vector<Common::UString>::iterator iter = std::find(_labels.begin(), _labels.end(), label);
254  if (iter != _labels.end()) {
255  return static_cast<uint32>(std::distance(_labels.begin(), iter));
256  } else {
257  _labels.push_back(label);
258  return static_cast<uint32>(_labels.size() - 1);
259  }
260 }
261 
263  switch (field->type) {
268  return 8;
270  return 4 + field->stringValue.size();
272  return 12 + field->locStringValue.getWrittenSize();
274  return 1 + field->stringValue.size();
276  return 12;
278  return 16;
280  return 4 + field->voidSize;
281  default:
282  return 0;
283  }
284 }
285 
287  // Create a field index
288  size_t index = _fields.size();
289 
290  // Create field
291  GFF3Writer::FieldPtr field = boost::make_shared<Field>();
292  field->type = type;
293  field->labelIndex = addLabel(label);
294  _fields.push_back(field);
295 
296  return index;
297 }
298 
300  // Create the structure pointer
301  GFF3WriterStructPtr strct(
302  boost::make_shared<GFF3WriterStruct>(_parent, static_cast<uint32>(_parent->_structs.size()) - 1));
303 
304  // Create a field index
305  _strcts.push_back(_parent->_structs.size());
306  GFF3Writer::FieldPtr field = boost::make_shared<GFF3Writer::Field>();
307  field->type = GFF3Struct::kFieldTypeStruct;
308  field->uint32Value = static_cast<uint32>(_parent->_structs.size());
309 
310  // Add the label
311  field->labelIndex = _parent->addLabel(label);
312 
313  // Insert the newly created struct into the struct vector
314  _parent->_structs.push_back(strct);
315 
316  // Insert the struct to the field vector
317  _parent->_fields.push_back(field);
318 
319  return strct;
320 }
321 
322 size_t GFF3WriterList::getSize() const {
323  return _strcts.size();
324 }
325 
326 GFF3WriterList::GFF3WriterList(GFF3Writer *parent) : _parent(parent) {
327 }
328 
330  return _id;
331 }
332 
334  return _fieldIndices.size();
335 }
336 
338  // Create the structure pointer
339  GFF3WriterStructPtr strct(
340  boost::make_shared<GFF3WriterStruct>(_parent, static_cast<uint32>(_parent->_structs.size()) - 1));
341 
342  // Create a field index
343  _fieldIndices.push_back(_parent->_fields.size());
344  GFF3Writer::FieldPtr field = boost::make_shared<GFF3Writer::Field>();
345  field->type = GFF3Struct::kFieldTypeStruct;
346  field->uint32Value = static_cast<uint32>(_parent->_structs.size());
347 
348  // Add the label
349  field->labelIndex = _parent->addLabel(label);
350 
351  // Insert the newly created struct into the struct vector
352  _parent->_structs.push_back(strct);
353 
354  // Insert the struct to the field vector
355  _parent->_fields.push_back(field);
356 
357  return strct;
358 }
359 
361  // Create the list pointer
362  GFF3WriterListPtr strct(boost::make_shared<GFF3WriterList>(_parent));
363 
364  // Create a field index
365  _fieldIndices.push_back(_parent->_fields.size());
366  GFF3Writer::FieldPtr field = boost::make_shared<GFF3Writer::Field>();
367  field->type = GFF3Struct::kFieldTypeList;
368  field->uint32Value = static_cast<uint32>(_parent->_lists.size());
369 
370  // Add the label
371  field->labelIndex = _parent->addLabel(label);
372 
373  // Insert the newly created list into the lists vector
374  _parent->_lists.push_back(strct);
375 
376  // Insert the list to the field vector
377  _parent->_fields.push_back(field);
378 
379  return strct;
380 }
381 
382 void GFF3WriterStruct::addByte(const Common::UString &label, byte value) {
383  createField(GFF3Struct::kFieldTypeByte, label)->uint32Value = value;
384 }
385 
386 void GFF3WriterStruct::addChar(const Common::UString &label, char value) {
387  createField(GFF3Struct::kFieldTypeChar, label)->int32Value = value;
388 }
389 
390 void GFF3WriterStruct::addFloat(const Common::UString &label, float value) {
391  createField(GFF3Struct::kFieldTypeFloat, label)->floatValue = value;
392 }
393 
394 void GFF3WriterStruct::addDouble(const Common::UString &label, double value) {
395  createField(GFF3Struct::kFieldTypeDouble, label)->doubleValue = value;
396 }
397 
399  createField(GFF3Struct::kFieldTypeUint16, label)->uint32Value = value;
400 }
401 
403  createField(GFF3Struct::kFieldTypeUint32, label)->uint32Value = value;
404 }
405 
407  createField(GFF3Struct::kFieldTypeUint64, label)->uint64Value = value;
408 }
409 
411  createField(GFF3Struct::kFieldTypeSint16, label)->int32Value = value;
412 }
413 
415  createField(GFF3Struct::kFieldTypeSint32, label)->int32Value = value;
416 }
417 
419  createField(GFF3Struct::kFieldTypeSint64, label)->int64Value = value;
420 }
421 
423  createField(GFF3Struct::kFieldTypeExoString, label)->stringValue = value;
424 }
425 
427  createField(GFF3Struct::kFieldTypeStrRef, label)->uint32Value = value;
428 }
429 
431  createField(GFF3Struct::kFieldTypeResRef, label)->stringValue = value;
432 }
433 
434 void GFF3WriterStruct::addVoid(const Common::UString &label, const byte *data, uint32 size) {
436  field->voidData.reset(new byte[size]);
437  field->voidSize = size;
438  memcpy(field->voidData.get(), data, size);
439 }
440 
441 void GFF3WriterStruct::addVector(const Common::UString &label, glm::vec3 value) {
442  createField(GFF3Struct::kFieldTypeVector, label)->vectorValue = glm::vec4(value, 0.0f);
443 }
444 
445 void GFF3WriterStruct::addOrientation(const Common::UString &label, glm::vec4 value) {
446  createField(GFF3Struct::kFieldTypeOrientation, label)->vectorValue = value;
447 }
448 
449 void GFF3WriterStruct::addLocString(const Common::UString &label, const LocString &value) {
450  createField(GFF3Struct::kFieldTypeLocString, label)->locStringValue = value;
451 }
452 
454  size_t index = _parent->createField(type, label);
455  _fieldIndices.push_back(index);
456  return _parent->_fields.back();
457 }
458 
459 GFF3WriterStruct::GFF3WriterStruct(GFF3Writer *parent, uint32 id) : _id(id), _parent(parent) {
460 }
461 
462 } // End of namespace Aurora
A single character.
Definition: gff3file.h:170
void addOrientation(const Common::UString &label, glm::vec4 value)
Add a new Orientation.
Definition: gff3writer.cpp:445
A class holding an UTF-8 string.
Definition: ustring.h:48
A localized string.
Definition: locstring.h:43
void writeString(const UString &str)
Write the given string to the stream, encoded as UTF-8.
Definition: writestream.cpp:94
GFF3WriterStruct(GFF3Writer *parent, uint32 id=0xFFFFFFFF)
Definition: gff3writer.cpp:459
uint64_t uint64
Definition: types.h:206
boost::shared_ptr< Field > FieldPtr
Definition: gff3writer.h:82
GFF3WriterListPtr addList(const Common::UString &label)
Create a new list.
Definition: gff3writer.cpp:360
void addVoid(const Common::UString &label, const byte *data, uint32 size)
Add new void data.
Definition: gff3writer.cpp:434
Unsigned 16bit integer.
Definition: gff3file.h:171
String reference, index into a talk table.
Definition: gff3file.h:187
Implementing the reading stream interfaces for plain memory blocks.
size_t getSize() const
Definition: gff3writer.cpp:322
size_t createField(GFF3Struct::FieldType type, const Common::UString &label)
Definition: gff3writer.cpp:286
Writer for writing version V3.2/V3.3 of BioWare&#39;s GFFs (generic file format).
FORCEINLINE void writeSint32LE(int32 value)
Definition: writestream.h:151
void writeUint64LE(uint64 value)
Definition: writestream.h:110
boost::shared_ptr< GFF3WriterStruct > GFF3WriterStructPtr
Definition: gff3writer.h:41
void addFloat(const Common::UString &label, float value)
Add a new float.
Definition: gff3writer.cpp:390
GFF3WriterList(GFF3Writer *parent)
Definition: gff3writer.cpp:326
int16_t int16
Definition: types.h:201
void addChar(const Common::UString &label, char value)
Add a new char.
Definition: gff3writer.cpp:386
FieldType
The type of a GFF3 field.
Definition: gff3file.h:167
void addResRef(const Common::UString &label, const Common::UString &value)
Add a new Resource reference.
Definition: gff3writer.cpp:430
std::vector< Common::UString > _labels
Definition: gff3writer.h:90
void addStrRef(const Common::UString &label, uint32 value)
Add a new String reference.
Definition: gff3writer.cpp:426
void addLocString(const Common::UString &label, const LocString &value)
Add a new LocString.
Definition: gff3writer.cpp:449
FORCEINLINE void writeIEEEDoubleLE(double value)
Definition: writestream.h:179
A vector of 3 floats.
Definition: gff3file.h:186
GFF3WriterStructPtr addStruct(const Common::UString &label)
Create a new struct.
Definition: gff3writer.cpp:337
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
GFF3WriterStructPtr addStruct(const Common::UString &label)
Add a new struct to the list.
Definition: gff3writer.cpp:299
void addExoString(const Common::UString &label, const Common::UString &value)
Add a new ExoString.
Definition: gff3writer.cpp:422
uint16_t uint16
Definition: types.h:202
std::vector< size_t > _strcts
Definition: gff3writer.h:119
Unsigned 64bit integer.
Definition: gff3file.h:175
Random data of variable length.
Definition: gff3file.h:182
void addSint16(const Common::UString &label, int16 value)
Add a new sint16.
Definition: gff3writer.cpp:410
FORCEINLINE void writeSint64LE(int64 value)
Definition: writestream.h:155
uint32 addLabel(const Common::UString &label)
Adds a label to the writer and returns the corresponding index.
Definition: gff3writer.cpp:252
void write(Common::WriteStream &stream)
Write the GFF3 to stream.
Definition: gff3writer.cpp:44
Basic writing stream interfaces.
void addUint64(const Common::UString &label, uint64 value)
Add a new uint64.
Definition: gff3writer.cpp:406
Signed 16bit integer.
Definition: gff3file.h:172
Signed 64bit integer.
Definition: gff3file.h:176
StackException Exception
Definition: error.h:59
void addVector(const Common::UString &label, glm::vec3 value)
Add a new Vector.
Definition: gff3writer.cpp:441
virtual size_t write(const void *dataPtr, size_t dataSize)=0
Write data into the stream.
void writeByte(byte value)
Definition: writestream.h:88
std::vector< GFF3WriterListPtr > _lists
Definition: gff3writer.h:88
Generic interface for a writable data stream.
Definition: writestream.h:64
int64_t int64
Definition: types.h:205
void addByte(const Common::UString &label, byte value)
Add a new byte.
Definition: gff3writer.cpp:382
std::vector< GFF3WriterStructPtr > _structs
Definition: gff3writer.h:87
Unsigned 32bit integer.
Definition: gff3file.h:173
Signed 32bit integer.
Definition: gff3file.h:174
size_t size() const
Return the size of the string, in characters.
Definition: ustring.cpp:241
FORCEINLINE void writeIEEEFloatLE(float value)
Definition: writestream.h:171
Resource reference, string.
Definition: gff3file.h:180
void addUint32(const Common::UString &label, uint32 value)
Add a new uint32.
Definition: gff3writer.cpp:402
uint32_t uint32
Definition: types.h:204
size_t getFieldCount() const
Get the count of fields.
Definition: gff3writer.cpp:333
std::vector< size_t > _fieldIndices
Definition: gff3writer.h:180
GFF3Writer * _parent
Definition: gff3writer.h:118
static uint32 getFieldDataSize(FieldPtr field)
Get the actual size of the field.
Definition: gff3writer.cpp:262
List containing a number of structs.
Definition: gff3file.h:184
Struct containing a number of fields.
Definition: gff3file.h:183
GFF3WriterStructPtr getTopLevel()
Get the top-level struct.
Definition: gff3writer.cpp:40
GFF3Writer::FieldPtr createField(GFF3Struct::FieldType type, const Common::UString &label)
Definition: gff3writer.cpp:453
void writeUint32BE(uint32 value)
Definition: writestream.h:122
FORCEINLINE void writeZeros(size_t n)
Write n zeros to the stream.
Definition: writestream.h:143
GFF3Writer(uint32 id, uint32 version=MKTAG('V', '3', '.', '2'))
Definition: gff3writer.cpp:36
boost::shared_ptr< GFF3WriterList > GFF3WriterListPtr
Definition: gff3writer.h:44
std::vector< FieldPtr > _fields
Definition: gff3writer.h:91
void addUint16(const Common::UString &label, uint16 value)
Add a new uint16.
Definition: gff3writer.cpp:398
void writeUint32LE(uint32 value)
Definition: writestream.h:104
uint32 getID() const
Get ID of the struct.
Definition: gff3writer.cpp:329
void addSint64(const Common::UString &label, int64 value)
Add a new sint64.
Definition: gff3writer.cpp:418
void addDouble(const Common::UString &label, double value)
Add a new double.
Definition: gff3writer.cpp:394
uint8 byte
Definition: types.h:209
int32_t int32
Definition: types.h:203
void addSint32(const Common::UString &label, int32 value)
Add a new sint32.
Definition: gff3writer.cpp:414