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("&lt;"), _T("<"));
247             escaped.Replace(_T("&gt;"), _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