1
2
3 #include "studiox_includes.h"
4
5 #ifdef _DEBUG
6 #define new DEBUG_NEW
7 #endif
8
9 ///////////////////////////////////////////////////////////////////////////////
xml_reader()10 xml_reader::xml_reader()
11 {
12 mpBuffer = NULL;
13 mpSectionStackPtr = mSectionStack;
14 mpSectionStackPtr += MAX_SECTION_NESTING;
15 mSectionLevel = 0;
16 }
17
18 ///////////////////////////////////////////////////////////////////////////////
~xml_reader()19 xml_reader::~xml_reader()
20 {
21 if (mpBuffer)
22 {
23 delete [] mpBuffer;
24 }
25 }
26
27 ///////////////////////////////////////////////////////////////////////////////
ReadFile(CString & pathname)28 BOOL xml_reader::ReadFile(CString &pathname)
29 {
30 CStdioFile file;
31 if (file.Open(pathname, CFile::modeRead))
32 {
33 ULONG size = (ULONG) file.GetLength();
34 mpBuffer = new char[size];
35 file.Read(mpBuffer, size);
36 file.Close();
37
38 // my current section is whole file
39 mSection.start = mpBuffer;
40 mSection.end = mpBuffer + size - 1;
41
42 // no local data copy
43 mSection.string = NULL;
44 return TRUE;
45 }
46
47 return FALSE;
48 }
49
50 ///////////////////////////////////////////////////////////////////////////////
ReadFile(CFile * memfile)51 BOOL xml_reader::ReadFile(CFile *memfile)
52 {
53 ULONG size = (ULONG) memfile->GetLength();
54 mpBuffer = new char[size];
55 memfile->Read(mpBuffer, size);
56
57 // my current section is whole file
58 mSection.start = mpBuffer;
59 mSection.end = mpBuffer + size - 1;
60
61 // no local data copy
62 mSection.string = NULL;
63 return TRUE;
64 }
65
66 ///////////////////////////////////////////////////////////////////////////////
ReadBool(const char * tagname,BOOL & put)67 BOOL xml_reader::ReadBool(const char *tagname, BOOL &put)
68 {
69 BOOL found = FALSE;
70 put = FALSE;
71 if (EnterTag(tagname))
72 {
73 if (mSection.string)
74 {
75 if (strcmp(mSection.string, "TRUE") == 0 ||
76 strcmp(mSection.string, "true") == 0)
77 {
78 put = TRUE;
79 }
80 found = TRUE;
81 }
82 CloseTag();
83 }
84 return found;
85 }
86
87 ///////////////////////////////////////////////////////////////////////////////
ReadInt(const char * tagname,int & put,int defval)88 BOOL xml_reader::ReadInt(const char *tagname, int &put, int defval)
89 {
90 BOOL found = FALSE;
91 put = defval;
92
93 if (EnterTag(tagname))
94 {
95 if (mSection.string)
96 {
97 put = strtol(mSection.string, NULL, 10);
98 found = TRUE;
99 }
100 CloseTag();
101 }
102 return found;
103 }
104
105 ///////////////////////////////////////////////////////////////////////////////
ReadUnsigned(const char * tagname,ULONG & put,ULONG defval)106 BOOL xml_reader::ReadUnsigned(const char *tagname, ULONG &put, ULONG defval)
107 {
108 BOOL found = FALSE;
109 ULONG val;
110 put = defval;
111
112 if (EnterTag(tagname))
113 {
114 if (mSection.string)
115 {
116 val = strtoul(mSection.string, NULL, 10);
117 put = val;
118 found = TRUE;
119 }
120 CloseTag();
121 }
122 return found;
123 }
124
125 ///////////////////////////////////////////////////////////////////////////////
ReadUByte(const char * tagname,GX_UBYTE & put,GX_UBYTE defval)126 BOOL xml_reader::ReadUByte(const char *tagname, GX_UBYTE &put, GX_UBYTE defval)
127 {
128 BOOL found = FALSE;
129 GX_UBYTE val;
130 put = defval;
131
132 if (EnterTag(tagname))
133 {
134 if (mSection.string)
135 {
136 val = (GX_UBYTE) strtoul(mSection.string, NULL, 10);
137 put = val;
138 found = TRUE;
139 }
140 CloseTag();
141 }
142 return found;
143
144 }
145
146
147 ///////////////////////////////////////////////////////////////////////////////
ReadHex(const char * tagname,ULONG & put,ULONG defval)148 BOOL xml_reader::ReadHex(const char *tagname, ULONG &put, ULONG defval)
149 {
150 BOOL found = FALSE;
151 ULONG val;
152 put = defval;
153
154 if (EnterTag(tagname))
155 {
156 if (mSection.string)
157 {
158 val = strtoul(mSection.string, NULL, 16);
159 put = val;
160 found = TRUE;
161 }
162 CloseTag();
163 }
164 return found;
165 }
166
167 ///////////////////////////////////////////////////////////////////////////////
ReadUShort(const char * tagname,USHORT & put,USHORT defval)168 BOOL xml_reader::ReadUShort(const char *tagname, USHORT &put, USHORT defval)
169 {
170 ULONG longval;
171 if (ReadUnsigned(tagname, longval, defval))
172 {
173 put = (USHORT) longval;
174 return TRUE;
175 }
176 put = defval;
177 return FALSE;
178 }
179
180 ///////////////////////////////////////////////////////////////////////////////
ReadValue(const char * tagname,GX_VALUE & put,GX_VALUE defval)181 BOOL xml_reader::ReadValue(const char *tagname, GX_VALUE &put, GX_VALUE defval)
182 {
183 ULONG longval;
184 if (ReadUnsigned(tagname, longval, defval))
185 {
186 put = (GX_VALUE)longval;
187 return TRUE;
188 }
189 put = defval;
190 return FALSE;
191 }
192
193 ///////////////////////////////////////////////////////////////////////////////
ReadRect(const char * tagname,GX_RECTANGLE & put)194 BOOL xml_reader::ReadRect(const char *tagname, GX_RECTANGLE &put)
195 {
196 put.gx_rectangle_bottom = put.gx_rectangle_top = 0;
197 put.gx_rectangle_left = put.gx_rectangle_right = 0;
198
199 if (EnterTag(tagname))
200 {
201 ReadValue("left", put.gx_rectangle_left);
202 ReadValue("top", put.gx_rectangle_top);
203 ReadValue("right", put.gx_rectangle_right);
204 ReadValue("bottom", put.gx_rectangle_bottom);
205
206 CloseTag();
207 return TRUE;
208 }
209
210 return FALSE;
211 }
212
213 ///////////////////////////////////////////////////////////////////////////////
ReadString(const char * tagname,char * put,int bufsize)214 BOOL xml_reader::ReadString(const char *tagname, char *put, int bufsize)
215 {
216 BOOL found = FALSE;
217 CString val;
218 found = ReadString(tagname, val);
219
220
221 if (found)
222 {
223 strncpy_s(put, bufsize, CT2A(val.GetString()), bufsize - 1);
224 }
225 else
226 {
227 *put = '\0';
228 }
229 return found;
230 }
231
232 ///////////////////////////////////////////////////////////////////////////////
ReadString(const char * tagname,CString & put)233 BOOL xml_reader::ReadString(const char *tagname, CString &put)
234 {
235 BOOL found = FALSE;
236 CString val;
237
238 if (EnterTag(tagname))
239 {
240 if (mSection.string)
241 {
242 CString escaped(CA2T(mSection.string, CP_UTF8));
243 escaped.Replace(_T("&"), _T("&"));
244 escaped.Replace(_T("""), _T("\""));
245 escaped.Replace(_T("'"), _T("\'"));
246 escaped.Replace(_T("<"), _T("<"));
247 escaped.Replace(_T(">"), _T(">"));
248
249 put = escaped;
250 found = TRUE;
251 }
252 CloseTag();
253 }
254
255 if (!found)
256 {
257 put.Empty();
258 }
259 return found;
260 }
261
262 ///////////////////////////////////////////////////////////////////////////////
ReadPathInfo(PATHINFO & info)263 void xml_reader::ReadPathInfo(PATHINFO &info)
264 {
265 info.pathname = "";
266 info.pathtype = PATH_TYPE_PROJECT_RELATIVE;
267
268 if (EnterSection("pathinfo"))
269 {
270 ReadString("pathname", info.pathname);
271
272 CString pathtype;
273 ReadString("pathtype", pathtype);
274
275 if (pathtype == "project_relative")
276 {
277 info.pathtype = PATH_TYPE_PROJECT_RELATIVE;
278 }
279 else
280 {
281 if (pathtype == "studio_relative")
282 {
283 info.pathtype = PATH_TYPE_INSTALL_RELATIVE;
284 }
285 else
286 {
287 info.pathtype = PATH_TYPE_ABSOLUTE;
288 }
289 }
290 CloseSection();
291 }
292 else
293 {
294 ReadString("path", info.pathname);
295 }
296
297 if (info.pathtype != PATH_TYPE_ABSOLUTE)
298 {
299 if (info.pathname[0] == '.' &&
300 info.pathname[1] == '\\')
301 {
302 info.pathname.TrimLeft(_T(".\\"));
303 }
304 else
305 {
306 if (info.pathname[0] == '\\')
307 {
308 info.pathname.TrimLeft('\\');
309 }
310 }
311 }
312 }
313
314
315 ///////////////////////////////////////////////////////////////////////////////
CloseSection(BOOL skip_to_end,BOOL mark_read)316 void xml_reader::CloseSection(BOOL skip_to_end, BOOL mark_read)
317 {
318 if (mark_read)
319 {
320 *(mSection.start + 1) = '.';
321 *(mSection.end + 1) = '.';
322 }
323
324 if (skip_to_end)
325 {
326 char *pStart = mSection.end + 1;
327 PopSection();
328 mSection.start = pStart;
329
330 // don't point the start at a closing tag,
331 // walk to the start of next tag:
332 if (*pStart == '<' && *(pStart + 1) == '/')
333 {
334 pStart += 2;
335
336 while(pStart < mSection.end)
337 {
338 if (*pStart == '>')
339 {
340 mSection.start = pStart + 1;
341 break;
342 }
343 pStart++;
344 }
345 }
346 }
347 else
348 {
349 PopSection();
350 }
351 }
352
353 ///////////////////////////////////////////////////////////////////////////////
CloseTag()354 void xml_reader::CloseTag()
355 {
356 PopSection();
357 }
358
359 ///////////////////////////////////////////////////////////////////////////////
FindTag(const char * tagname,BOOL mark_used)360 char *xml_reader::FindTag(const char *tagname, BOOL mark_used)
361 {
362 return FindTag(mSection.start, mSection.end, tagname, mark_used);
363 }
364
365 ///////////////////////////////////////////////////////////////////////////////
FindTag(char * start,char * stop,const char * tagname,BOOL mark_used)366 char *xml_reader::FindTag(char *start, char *stop,
367 const char *tagname, BOOL mark_used)
368 {
369 int nest_level = 0;
370 int taglen = (int) strlen(tagname);
371
372 while(start < stop)
373 {
374 // this will only happen if the XML is mal-formed, but we have
375 // to guard against it.
376 if (nest_level < 0)
377 {
378 return NULL;
379 }
380
381 if (*start == '<')
382 {
383 if (!nest_level)
384 {
385 // FIXME this is NOT very robust, it will fail if there is
386 // any whitespace around the tagname, but it will
387 // work for now.
388
389 if (strncmp(start + 1, tagname, taglen) == 0)
390 {
391 if (*(start + taglen + 1) == '>' || *(start + taglen + 1) == ' ')
392 {
393 // were we search for the end tag?
394 if (*tagname == '/')
395 {
396 // we found the end tag
397 return (start - 1);
398 }
399
400 // we found the start tag
401 // are we supposed to mark this unreadable?
402 if (mark_used)
403 {
404 *(start + 1) = '.';
405 }
406 // return pointer to first character after the tag:
407 //start += taglen + 2;
408
409 //while(*start == ' ' || *start == 0x0d || *start == 0x0a)
410 //{
411 // start++;
412 //}
413 return start;
414 }
415 }
416 }
417
418 char test = *(start + 1);
419
420 // check for </ sequence
421 if (test == '/')
422 {
423 nest_level--;
424 }
425 else
426 {
427 // if we hit a '<' and it's not a comment, then
428 // bump up our nest level:
429 if (test != '?' && test != '!')
430 {
431 nest_level++;
432 }
433 }
434 }
435 start++;
436 }
437
438 // didn't find what we were looking for
439 return NULL;
440 }
441
442 ///////////////////////////////////////////////////////////////////////////////
EndTag(char * start,char * stop)443 char *xml_reader::EndTag(char *start, char *stop)
444 {
445 while(start < stop)
446 {
447 if (*start == '>')
448 {
449 return start;
450 }
451 start++;
452 }
453 return NULL;
454 }
455
456 ///////////////////////////////////////////////////////////////////////////////
EnterSection(const char * tagname)457 BOOL xml_reader::EnterSection(const char *tagname)
458 {
459 char *end_section;
460 char *end_tag;
461 char close[MAX_PATH];
462 close[0] = '/';
463
464 if (!tagname || *tagname == '\0')
465 {
466 return FALSE;
467 }
468
469 if (mSectionLevel >= MAX_SECTION_NESTING)
470 {
471 return FALSE;
472 }
473
474 char *start_tag = FindTag(tagname);
475
476 if (!start_tag)
477 {
478 return FALSE;
479 }
480 end_tag = EndTag(start_tag, mSection.end);
481
482 if (!end_tag)
483 {
484 return FALSE;
485 }
486
487 strcpy_s(close + 1, MAX_PATH -1, tagname);
488 end_section = FindTag(end_tag + 1, mSection.end, close);
489
490 if (end_section)
491 {
492 int datalen = (int) (end_section - end_tag) + 1;
493
494 if (datalen >= 0)
495 {
496 if (PushSection())
497 {
498 mSection.start = end_tag + 1;
499 mSection.end = end_section;
500 mSection.string = NULL;
501
502 // copy the section tagname into the section marker
503 // just for debugging purposes.
504 int len = end_tag - start_tag + 1;
505 mSection.tag = new char[len + 1];
506 strncpy_s(mSection.tag, len + 1, start_tag, len);
507 mSection.tag[len] = 0;
508 return TRUE;
509 }
510 }
511 }
512 return FALSE;
513 }
514
515 ///////////////////////////////////////////////////////////////////////////////
EnterTag(const char * tagname)516 BOOL xml_reader::EnterTag(const char *tagname)
517 {
518 char *end_data;
519 char close[MAX_PATH];
520 close[0] = '/';
521
522 if (mSectionLevel >= MAX_SECTION_NESTING)
523 {
524 return FALSE;
525 }
526
527 char *start_tag = FindTag(tagname, TRUE);
528 char *end_tag;
529
530 if (!start_tag)
531 {
532 return FALSE;
533 }
534 end_tag = EndTag(start_tag, mSection.end);
535
536 if (!end_tag)
537 {
538 return FALSE;
539 }
540
541 // the tag close is the same as the tag, with a leading '/' char
542 strcpy_s(close + 1, MAX_PATH -1, tagname);
543 end_data = FindTag(end_tag, mSection.end, close);
544
545 if (end_data)
546 {
547 int datalen = (int) (end_data - end_tag);
548
549 if (datalen >= 0)
550 {
551 // this is just a safety check, we don't use any
552 // values that are huge, so if we think we found a huge tag
553 // something is wrong with the XML:
554 if (datalen > (10 * 1024))
555 {
556 ErrorMsg("Internal error: Invalid XML data length.");
557 return FALSE;
558 }
559
560 if (PushSection())
561 {
562 mSection.start = end_tag + 1;
563 mSection.end = end_data;
564 mSection.tag = NULL;
565
566 // copy the tag (and any embedded elements) into local array:
567
568 int tag_len = end_tag - start_tag + 1;
569 if (tag_len > 0)
570 {
571 mSection.tag = new char[tag_len + 1];
572 strncpy_s(mSection.tag, tag_len + 1, start_tag, tag_len);
573 mSection.tag[tag_len] = 0;
574 }
575 // copy the tag contents to a new array, so that we
576 // can NULL terminate the content string
577 mSection.string = new char[datalen + 1];
578 strncpy_s(mSection.string, datalen + 1, end_tag + 1, datalen);
579 // null terminate our local copy
580 mSection.string[datalen] = 0;
581
582 return TRUE;
583 }
584 }
585 }
586 return FALSE;
587 }
588
589 ///////////////////////////////////////////////////////////////////////////////
GetString(void)590 char *xml_reader::GetString(void)
591 {
592 return mSection.string;
593 }
594
595 ///////////////////////////////////////////////////////////////////////////////
GetTagValueFloat(char * name,float def_val)596 float xml_reader::GetTagValueFloat(char *name, float def_val)
597 {
598 float return_val = def_val;
599
600 // search within the tag itself for the requested value
601 if (mSection.tag)
602 {
603 char *marker = strstr(mSection.tag, name);
604 if (marker)
605 {
606 while(*marker)
607 {
608 if (*marker == '=')
609 {
610 marker++;
611 while(*marker == '\"' || *marker == '\'' || *marker == ' ')
612 {
613 marker++;
614 }
615 return_val = (float) atof(marker);
616 return return_val;
617 }
618 marker++;
619 }
620 }
621 }
622 return return_val;
623 }
624
625 ///////////////////////////////////////////////////////////////////////////////
GetTagString(char * name,CString & value)626 BOOL xml_reader::GetTagString(char *name, CString &value)
627 {
628 // search within the tag itself for the requested value
629 value = "";
630
631 char temp[MAX_PATH];
632
633 if (mSection.tag)
634 {
635 char *marker = strstr(mSection.tag, name);
636 if (marker)
637 {
638 while(*marker)
639 {
640 if (*marker == '=')
641 {
642 marker++;
643 while(*marker == '\"' || *marker == '\'' || *marker == ' ')
644 {
645 marker++;
646 }
647 char *end = marker + 1;
648
649 while(*end)
650 {
651 if (*end == '\"' || *end == '\'')
652 {
653 break;
654 }
655 end++;
656 }
657 int len = end - marker;
658
659 if (len > 0)
660 {
661 if (len >= MAX_PATH)
662 {
663 ErrorMsg("Invalid XLIFF content.");
664 return FALSE;
665 }
666 strncpy(temp, marker, len);
667 temp[len] = 0;
668 value = CString(temp);
669 return TRUE;
670 }
671 else
672 {
673 return FALSE;
674 }
675 }
676 marker++;
677 }
678 }
679 }
680 return FALSE;
681 }
682
683 ///////////////////////////////////////////////////////////////////////////////
PopSection(void)684 BOOL xml_reader::PopSection(void)
685 {
686 if (mSectionLevel > 0)
687 {
688 if (mSection.string)
689 {
690 delete [] mSection.string;
691 }
692 if (mSection.tag)
693 {
694 delete [] mSection.tag;
695 }
696 mSection = *mpSectionStackPtr;
697 mpSectionStackPtr++;
698 mSectionLevel--;
699 return TRUE;
700 }
701 return FALSE;
702 }
703
704 ///////////////////////////////////////////////////////////////////////////////
PushSection(void)705 BOOL xml_reader::PushSection(void)
706 {
707 if (mSectionLevel < MAX_SECTION_NESTING)
708 {
709 mpSectionStackPtr--;
710 *mpSectionStackPtr = mSection;
711 mSectionLevel++;
712 return TRUE;
713 }
714 return FALSE;
715 }
716
717
718