Switch to using -I to find includes, rather than relative paths.
[gemrb.git] / gemrb / plugins / DLGImporter / DLGImporter.cpp
blob543d2ae5adef7cae6341ff91b8a3f26f3d74e1fc
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "win32def.h"
22 #include "DLGImporter.h"
23 #include "FileStream.h"
24 #include "Interface.h"
26 DLGImp::DLGImp(void)
28 str = NULL;
29 autoFree = false;
30 Version = 0;
33 DLGImp::~DLGImp(void)
35 if (str && autoFree) {
36 delete( str );
40 bool DLGImp::Open(DataStream* stream, bool autoFree)
42 if (stream == NULL) {
43 return false;
45 if (str && this->autoFree) {
46 delete( str );
48 str = stream;
49 this->autoFree = autoFree;
50 char Signature[8];
51 str->Read( Signature, 8 );
52 if (strnicmp( Signature, "DLG V1.0", 8 ) != 0) {
53 printMessage( "DLGImporter", "Not a valid DLG File...", WHITE );
54 printStatus( "ERROR", LIGHT_RED );
55 Version = 0;
56 return false;
58 str->ReadDword( &StatesCount );
59 str->ReadDword( &StatesOffset );
60 // bg2
61 if (StatesOffset == 0x34 ) {
62 Version = 104;
64 else {
65 Version = 100;
67 str->ReadDword( &TransitionsCount );
68 str->ReadDword( &TransitionsOffset );
69 str->ReadDword( &StateTriggersOffset );
70 str->ReadDword( &StateTriggersCount );
71 str->ReadDword( &TransitionTriggersOffset );
72 str->ReadDword( &TransitionTriggersCount );
73 str->ReadDword( &ActionsOffset );
74 str->ReadDword( &ActionsCount );
75 if (Version == 104) {
76 str->ReadDword( &Flags );
78 else {
79 Flags = 0;
81 return true;
84 Dialog* DLGImp::GetDialog()
86 if(!Version) {
87 return NULL;
89 Dialog* d = new Dialog();
90 d->Flags = Flags;
91 d->TopLevelCount = StatesCount;
92 d->Order = (unsigned int *) calloc (StatesCount, sizeof(unsigned int *) );
93 d->initialStates = (DialogState **) calloc (StatesCount, sizeof(DialogState *) );
94 for (unsigned int i = 0; i < StatesCount; i++) {
95 DialogState* ds = GetDialogState( d, i );
96 d->initialStates[i] = ds;
98 return d;
101 DialogState* DLGImp::GetDialogState(Dialog *d, unsigned int index)
103 DialogState* ds = new DialogState();
104 //16 = sizeof(State)
105 str->Seek( StatesOffset + ( index * 16 ), GEM_STREAM_START );
106 ieDword FirstTransitionIndex;
107 ieDword TriggerIndex;
108 str->ReadDword( &ds->StrRef );
109 str->ReadDword( &FirstTransitionIndex );
110 str->ReadDword( &ds->transitionsCount );
111 str->ReadDword( &TriggerIndex );
112 ds->trigger = GetStateTrigger( TriggerIndex );
113 ds->transitions = GetTransitions( FirstTransitionIndex, ds->transitionsCount );
114 if (TriggerIndex<StatesCount)
115 d->Order[TriggerIndex] = index;
116 return ds;
119 DialogTransition** DLGImp::GetTransitions(unsigned int firstIndex, unsigned int count)
121 DialogTransition** trans = ( DialogTransition** )
122 malloc( count*sizeof( DialogTransition* ) );
123 for (unsigned int i = 0; i < count; i++) {
124 trans[i] = GetTransition( firstIndex + i );
126 return trans;
129 DialogTransition* DLGImp::GetTransition(unsigned int index)
131 if (index >= TransitionsCount) {
132 return NULL;
134 //32 = sizeof(Transition)
135 str->Seek( TransitionsOffset + ( index * 32 ), GEM_STREAM_START );
136 DialogTransition* dt = new DialogTransition();
137 str->ReadDword( &dt->Flags );
138 str->ReadDword( &dt->textStrRef );
139 if (!(dt->Flags & IE_DLG_TR_TEXT)) {
140 dt->textStrRef = 0xffffffff;
142 str->ReadDword( &dt->journalStrRef );
143 if (!(dt->Flags & IE_DLG_TR_JOURNAL)) {
144 dt->journalStrRef = 0xffffffff;
146 ieDword TriggerIndex;
147 ieDword ActionIndex;
148 str->ReadDword( &TriggerIndex );
149 str->ReadDword( &ActionIndex );
150 str->ReadResRef( dt->Dialog );
151 str->ReadDword( &dt->stateIndex );
152 if (dt->Flags &IE_DLG_TR_TRIGGER) {
153 dt->trigger = GetTransitionTrigger( TriggerIndex );
155 else {
156 dt->trigger = NULL;
158 if (dt->Flags & IE_DLG_TR_ACTION) {
159 dt->action = GetAction( ActionIndex );
161 else {
162 dt->action = NULL;
164 return dt;
167 DialogString* DLGImp::GetStateTrigger(unsigned int index)
169 if (index >= StateTriggersCount) {
170 return NULL;
172 //8 = sizeof(VarOffset)
173 str->Seek( StateTriggersOffset + ( index * 8 ), GEM_STREAM_START );
174 ieDword Offset, Length;
175 str->ReadDword( &Offset );
176 str->ReadDword( &Length );
177 //a zero length trigger counts as no trigger
178 //a // comment counts as true(), so we simply ignore zero
179 //length trigger text like it isn't there
180 if (!Length) {
181 return NULL;
183 DialogString* ds = new DialogString();
184 str->Seek( Offset, GEM_STREAM_START );
185 char* string = ( char* ) malloc( Length + 1 );
186 str->Read( string, Length );
187 string[Length] = 0;
188 ds->strings = GetStrings( string, ds->count );
189 free( string );
190 return ds;
193 DialogString* DLGImp::GetTransitionTrigger(unsigned int index)
195 if (index >= TransitionTriggersCount) {
196 return NULL;
198 str->Seek( TransitionTriggersOffset + ( index * 8 ), GEM_STREAM_START );
199 ieDword Offset, Length;
200 str->ReadDword( &Offset );
201 str->ReadDword( &Length );
202 DialogString* ds = new DialogString();
203 str->Seek( Offset, GEM_STREAM_START );
204 char* string = ( char* ) malloc( Length + 1 );
205 str->Read( string, Length );
206 string[Length] = 0;
207 ds->strings = GetStrings( string, ds->count );
208 free( string );
209 return ds;
212 DialogString* DLGImp::GetAction(unsigned int index)
214 if (index >= ActionsCount) {
215 return NULL;
217 str->Seek( ActionsOffset + ( index * 8 ), GEM_STREAM_START );
218 ieDword Offset, Length;
219 str->ReadDword( &Offset );
220 str->ReadDword( &Length );
221 DialogString* ds = new DialogString();
222 str->Seek( Offset, GEM_STREAM_START );
223 char* string = ( char* ) malloc( Length + 1 );
224 str->Read( string, Length );
225 string[Length] = 0;
226 ds->strings = GetStrings( string, ds->count );
227 free( string );
228 return ds;
231 int GetActionLength(const char* string)
233 int i;
234 int level = 0;
235 bool quotes = true;
236 const char* poi = string;
238 for (i = 0; *poi; i++) {
239 switch (*poi++) {
240 case '"':
241 quotes = !quotes;
242 break;
243 case '(':
244 if (quotes) {
245 level++;
247 break;
248 case ')':
249 if (quotes && level) {
250 level--;
251 if (level == 0) {
252 return i + 1;
255 break;
256 default:
257 break;
260 return i;
263 #define MyIsSpace(c) (((c) == ' ') || ((c) == '\n') || ((c) == '\r'))
265 /* this function will break up faulty script strings that lack the CRLF
266 between commands, common in PST dialog */
267 char** DLGImp::GetStrings(char* string, unsigned int& count)
269 int col = 0;
270 int level = 0;
271 bool quotes = true;
272 bool ignore = false;
273 char* poi = string;
275 count = 0;
276 while (*poi) {
277 switch (*poi++) {
278 case '/':
279 if(col==0) {
280 if(*poi=='/') {
281 poi++;
282 ignore=true;
285 break;
286 case '"':
287 quotes = !quotes;
288 break;
289 case '(':
290 if (quotes) {
291 level++;
293 break;
294 case ')':
295 if (quotes && level) {
296 level--;
297 if (level == 0) {
298 if(!ignore) {
299 count++;
301 ignore=false;
304 break;
305 default:
306 break;
309 if(!count) {
310 return NULL;
312 char** strings = ( char** ) calloc( count, sizeof( char* ) );
313 if (strings == NULL) {
314 count = 0;
315 return strings;
317 poi = string;
318 for (int i = 0; i < (int)count; i++) {
319 while (MyIsSpace( *poi ))
320 poi++;
321 int len = GetActionLength( poi );
322 if((*poi=='/') && (*(poi+1)=='/') ) {
323 poi+=len;
324 i--;
325 continue;
327 strings[i] = ( char * ) malloc( len + 1 );
328 int j;
329 for (j = 0; len; poi++,len--) {
330 if (isspace( *poi ))
331 continue;
332 strings[i][j++] = *poi;
334 strings[i][j] = 0;
336 return strings;
339 #include "plugindef.h"
341 GEMRB_PLUGIN(0x1970D894, "DLG File Importer")
342 PLUGIN_CLASS(IE_DLG_CLASS_ID, DLGImp)
343 END_PLUGIN()