xoreos  0.0.5
talktable_tlk.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 /* See BioWare's own specs released for Neverwinter Nights modding
26  * (<https://github.com/xoreos/xoreos-docs/tree/master/specs/bioware>)
27  */
28 
29 #include <cassert>
30 
31 #include "src/common/util.h"
32 #include "src/common/strutil.h"
34 #include "src/common/readfile.h"
35 #include "src/common/error.h"
36 
38 #include "src/aurora/language.h"
39 
40 static const uint32 kTLKID = MKTAG('T', 'L', 'K', ' ');
41 static const uint32 kVersion3 = MKTAG('V', '3', '.', '0');
42 static const uint32 kVersion4 = MKTAG('V', '4', '.', '0');
43 
44 namespace Aurora {
45 
47  TalkTable(encoding), _tlk(tlk) {
48 
49  assert(_tlk);
50 
51  load();
52 }
53 
55 }
56 
58  try {
59  readHeader(*_tlk);
60 
61  if (_id != kTLKID)
62  throw Common::Exception("Not a TLK file (%s)", Common::debugTag(_id).c_str());
63 
64  if (_version != kVersion3 && _version != kVersion4)
65  throw Common::Exception("Unsupported TLK file version %s", Common::debugTag(_version).c_str());
66 
67  _languageID = _tlk->readUint32LE();
68 
69  uint32 stringCount = _tlk->readUint32LE();
70  _entries.resize(stringCount);
71 
72  // V4 added this field; it's right after the header in V3
73  uint32 tableOffset = 20;
74  if (_version == kVersion4)
75  tableOffset = _tlk->readUint32LE();
76 
77  const uint32 stringsOffset = _tlk->readUint32LE();
78 
79  // Go to the table
80  _tlk->seek(tableOffset);
81 
82  // Read in all the table data
83  if (_version == kVersion3)
84  readEntryTableV3(stringsOffset);
85  else
87 
88  } catch (Common::Exception &e) {
89  e.add("Failed reading TLK file");
90  throw;
91  }
92 }
93 
95  for (Entries::iterator entry = _entries.begin(); entry != _entries.end(); ++entry) {
96  entry->flags = _tlk->readUint32LE();
97  entry->soundResRef = Common::readStringFixed(*_tlk, Common::kEncodingASCII, 16);
98  entry->volumeVariance = _tlk->readUint32LE();
99  entry->pitchVariance = _tlk->readUint32LE();
100  entry->offset = _tlk->readUint32LE() + stringsOffset;
101  entry->length = _tlk->readUint32LE();
102  entry->soundLength = _tlk->readIEEEFloatLE();
103  entry->soundID = kFieldIDInvalid;
104  }
105 }
106 
108  for (Entries::iterator entry = _entries.begin(); entry != _entries.end(); ++entry) {
109  entry->soundID = _tlk->readUint32LE();
110  entry->offset = _tlk->readUint32LE();
111  entry->length = _tlk->readUint16LE();
112  entry->flags = kFlagTextPresent;
113  }
114 }
115 
116 void TalkTable_TLK::readString(Entry &entry) const {
117  if (!entry.text.empty() || (entry.length == 0) || !(entry.flags & kFlagTextPresent))
118  // We already have the string
119  return;
120 
121  assert(_tlk);
122 
123  _tlk->seek(entry.offset);
124 
125  uint32 length = MIN<size_t>(entry.length, _tlk->size() - _tlk->pos());
126  if (length == 0)
127  return;
128 
129  Common::ScopedPtr<Common::MemoryReadStream> data(_tlk->readStream(length));
130  Common::ScopedPtr<Common::MemoryReadStream> parsed(LangMan.preParseColorCodes(*data));
131 
133  entry.text = Common::readString(*parsed, _encoding);
134  else
135  entry.text = "[???]";
136 }
137 
139  return _languageID;
140 }
141 
142 bool TalkTable_TLK::hasEntry(uint32 strRef) const {
143  return strRef < _entries.size();
144 }
145 
146 static const Common::UString kEmptyString = "";
148  if (strRef >= _entries.size())
149  return kEmptyString;
150 
151  readString(_entries[strRef]);
152 
153  return _entries[strRef].text;
154 }
155 
157  if (strRef >= _entries.size())
158  return kEmptyString;
159 
160  return _entries[strRef].soundResRef;
161 }
162 
164  if (strRef >= _entries.size())
165  return kFieldIDInvalid;
166 
167  return _entries[strRef].soundID;
168 }
169 
171  uint32 id, version;
172  bool utf16le;
173 
174  AuroraFile::readHeader(tlk, id, version, utf16le);
175 
176  if ((id != kTLKID) || ((version != kVersion3) && (version != kVersion4)))
177  return kLanguageInvalid;
178 
179  return tlk.readUint32LE();
180 }
181 
183  Common::ReadFile tlk;
184  if (!tlk.open(file))
185  return kLanguageInvalid;
186 
187  return getLanguageID(tlk);
188 }
189 
190 } // End of namespace Aurora
const Common::UString & getSoundResRef(uint32 strRef) const
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like &#39;DATA&#39;, to ensure portability.
Definition: endianness.h:140
bool hasEntry(uint32 strRef) const
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
uint32 readUint32LE()
Read an unsigned 32-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:133
A class holding an UTF-8 string.
Definition: ustring.h:48
Base class for BioWare&#39;s talk tables.
Definition: talktable.h:52
A simple streaming file reading class.
Definition: readfile.h:40
Implementing the reading stream interfaces for plain memory blocks.
A talk resource entry.
Definition: talktable_tlk.h:82
void readString(Entry &entry) const
Utility templates and functions for working with strings and streams.
Exception that provides a stack of explanations.
Definition: error.h:36
static void readHeader(Common::ReadStream &stream, uint32 &id, uint32 &version, bool &utf16le)
Read the header out of a stream.
Definition: aurorafile.cpp:53
static const uint32 kVersion4
static const uint32 kVersion3
Basic exceptions to throw.
bool open(const UString &fileName)
Try to open the file with the given fileName.
Definition: readfile.cpp:61
Utility templates and functions.
Common::Encoding _encoding
Definition: talktable.h:70
Types and functions related to language.
Encoding
Definition: encoding.h:37
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
uint32 _id
The file&#39;s ID.
Definition: aurorafile.h:77
const Common::UString & getString(uint32 strRef) const
StackException Exception
Definition: error.h:59
A scoped plain pointer, allowing pointer-y access and normal deletion.
Definition: scopedptr.h:120
uint32 _version
The file&#39;s version.
Definition: aurorafile.h:78
Handling BioWare&#39;s TLK talk tables.
Implementing the stream reading interfaces for files.
Plain, unextended ASCII (7bit clean).
Definition: encoding.h:40
uint32 getSoundID(uint32 strRef) const
#define LangMan
Shortcut for accessing the language manager.
Definition: language.h:275
uint32_t uint32
Definition: types.h:204
UString debugTag(uint32 tag, bool trim)
Create an elaborate string from an integer tag, for debugging purposes.
Definition: strutil.cpp:117
static const uint32 kFieldIDInvalid
Definition: types.h:443
UString readString(SeekableReadStream &stream, Encoding encoding)
Read a string with the given encoding of a stream.
Definition: encoding.cpp:287
void readEntryTableV3(uint32 stringsOffset)
static const uint32 kTLKID
UString readStringFixed(SeekableReadStream &stream, Encoding encoding, size_t length)
Read length bytes as a string with the given encoding out of a stream.
Definition: encoding.cpp:297
TalkTable_TLK(Common::SeekableReadStream *tlk, Common::Encoding encoding)
Take over this stream and read a TLK out of it.
static const Common::UString kEmptyString
Definition: talkman.cpp:129
Common::ScopedPtr< Common::SeekableReadStream > _tlk
uint32 getLanguageID() const
Return the language ID (ungendered) of the talk table.
Interface for a seekable & readable data stream.
Definition: readstream.h:265