~ubuntu-branches/debian/sid/astromenace/sid

« back to all changes in this revision

Viewing changes to AstroMenaceSource/Core/XML/XML.cpp

  • Committer: Package Import Robot
  • Author(s): Boris Pek
  • Date: 2013-04-09 02:04:25 UTC
  • Revision ID: package-import@ubuntu.com-20130409020425-a7fl9xk4diamw6di
Tags: upstream-1.3.1+repack
Import upstream version 1.3.1+repack

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************************************************
 
2
 
 
3
        AstroMenace (Hardcore 3D space shooter with spaceship upgrade possibilities)
 
4
        Copyright © 2006-2012 Michael Kurinnoy, Viewizard
 
5
 
 
6
 
 
7
        AstroMenace is free software: you can redistribute it and/or modify
 
8
        it under the terms of the GNU General Public License as published by
 
9
        the Free Software Foundation, either version 3 of the License, or
 
10
        (at your option) any later version.
 
11
 
 
12
        AstroMenace 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 AstroMenace. If not, see <http://www.gnu.org/licenses/>.
 
19
 
 
20
 
 
21
        Web Site: http://www.viewizard.com/
 
22
        Project: http://sourceforge.net/projects/openastromenace/
 
23
        E-mail: viewizard@viewizard.com
 
24
 
 
25
*************************************************************************************/
 
26
 
 
27
 
 
28
#include "XML.h"
 
29
#include "../VirtualFileSystem/VFS.h"
 
30
 
 
31
 
 
32
 
 
33
 
 
34
 
 
35
 
 
36
 
 
37
 
 
38
// ищем первое вхождение подстроки в строку, передаем позицию, или -1 если не найдена
 
39
int FindSubString(char *String, const char *SubString)
 
40
{
 
41
        unsigned int lenght = strlen(SubString);
 
42
        for (int i = 0; (String+i)[0] != '\0'; i++)
 
43
        {
 
44
                if (!strncmp(String+i, SubString, lenght)) return i;
 
45
        }
 
46
        return -1;
 
47
}
 
48
 
 
49
// замена данных, с сохранением перевода на новую строку
 
50
void EraseSubString(char *String, unsigned int StartPos, unsigned int EndPos)
 
51
{
 
52
        // проверяем, если не символы конце строки \r или \n - меняем на пробелы
 
53
        for (unsigned int i=StartPos; i<EndPos; i++)
 
54
        {
 
55
                if ((String[i] != '\r') && (String[i] != '\n')) String[i] = ' ';
 
56
        }
 
57
}
 
58
 
 
59
// считаем кол-во строк до текущего положения буфера
 
60
#ifdef gamedebug
 
61
unsigned int GetLineNumber(char *String, unsigned int Pos)
 
62
{
 
63
        unsigned int LineNumber = 1;
 
64
        unsigned int CurrentPos = 0;
 
65
 
 
66
        while ((strlen(String) > 0) && (CurrentPos <= Pos))
 
67
        {
 
68
                if (String[0] == '\n') LineNumber++;
 
69
                CurrentPos++;
 
70
                String++;
 
71
        }
 
72
        return LineNumber;
 
73
}
 
74
#else
 
75
unsigned int GetLineNumber(char *UNUSED(String), unsigned int UNUSED(Pos))
 
76
{
 
77
        return 0;
 
78
}
 
79
#endif // gamedebug
 
80
 
 
81
// создаем подстроку из строки с выделением памяти
 
82
char *CreateSubString(char *String, unsigned int StartPos, unsigned int EndPos)
 
83
{
 
84
        if (EndPos <= StartPos) return 0;
 
85
 
 
86
        char * Result = new char[EndPos-StartPos+1];
 
87
        strncpy(Result, String+StartPos, EndPos-StartPos);
 
88
        Result[EndPos-StartPos] = 0;
 
89
 
 
90
        return Result;
 
91
}
 
92
 
 
93
 
 
94
 
 
95
 
 
96
 
 
97
 
 
98
 
 
99
 
 
100
 
 
101
 
 
102
 
 
103
 
 
104
 
 
105
//-----------------------------------------------------------------------------
 
106
// Включаем в список
 
107
//-----------------------------------------------------------------------------
 
108
void cXMLDocument::AttachXMLChildEntry(cXMLEntry *ParentXMLEntry, cXMLEntry *ChildXMLEntry)
 
109
{
 
110
        if ((RootXMLEntry == 0) && (ParentXMLEntry == 0))
 
111
        {
 
112
                RootXMLEntry = ChildXMLEntry;
 
113
                return;
 
114
        }
 
115
 
 
116
 
 
117
        if (ParentXMLEntry == 0) return;
 
118
        if (ChildXMLEntry == 0) return;
 
119
 
 
120
        // первый в списке...
 
121
        if (ParentXMLEntry->LastChild == 0)
 
122
        {
 
123
                ChildXMLEntry->Prev = 0;
 
124
                ChildXMLEntry->Next = 0;
 
125
                ParentXMLEntry->FirstChild = ChildXMLEntry;
 
126
                ParentXMLEntry->LastChild = ChildXMLEntry;
 
127
        }
 
128
        else // продолжаем заполнение...
 
129
        {
 
130
                ChildXMLEntry->Prev = ParentXMLEntry->LastChild;
 
131
                ChildXMLEntry->Next = 0;
 
132
                ParentXMLEntry->LastChild->Next = ChildXMLEntry;
 
133
                ParentXMLEntry->LastChild = ChildXMLEntry;
 
134
        }
 
135
}
 
136
 
 
137
//-----------------------------------------------------------------------------
 
138
// Исключаем из списка
 
139
//-----------------------------------------------------------------------------
 
140
void cXMLDocument::DetachXMLChildEntry(cXMLEntry *ParentXMLEntry, cXMLEntry *XMLChildEntry)
 
141
{
 
142
        if (ParentXMLEntry == 0) return;
 
143
        if (XMLChildEntry == 0) return;
 
144
 
 
145
        // переустанавливаем указатели...
 
146
        if (ParentXMLEntry->FirstChild == XMLChildEntry) ParentXMLEntry->FirstChild = XMLChildEntry->Next;
 
147
        if (ParentXMLEntry->LastChild == XMLChildEntry) ParentXMLEntry->LastChild = XMLChildEntry->Prev;
 
148
 
 
149
 
 
150
        if (XMLChildEntry->Next != 0) XMLChildEntry->Next->Prev = XMLChildEntry->Prev;
 
151
                else if (XMLChildEntry->Prev != 0) XMLChildEntry->Prev->Next = 0;
 
152
        if (XMLChildEntry->Prev != 0) XMLChildEntry->Prev->Next = XMLChildEntry->Next;
 
153
                else if (XMLChildEntry->Next != 0) XMLChildEntry->Next->Prev = 0;
 
154
}
 
155
 
 
156
//-----------------------------------------------------------------------------
 
157
// Включаем в список атрибут
 
158
//-----------------------------------------------------------------------------
 
159
void cXMLDocument::AttachXMLAttribute(cXMLEntry *XMLEntry, cXMLAttribute *XMLAttribute)
 
160
{
 
161
        if (XMLEntry == 0) return;
 
162
        if (XMLAttribute == 0) return;
 
163
 
 
164
        // первый в списке...
 
165
        if (XMLEntry->LastAttribute == 0)
 
166
        {
 
167
                XMLAttribute->Prev = 0;
 
168
                XMLAttribute->Next = 0;
 
169
                XMLEntry->FirstAttribute = XMLAttribute;
 
170
                XMLEntry->LastAttribute = XMLAttribute;
 
171
        }
 
172
        else // продолжаем заполнение...
 
173
        {
 
174
                XMLAttribute->Prev = XMLEntry->LastAttribute;
 
175
                XMLAttribute->Next = 0;
 
176
                XMLEntry->LastAttribute->Next = XMLAttribute;
 
177
                XMLEntry->LastAttribute = XMLAttribute;
 
178
        }
 
179
}
 
180
 
 
181
//-----------------------------------------------------------------------------
 
182
// Исключаем из списка атрибут
 
183
//-----------------------------------------------------------------------------
 
184
void cXMLDocument::DetachXMLAttribute(cXMLEntry *XMLEntry, cXMLAttribute *XMLAttribute)
 
185
{
 
186
        if (XMLEntry == 0) return;
 
187
        if (XMLAttribute == 0) return;
 
188
 
 
189
        // переустанавливаем указатели...
 
190
        if (XMLEntry->FirstAttribute == XMLAttribute) XMLEntry->FirstAttribute = XMLAttribute->Next;
 
191
        if (XMLEntry->LastAttribute == XMLAttribute) XMLEntry->LastAttribute = XMLAttribute->Prev;
 
192
 
 
193
 
 
194
        if (XMLAttribute->Next != 0) XMLAttribute->Next->Prev = XMLAttribute->Prev;
 
195
                else if (XMLAttribute->Prev != 0) XMLAttribute->Prev->Next = 0;
 
196
        if (XMLAttribute->Prev != 0) XMLAttribute->Prev->Next = XMLAttribute->Next;
 
197
                else if (XMLAttribute->Next != 0) XMLAttribute->Next->Prev = 0;
 
198
}
 
199
 
 
200
 
 
201
 
 
202
 
 
203
 
 
204
 
 
205
 
 
206
 
 
207
 
 
208
 
 
209
 
 
210
 
 
211
 
 
212
bool cXMLDocument::ParseTagLine(char *OriginBuffer, unsigned int StartPosition, char *Buffer, cXMLEntry *XMLEntry)
 
213
{
 
214
        // 1 - получаем имя тэга (начинается сразу после символа <, а заканчивается пробелом, >, />, или символом таб)
 
215
        int TagNameEnd = FindSubString(Buffer, " ");
 
216
        if (TagNameEnd == -1 || (FindSubString(Buffer, "\t") != -1 && TagNameEnd > FindSubString(Buffer, "\t"))) TagNameEnd = FindSubString(Buffer, "\t");
 
217
        if (TagNameEnd == -1 || (FindSubString(Buffer, ">") != -1 && TagNameEnd > FindSubString(Buffer, ">"))) TagNameEnd = FindSubString(Buffer, ">");
 
218
        if (TagNameEnd == -1 || (FindSubString(Buffer, "/>") != -1 && TagNameEnd > FindSubString(Buffer, "/>"))) TagNameEnd = FindSubString(Buffer, "/>");
 
219
        XMLEntry->Name = CreateSubString(Buffer, 1, TagNameEnd);
 
220
 
 
221
        // 2 - проверяем наличие атрибутов и заносим их в динамический массив
 
222
        unsigned int i = TagNameEnd;
 
223
        while (((Buffer+i)[0] != '>') || ((Buffer+i)[0] != '\0'))
 
224
        {
 
225
                // пропускаем все пробелы и табы
 
226
                while ((((Buffer+i)[0] == ' ') || ((Buffer+i)[0] == '\t')) && ((Buffer+i)[0] != '\0')) i++;
 
227
                if ((Buffer+i)[0] == '\0') {fprintf(stderr, "XML file corrupted, line: %i.", GetLineNumber(OriginBuffer, StartPosition)); break;}
 
228
                // еще раз проверяем, возможно завершение тэга ставили через пробел или таб
 
229
                if (((Buffer+i)[0] == '>') || (!strncmp(Buffer+i, "/>", strlen("/>")))) break;
 
230
 
 
231
                // находим имя атрибута
 
232
                unsigned int AttribNameStart = i;
 
233
                while (((Buffer+i)[0] != '=') && ((Buffer+i)[0] != '\0')) i++;
 
234
                if ((Buffer+i)[0] == '\0') {fprintf(stderr, "XML file corrupted, line: %i.", GetLineNumber(OriginBuffer, StartPosition)); break;}
 
235
                unsigned int AttribNameEnd = i;
 
236
                // пропускаем все до кавычек (они у нас следующие, после знака равенства)
 
237
                i+=2;
 
238
                unsigned int AttribDataStart = i;
 
239
                while ((((Buffer+i)[0] != '\'') && ((Buffer+i)[0] != '\"')) && ((Buffer+i)[0] != '\0')) i++;
 
240
                if ((Buffer+i)[0] == '\0') {fprintf(stderr, "XML file corrupted, line: %i.", GetLineNumber(OriginBuffer, StartPosition)); break;}
 
241
                unsigned int AttribDataEnd = i;
 
242
                i++;
 
243
 
 
244
                // собираем новый атрибут и подключаем его к элементу
 
245
                cXMLAttribute *XMLAttribute = new cXMLAttribute;
 
246
                AttachXMLAttribute(XMLEntry, XMLAttribute);
 
247
                XMLAttribute->Name = CreateSubString(Buffer, AttribNameStart, AttribNameEnd);
 
248
                XMLAttribute->Data = CreateSubString(Buffer, AttribDataStart, AttribDataEnd);
 
249
        }
 
250
 
 
251
 
 
252
        // 3 - определяем и номер строки
 
253
        XMLEntry->LineNumber = GetLineNumber(OriginBuffer, StartPosition);
 
254
 
 
255
 
 
256
        // 4 - определить есть ли в ней атрибут закрытия '/', или у нас есть еще и контент и закрывающий тэг
 
257
        if (FindSubString(Buffer, "/>") != -1) return false;
 
258
        return true;
 
259
}
 
260
 
 
261
 
 
262
 
 
263
bool cXMLDocument::ParseTagContent(char *OriginBuffer, unsigned int StartPosition, char *Buffer, cXMLEntry *ParentXMLEntry)
 
264
{
 
265
        // проверяем наличие вложенных тэгов
 
266
        bool ChildsFound = true;
 
267
        int DetectTagOpenSymbol = FindSubString(Buffer, "<");
 
268
        // если символа открытия в строке нет - это просто данные, иначе проверяем, что стоит до этого символа
 
269
        if (DetectTagOpenSymbol > 0)
 
270
        {
 
271
                int CurrentPos = 0;
 
272
                while(CurrentPos != DetectTagOpenSymbol)
 
273
                {
 
274
                        // если до открывающего тэга идут не " ", "\t", "\r", "\n", значит у нас просто данные
 
275
                        if (((Buffer+CurrentPos)[0] != ' ') &&
 
276
                                ((Buffer+CurrentPos)[0] != '\t') &&
 
277
                                ((Buffer+CurrentPos)[0] != '\r') &&
 
278
                                ((Buffer+CurrentPos)[0] != '\n'))
 
279
                        {
 
280
                                ChildsFound = false;
 
281
                                break;
 
282
                        }
 
283
 
 
284
                        CurrentPos++;
 
285
                }
 
286
 
 
287
        }
 
288
        else ChildsFound = false;
 
289
 
 
290
 
 
291
        // 1 - это просто контент, заносим данные и выходи из рекурсии
 
292
        if (!ChildsFound)
 
293
        {
 
294
                ParentXMLEntry->Content = CreateSubString(Buffer, 0, strlen(Buffer));
 
295
                return true;
 
296
        }
 
297
        // 2 - если в строке нашли открывающий символ тэга - идем на рекурсивную обработку строки с хмл данными
 
298
        else
 
299
        {
 
300
                // в цикле, пока не достигнем конца обрабатываемой строки:
 
301
                unsigned int CurrentBufferPosition = 0;
 
302
                while(strlen(Buffer) > 0)
 
303
                {
 
304
                        // находим положение открывающего тэг символа и закрывающего
 
305
                        DetectTagOpenSymbol = FindSubString(Buffer, "<");
 
306
 
 
307
                        // это может быть комментарий, проверяем
 
308
                        if (!strncmp(Buffer+DetectTagOpenSymbol, "<!--", strlen("<!--")))
 
309
                        {
 
310
                                // ищем завершающую часть, и сразу перемещаемся к ней
 
311
                                int DetectCommentCloseSymbol = FindSubString(Buffer, "-->");
 
312
                                if (DetectCommentCloseSymbol == -1)
 
313
                                {
 
314
                                        fprintf(stderr, "XML file corrupted, can't find comment end in line %i.\n", GetLineNumber(OriginBuffer, StartPosition+DetectTagOpenSymbol+CurrentBufferPosition));
 
315
                                        return false;
 
316
                                }
 
317
                                Buffer += DetectCommentCloseSymbol + strlen("-->");
 
318
                                CurrentBufferPosition += DetectCommentCloseSymbol + strlen("-->");
 
319
                                continue;
 
320
                        }
 
321
 
 
322
                        // если в строке уже нет открывающих символов - просто выходим, все проверили
 
323
                        if (DetectTagOpenSymbol == -1) return true;
 
324
                        int DetectTagCloseSymbol = FindSubString(Buffer, ">");
 
325
                        // если был открывающий символ, но нет закрывающего - это ошибка структуры документа
 
326
                        if (DetectTagCloseSymbol == -1)
 
327
                        {
 
328
                                fprintf(stderr, "XML file corrupted, can't find element end for element in line %i.\n", GetLineNumber(OriginBuffer, StartPosition+DetectTagOpenSymbol+CurrentBufferPosition));
 
329
                                return false;
 
330
                        }
 
331
                        DetectTagCloseSymbol += strlen(">");
 
332
 
 
333
                        // создаем новый элемент и подключаем его к родительскому
 
334
                        cXMLEntry *XMLEntry = new cXMLEntry;
 
335
                        AttachXMLChildEntry(ParentXMLEntry, XMLEntry);
 
336
 
 
337
                        // полученные данные передаем на обработку и анализ строки элемента
 
338
                        char *TagString = CreateSubString(Buffer, DetectTagOpenSymbol, DetectTagCloseSymbol);
 
339
                        bool ElementHaveContent = ParseTagLine(OriginBuffer, StartPosition+DetectTagOpenSymbol+CurrentBufferPosition, TagString, XMLEntry);
 
340
                        delete [] TagString;
 
341
 
 
342
                        // если у нас закрытый тэг - с этим элементом закончили, идем искать дальше
 
343
                        if (!ElementHaveContent)
 
344
                        {
 
345
                                Buffer += DetectTagCloseSymbol;
 
346
                                CurrentBufferPosition += DetectTagCloseSymbol;
 
347
                                continue;
 
348
                        }
 
349
 
 
350
                        // если тэг открытый - ищем завершающий тэг </имя>
 
351
                        char *CloseElement = new char[strlen("</>")+strlen(XMLEntry->Name)+1];
 
352
                        strcpy(CloseElement, "</"); strcat(CloseElement, XMLEntry->Name); strcat(CloseElement, ">");
 
353
                        CloseElement[strlen("</>")+strlen(XMLEntry->Name)] = 0;
 
354
                        int CloseElementPosition = FindSubString(Buffer, CloseElement);
 
355
                        delete [] CloseElement;
 
356
                        // если закрывающего элемента нет - значит файл поврежден
 
357
                        if (CloseElementPosition == -1)
 
358
                        {
 
359
                                fprintf(stderr, "XML file corrupted, can't find element end: %s in line: %i\n", XMLEntry->Name, GetLineNumber(OriginBuffer, StartPosition+DetectTagOpenSymbol+CurrentBufferPosition));
 
360
                                return false;
 
361
                        }
 
362
 
 
363
                        // передаем данные на рекурсивную обработку (если закрывающий тэг не стоит сразу после открывающего)
 
364
                        if (DetectTagCloseSymbol < CloseElementPosition)
 
365
                        {
 
366
                                char *ElementContent = CreateSubString(Buffer, DetectTagCloseSymbol, CloseElementPosition);
 
367
                                if (!ParseTagContent(OriginBuffer, DetectTagCloseSymbol+StartPosition+CurrentBufferPosition, ElementContent, XMLEntry))
 
368
                                {
 
369
                                        // вернули с ошибкой, выходим
 
370
                                        delete [] ElementContent;
 
371
                                        return false;
 
372
                                }
 
373
                                delete [] ElementContent;
 
374
                        }
 
375
 
 
376
                        // смещаем буфер
 
377
                        Buffer += CloseElementPosition + strlen(XMLEntry->Name) + strlen("</>");
 
378
                        CurrentBufferPosition += CloseElementPosition + strlen(XMLEntry->Name) + strlen("</>");
 
379
                }
 
380
        }
 
381
 
 
382
 
 
383
        return false;
 
384
}
 
385
 
 
386
 
 
387
 
 
388
 
 
389
 
 
390
 
 
391
 
 
392
 
 
393
 
 
394
 
 
395
 
 
396
 
 
397
//-----------------------------------------------------------------------------
 
398
// Загрузка
 
399
//-----------------------------------------------------------------------------
 
400
bool cXMLDocument::Load(const char *XMLFileName)
 
401
{
 
402
        printf("Open XML file: %s\n", XMLFileName);
 
403
 
 
404
        // если что-то было загружено ранее - освобождаем
 
405
        ReleaseXMLDocument();
 
406
 
 
407
        // читаем данные
 
408
        eFILE *XMLFile = vw_fopen(XMLFileName);
 
409
 
 
410
        if (XMLFile == NULL)
 
411
        {
 
412
                fprintf(stderr, "XML file not found: %s\n", XMLFileName);
 
413
                return false;
 
414
        }
 
415
 
 
416
        // читаем все данные в буфер
 
417
        XMLFile->fseek(0, SEEK_END);
 
418
        unsigned int DataLength = XMLFile->ftell();
 
419
        XMLFile->fseek(0, SEEK_SET);
 
420
        char *Buffer = new char[DataLength+1];
 
421
        Buffer[DataLength] = 0;
 
422
        XMLFile->fread(Buffer, DataLength, 1);
 
423
        vw_fclose(XMLFile);
 
424
 
 
425
 
 
426
        // проверяем заголовок
 
427
        if (FindSubString(Buffer, "<?xml") == -1)
 
428
        {
 
429
                fprintf(stderr, "XML file corrupted: %s\n", XMLFileName);
 
430
                return false;
 
431
        }
 
432
        if (FindSubString(Buffer, "?>") == -1)
 
433
        {
 
434
                fprintf(stderr, "XML file corrupted: %s\n", XMLFileName);
 
435
                return false;
 
436
        }
 
437
 
 
438
 
 
439
        // идем на рекурсивную обработку
 
440
        if (!ParseTagContent(Buffer, FindSubString(Buffer, "?>")+strlen("?>"), Buffer+FindSubString(Buffer, "?>")+strlen("?>"), 0))
 
441
        {
 
442
                fprintf(stderr, "XML file corrupted: %s\n", XMLFileName);
 
443
                delete [] Buffer;
 
444
                return false;
 
445
        }
 
446
 
 
447
        if (RootXMLEntry == 0)
 
448
        {
 
449
                fprintf(stderr, "XML file corrupted, root element not found: %s\n", XMLFileName);
 
450
                delete [] Buffer;
 
451
                return false;
 
452
        }
 
453
 
 
454
        delete [] Buffer;
 
455
        return true;
 
456
}
 
457
 
 
458
 
 
459
 
 
460
 
 
461
 
 
462
 
 
463
 
 
464
 
 
465
 
 
466
//-----------------------------------------------------------------------------
 
467
// Сохранение
 
468
//-----------------------------------------------------------------------------
 
469
void cXMLDocument::SaveRecursive(cXMLEntry *XMLEntry, SDL_RWops *File, unsigned int Level)
 
470
{
 
471
        // если это комментарий
 
472
        if (XMLEntry->EntryType == 1)
 
473
        {
 
474
                for (unsigned int i=0; i<Level; i++) SDL_RWwrite(File, "    ", strlen("    "), 1);
 
475
                SDL_RWwrite(File, "<!--", strlen("<!--"), 1);
 
476
                SDL_RWwrite(File, XMLEntry->Name, strlen(XMLEntry->Name), 1);
 
477
                SDL_RWwrite(File, "-->\r\n", strlen("-->\r\n"), 1);
 
478
        }
 
479
        else
 
480
        {
 
481
                // пишем имя
 
482
                for (unsigned int i=0; i<Level; i++) SDL_RWwrite(File, "    ", strlen("    "), 1);
 
483
                SDL_RWwrite(File, "<", strlen("<"), 1);
 
484
                SDL_RWwrite(File, XMLEntry->Name, strlen(XMLEntry->Name), 1);
 
485
 
 
486
                // пишем атрибуты
 
487
                if (XMLEntry->FirstAttribute != 0)
 
488
                {
 
489
                        cXMLAttribute *TmpAttrib = XMLEntry->FirstAttribute;
 
490
                        while (TmpAttrib != 0)
 
491
                        {
 
492
                                SDL_RWwrite(File, " ", strlen(" "), 1);
 
493
                                SDL_RWwrite(File, TmpAttrib->Name, strlen(TmpAttrib->Name), 1);
 
494
                                SDL_RWwrite(File, "=\"", strlen("=\""), 1);
 
495
                                SDL_RWwrite(File, TmpAttrib->Data, strlen(TmpAttrib->Data), 1);
 
496
                                SDL_RWwrite(File, "\"", strlen("\""), 1);
 
497
                                TmpAttrib = TmpAttrib->Next;
 
498
                        }
 
499
                        SDL_RWwrite(File, " ", strlen(" "), 1);
 
500
                }
 
501
 
 
502
 
 
503
                // пишем данные
 
504
                if ((XMLEntry->FirstChild != 0) || (XMLEntry->Content != 0))
 
505
                {
 
506
                        if (XMLEntry->Content != 0)
 
507
                        {
 
508
                                SDL_RWwrite(File, ">", strlen(">"), 1);
 
509
                                SDL_RWwrite(File, XMLEntry->Content, strlen(XMLEntry->Content), 1);
 
510
                                SDL_RWwrite(File, "</", strlen("</"), 1);
 
511
                                SDL_RWwrite(File, XMLEntry->Name, strlen(XMLEntry->Name), 1);
 
512
                                SDL_RWwrite(File, ">\r\n", strlen(">\r\n"), 1);
 
513
                        }
 
514
                        else
 
515
                        {
 
516
                                SDL_RWwrite(File, ">\r\n", strlen(">\r\n"), 1);
 
517
                                cXMLEntry *Tmp = XMLEntry->FirstChild;
 
518
                                while (Tmp != 0)
 
519
                                {
 
520
                                        SaveRecursive(Tmp, File, Level+1);
 
521
                                        Tmp = Tmp->Next;
 
522
                                }
 
523
                                for (unsigned int i=0; i<Level; i++) SDL_RWwrite(File, "    ", strlen("    "), 1);
 
524
                                SDL_RWwrite(File, "</", strlen("</"), 1);
 
525
                                SDL_RWwrite(File, XMLEntry->Name, strlen(XMLEntry->Name), 1);
 
526
                                SDL_RWwrite(File, ">\r\n", strlen(">\r\n"), 1);
 
527
                        }
 
528
                }
 
529
                else
 
530
                {
 
531
                        SDL_RWwrite(File, "/>\r\n", strlen("/>\r\n"), 1);
 
532
                }
 
533
        }
 
534
}
 
535
bool cXMLDocument::Save(const char *XMLFileName)
 
536
{
 
537
        printf("Save XML file: %s\n", XMLFileName);
 
538
 
 
539
        SDL_RWops *File = SDL_RWFromFile(XMLFileName, "wb");
 
540
    if (File == NULL)
 
541
    {
 
542
        fprintf(stderr, "Can't open XML file for write %s\n", XMLFileName);
 
543
        return false;
 
544
    }
 
545
 
 
546
 
 
547
        // пишем заголовок
 
548
        SDL_RWwrite(File, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n", strlen("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n"), 1);
 
549
 
 
550
        if (RootXMLEntry == 0)
 
551
        {
 
552
                SDL_RWclose(File);
 
553
                return true;
 
554
        }
 
555
 
 
556
        // рекурсивно пишем все данные
 
557
        SaveRecursive(RootXMLEntry, File, 0);
 
558
 
 
559
        SDL_RWclose(File);
 
560
        return true;
 
561
}