1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 
23 #include "GenericParser2.h"
24 
25 #include <cstring>
26 #include "qcommon/qcommon.h"
27 
28 #define MAX_TOKEN_SIZE	1024
29 static char	token[MAX_TOKEN_SIZE];
30 
GetToken(char ** text,bool allowLineBreaks,bool readUntilEOL=false)31 static char *GetToken(char **text, bool allowLineBreaks, bool readUntilEOL = false)
32 {
33 	char	*pointer = *text;
34 	int		length = 0;
35 	int		c = 0;
36 	bool	foundLineBreak;
37 
38 	token[0] = 0;
39 	if (!pointer)
40 	{
41 		return token;
42 	}
43 
44 	while(1)
45 	{
46 		foundLineBreak = false;
47 		while(1)
48 		{
49 			c = *pointer;
50 			if (c > ' ')
51 			{
52 				break;
53 			}
54 			if (!c)
55 			{
56 				*text = 0;
57 				return token;
58 			}
59 			if (c == '\n')
60 			{
61 				foundLineBreak = true;
62 			}
63 			pointer++;
64 		}
65 		if (foundLineBreak && !allowLineBreaks)
66 		{
67 			*text = pointer;
68 			return token;
69 		}
70 
71 		c = *pointer;
72 
73 		// skip single line comment
74 		if (c == '/' && pointer[1] == '/')
75 		{
76 			pointer += 2;
77 			while (*pointer && *pointer != '\n')
78 			{
79 				pointer++;
80 			}
81 		}
82 		// skip multi line comments
83 		else if (c == '/' && pointer[1] == '*')
84 		{
85 			pointer += 2;
86 			while (*pointer && (*pointer != '*' || pointer[1] != '/'))
87 			{
88 				pointer++;
89 			}
90 			if (*pointer)
91 			{
92 				pointer += 2;
93 			}
94 		}
95 		else
96 		{	// found the start of a token
97 			break;
98 		}
99 	}
100 
101 	if (c == '\"')
102 	{	// handle a string
103 		pointer++;
104 		while (1)
105 		{
106 			c = *pointer++;
107 			if (c == '\"')
108 			{
109 //				token[length++] = c;
110 				break;
111 			}
112 			else if (!c)
113 			{
114 				break;
115 			}
116 			else if (length < MAX_TOKEN_SIZE)
117 			{
118 				token[length++] = c;
119 			}
120 		}
121 	}
122 	else if (readUntilEOL)
123 	{
124 		// absorb all characters until EOL
125 		while(c != '\n' && c != '\r')
126 		{
127 			if (c == '/' && ((*(pointer+1)) == '/' || (*(pointer+1)) == '*'))
128 			{
129 				break;
130 			}
131 
132 			if (length < MAX_TOKEN_SIZE)
133 			{
134 				token[length++] = c;
135 			}
136 			pointer++;
137 			c = *pointer;
138 		}
139 		// remove trailing white space
140 		while(length && token[length-1] < ' ')
141 		{
142 			length--;
143 		}
144 	}
145 	else
146 	{
147 		while(c > ' ')
148 		{
149 			if (length < MAX_TOKEN_SIZE)
150 			{
151 				token[length++] = c;
152 			}
153 			pointer++;
154 			c = *pointer;
155 		}
156 	}
157 
158 	if (token[0] == '\"')
159 	{	// remove start quote
160 		length--;
161 		memmove(token, token+1, length);
162 
163 		if (length && token[length-1] == '\"')
164 		{	// remove end quote
165 			length--;
166 		}
167 	}
168 
169 	if (length >= MAX_TOKEN_SIZE)
170 	{
171 		length = 0;
172 	}
173 	token[length] = 0;
174 	*text = (char *)pointer;
175 
176 	return token;
177 }
178 
CTextPool(int initSize)179 CTextPool::CTextPool(int initSize) :
180 	mNext(0),
181 	mSize(initSize),
182 	mUsed(0)
183 {
184 //	mPool = (char *)Z_Malloc(mSize, TAG_GP2);
185 	mPool = (char *)Z_Malloc(mSize, TAG_TEXTPOOL, qtrue);
186 }
187 
~CTextPool(void)188 CTextPool::~CTextPool(void)
189 {
190 	Z_Free(mPool);
191 }
192 
AllocText(char * text,bool addNULL,CTextPool ** poolPtr)193 char *CTextPool::AllocText(char *text, bool addNULL, CTextPool **poolPtr)
194 {
195 	int	length = strlen(text) + (addNULL ? 1 : 0);
196 
197 	if (mUsed + length + 1> mSize)
198 	{	// extra 1 to put a null on the end
199 		if (poolPtr)
200 		{
201 			(*poolPtr)->SetNext(new CTextPool(mSize));
202 			*poolPtr = (*poolPtr)->GetNext();
203 
204 			return (*poolPtr)->AllocText(text, addNULL);
205 		}
206 
207 		return 0;
208 	}
209 
210 	strcpy(mPool + mUsed, text);
211 	mUsed += length;
212 	mPool[mUsed] = 0;
213 
214 	return mPool + mUsed - length;
215 }
216 
CleanTextPool(CTextPool * pool)217 void CleanTextPool(CTextPool *pool)
218 {
219 	CTextPool *next;
220 
221 	while(pool)
222 	{
223 		next = pool->GetNext();
224 		delete pool;
225 		pool = next;
226 	}
227 }
228 
229 
230 
231 
232 
233 
234 
CGPObject(const char * initName)235 CGPObject::CGPObject(const char *initName) :
236 	mName(initName),
237 	mNext(0),
238 	mInOrderNext(0),
239 	mInOrderPrevious(0)
240 {
241 }
242 
WriteText(CTextPool ** textPool,const char * text)243 bool CGPObject::WriteText(CTextPool **textPool, const char *text)
244 {
245    if (strchr(text, ' ') || !text[0])
246    {
247 	   (*textPool)->AllocText("\"", false, textPool);
248 	   (*textPool)->AllocText((char *)text, false, textPool);
249 	   (*textPool)->AllocText("\"", false, textPool);
250    }
251    else
252    {
253 	   (*textPool)->AllocText((char *)text, false, textPool);
254    }
255 
256    return true;
257 }
258 
259 
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 
270 
271 
CGPValue(const char * initName,const char * initValue)272 CGPValue::CGPValue(const char *initName, const char *initValue) :
273 	CGPObject(initName),
274 	mList(0)
275 {
276 	if (initValue)
277 	{
278 		AddValue(initValue);
279 	}
280 }
281 
~CGPValue(void)282 CGPValue::~CGPValue(void)
283 {
284 	CGPObject	*next;
285 
286 	while(mList)
287 	{
288 		next = mList->GetNext();
289 		delete mList;
290 		mList = next;
291 	}
292 }
293 
Duplicate(CTextPool ** textPool)294 CGPValue *CGPValue::Duplicate(CTextPool **textPool)
295 {
296 	CGPValue	*newValue;
297 	CGPObject	*iterator;
298 	char		*name;
299 
300 	if (textPool)
301 	{
302 		name = (*textPool)->AllocText((char *)mName, true, textPool);
303 	}
304 	else
305 	{
306 		name = (char *)mName;
307 	}
308 
309 	newValue = new CGPValue(name);
310 	iterator = mList;
311 	while(iterator)
312 	{
313 		if (textPool)
314 		{
315 			name = (*textPool)->AllocText((char *)iterator->GetName(), true, textPool);
316 		}
317 		else
318 		{
319 			name = (char *)iterator->GetName();
320 		}
321 		newValue->AddValue(name);
322 		iterator = iterator->GetNext();
323 	}
324 
325 	return newValue;
326 }
327 
IsList(void)328 bool CGPValue::IsList(void)
329 {
330 	if (!mList || !mList->GetNext())
331 	{
332 		return false;
333 	}
334 
335 	return true;
336 }
337 
GetTopValue(void)338 const char *CGPValue::GetTopValue(void)
339 {
340 	if (mList)
341 	{
342 		return mList->GetName();
343 	}
344 
345 	return 0;
346 }
347 
AddValue(const char * newValue,CTextPool ** textPool)348 void CGPValue::AddValue(const char *newValue, CTextPool **textPool)
349 {
350 	if (textPool)
351 	{
352 		newValue = (*textPool)->AllocText((char *)newValue, true, textPool);
353 	}
354 
355 	if (mList == 0)
356 	{
357 		mList = new CGPObject(newValue);
358 		mList->SetInOrderNext(mList);
359 	}
360 	else
361 	{
362 		mList->GetInOrderNext()->SetNext(new CGPObject(newValue));
363 		mList->SetInOrderNext(mList->GetInOrderNext()->GetNext());
364 	}
365 }
366 
Parse(char ** dataPtr,CTextPool ** textPool)367 bool CGPValue::Parse(char **dataPtr, CTextPool **textPool)
368 {
369 	char		*token;
370 	char		*value;
371 
372 	while(1)
373 	{
374 		token = GetToken(dataPtr, true, true);
375 
376 		if (!token[0])
377 		{	// end of data - error!
378 			return false;
379 		}
380 		else if (Q_stricmp(token, "]") == 0)
381 		{	// ending brace for this list
382 			break;
383 		}
384 
385 		value = (*textPool)->AllocText(token, true, textPool);
386 		AddValue(value);
387 	}
388 
389 	return true;
390 }
391 
Write(CTextPool ** textPool,int depth)392 bool CGPValue::Write(CTextPool **textPool, int depth)
393 {
394 	int				i;
395 	CGPObject	*next;
396 
397 	if (!mList)
398 	{
399 		return true;
400 	}
401 
402 	for(i=0;i<depth;i++)
403 	{
404 		(*textPool)->AllocText("\t", false, textPool);
405 	}
406 
407 	WriteText(textPool, mName);
408 
409 	if (!mList->GetNext())
410 	{
411 		(*textPool)->AllocText("\t\t", false, textPool);
412 		mList->WriteText(textPool, mList->GetName());
413 		(*textPool)->AllocText("\r\n", false, textPool);
414 	}
415 	else
416 	{
417 		(*textPool)->AllocText("\r\n", false, textPool);
418 
419 		for(i=0;i<depth;i++)
420 		{
421 			(*textPool)->AllocText("\t", false, textPool);
422 		}
423 		(*textPool)->AllocText("[\r\n", false, textPool);
424 
425 		next = mList;
426 		while(next)
427 		{
428 			for(i=0;i<depth+1;i++)
429 			{
430 				(*textPool)->AllocText("\t", false, textPool);
431 			}
432 			mList->WriteText(textPool, next->GetName());
433 			(*textPool)->AllocText("\r\n", false, textPool);
434 
435 			next = next->GetNext();
436 		}
437 
438 		for(i=0;i<depth;i++)
439 		{
440 			(*textPool)->AllocText("\t", false, textPool);
441 		}
442 		(*textPool)->AllocText("]\r\n", false, textPool);
443 	}
444 
445 	return true;
446 }
447 
448 
449 
450 
451 
452 
453 
454 
455 
456 
457 
458 
459 
460 
461 
462 
CGPGroup(const char * initName,CGPGroup * initParent)463 CGPGroup::CGPGroup(const char *initName, CGPGroup *initParent) :
464 	CGPObject(initName),
465 	mPairs(0),
466 	mInOrderPairs(0),
467 	mCurrentPair(0),
468 	mSubGroups(0),
469 	mInOrderSubGroups(0),
470 	mCurrentSubGroup(0),
471 	mParent(initParent),
472 	mWriteable(false)
473 {
474 }
475 
~CGPGroup(void)476 CGPGroup::~CGPGroup(void)
477 {
478 	Clean();
479 }
480 
GetNumSubGroups(void)481 int CGPGroup::GetNumSubGroups(void)
482 {
483 	int			count;
484 	CGPGroup	*group;
485 
486 	count = 0;
487 	group = mSubGroups;
488 	do
489 	{
490 		count++;
491 		group = (CGPGroup *)group->GetNext();
492 	}
493 	while(group);
494 
495 	return(count);
496 }
497 
GetNumPairs(void)498 int CGPGroup::GetNumPairs(void)
499 {
500 	int			count;
501 	CGPValue	*pair;
502 
503 	count = 0;
504 	pair = mPairs;
505 	do
506 	{
507 		count++;
508 		pair = (CGPValue *)pair->GetNext();
509 	}
510 	while(pair);
511 
512 	return(count);
513 }
514 
Clean(void)515 void CGPGroup::Clean(void)
516 {
517 	while(mPairs)
518 	{
519 		mCurrentPair = (CGPValue *)mPairs->GetNext();
520 		delete mPairs;
521 		mPairs = mCurrentPair;
522 	}
523 
524 	while(mSubGroups)
525 	{
526 		mCurrentSubGroup = (CGPGroup *)mSubGroups->GetNext();
527 		delete mSubGroups;
528 		mSubGroups = mCurrentSubGroup;
529 	}
530 
531 	mPairs = mInOrderPairs = mCurrentPair = 0;
532 	mSubGroups = mInOrderSubGroups = mCurrentSubGroup = 0;
533 	mParent = 0;
534 	mWriteable = false;
535 }
536 
Duplicate(CTextPool ** textPool,CGPGroup * initParent)537 CGPGroup *CGPGroup::Duplicate(CTextPool **textPool, CGPGroup *initParent)
538 {
539 	CGPGroup	*newGroup, *subSub, *newSub;
540 	CGPValue	*newPair, *subPair;
541 	char		*name;
542 
543 	if (textPool)
544 	{
545 		name = (*textPool)->AllocText((char *)mName, true, textPool);
546 	}
547 	else
548 	{
549 		name = (char *)mName;
550 	}
551 
552 	newGroup = new CGPGroup(name);
553 
554 	subSub = mSubGroups;
555 	while(subSub)
556 	{
557 		newSub = subSub->Duplicate(textPool, newGroup);
558 		newGroup->AddGroup(newSub);
559 
560 		subSub = (CGPGroup *)subSub->GetNext();
561 	}
562 
563 	subPair = mPairs;
564 	while(subPair)
565 	{
566 		newPair = subPair->Duplicate(textPool);
567 		newGroup->AddPair(newPair);
568 
569 		subPair = (CGPValue *)subPair->GetNext();
570 	}
571 
572 	return newGroup;
573 }
574 
SortObject(CGPObject * object,CGPObject ** unsortedList,CGPObject ** sortedList,CGPObject ** lastObject)575 void CGPGroup::SortObject(CGPObject *object, CGPObject **unsortedList, CGPObject **sortedList,
576 							 CGPObject **lastObject)
577 {
578 	CGPObject	*test, *last;
579 
580 	if (!*unsortedList)
581 	{
582 		*unsortedList = *sortedList = object;
583 	}
584 	else
585 	{
586 		(*lastObject)->SetNext(object);
587 
588 		test = *sortedList;
589 		last = 0;
590 		while(test)
591 		{
592 			if (Q_stricmp(object->GetName(), test->GetName()) < 0)
593 			{
594 				break;
595 			}
596 
597 			last = test;
598 			test = test->GetInOrderNext();
599 		}
600 
601 		if (test)
602 		{
603 			test->SetInOrderPrevious(object);
604 			object->SetInOrderNext(test);
605 		}
606 		if (last)
607 		{
608 			last->SetInOrderNext(object);
609 			object->SetInOrderPrevious(last);
610 		}
611 		else
612 		{
613 			*sortedList = object;
614 		}
615 	}
616 
617 	*lastObject = object;
618 }
619 
AddPair(const char * name,const char * value,CTextPool ** textPool)620 CGPValue *CGPGroup::AddPair(const char *name, const char *value, CTextPool **textPool)
621 {
622 	CGPValue	*newPair;
623 
624 	if (textPool)
625 	{
626 		name = (*textPool)->AllocText((char *)name, true, textPool);
627 		if (value)
628 		{
629 			value = (*textPool)->AllocText((char *)value, true, textPool);
630 		}
631 	}
632 
633 	newPair = new CGPValue(name, value);
634 
635 	AddPair(newPair);
636 
637 	return newPair;
638 }
639 
AddPair(CGPValue * NewPair)640 void CGPGroup::AddPair(CGPValue *NewPair)
641 {
642 	SortObject(NewPair, (CGPObject **)&mPairs, (CGPObject **)&mInOrderPairs,
643 		(CGPObject **)&mCurrentPair);
644 }
645 
AddGroup(const char * name,CTextPool ** textPool)646 CGPGroup *CGPGroup::AddGroup(const char *name, CTextPool **textPool)
647 {
648 	CGPGroup	*newGroup;
649 
650 	if (textPool)
651 	{
652 		name = (*textPool)->AllocText((char *)name, true, textPool);
653 	}
654 
655 	newGroup = new CGPGroup(name, this);
656 
657 	AddGroup(newGroup);
658 
659 	return newGroup;
660 }
661 
AddGroup(CGPGroup * NewGroup)662 void CGPGroup::AddGroup(CGPGroup *NewGroup)
663 {
664 	SortObject(NewGroup, (CGPObject **)&mSubGroups, (CGPObject **)&mInOrderSubGroups,
665 		(CGPObject **)&mCurrentSubGroup);
666 }
667 
FindSubGroup(const char * name)668 CGPGroup *CGPGroup::FindSubGroup(const char *name)
669 {
670 	CGPGroup	*group;
671 
672 	group = mSubGroups;
673 	while(group)
674 	{
675 		if(!Q_stricmp(name, group->GetName()))
676 		{
677 			return(group);
678 		}
679 		group = (CGPGroup *)group->GetNext();
680 	}
681 	return(NULL);
682 }
683 
Parse(char ** dataPtr,CTextPool ** textPool)684 bool CGPGroup::Parse(char **dataPtr, CTextPool **textPool)
685 {
686 	char		*token;
687 	char		lastToken[MAX_TOKEN_SIZE];
688 	CGPGroup	*newSubGroup;
689 	CGPValue	*newPair;
690 
691 	while(1)
692 	{
693 		token = GetToken(dataPtr, true);
694 
695 		if (!token[0])
696 		{	// end of data - error!
697 			if (mParent)
698 			{
699 				return false;
700 			}
701 			else
702 			{
703 				break;
704 			}
705 		}
706 		else if (Q_stricmp(token, "}") == 0)
707 		{	// ending brace for this group
708 			break;
709 		}
710 
711 		strcpy(lastToken, token);
712 
713 		// read ahead to see what we are doing
714 		token = GetToken(dataPtr, true, true);
715 		if (Q_stricmp(token, "{") == 0)
716 		{	// new sub group
717 			newSubGroup = AddGroup(lastToken, textPool);
718 			newSubGroup->SetWriteable(mWriteable);
719 			if (!newSubGroup->Parse(dataPtr, textPool))
720 			{
721 				return false;
722 			}
723 		}
724 		else if (Q_stricmp(token, "[") == 0)
725 		{	// new pair list
726 			newPair = AddPair(lastToken, 0, textPool);
727 			if (!newPair->Parse(dataPtr, textPool))
728 			{
729 				return false;
730 			}
731 		}
732 		else
733 		{	// new pair
734 			AddPair(lastToken, token, textPool);
735 		}
736 	}
737 
738 	return true;
739 }
740 
Write(CTextPool ** textPool,int depth)741 bool CGPGroup::Write(CTextPool **textPool, int depth)
742 {
743 	int				i;
744 	CGPValue		*mPair = mPairs;
745 	CGPGroup		*mSubGroup = mSubGroups;
746 
747 	if (depth >= 0)
748 	{
749 		for(i=0;i<depth;i++)
750 		{
751 			(*textPool)->AllocText("\t", false, textPool);
752 		}
753 		WriteText(textPool, mName);
754 		(*textPool)->AllocText("\r\n", false, textPool);
755 
756 		for(i=0;i<depth;i++)
757 		{
758 			(*textPool)->AllocText("\t", false, textPool);
759 		}
760 		(*textPool)->AllocText("{\r\n", false, textPool);
761 	}
762 
763 	while(mPair)
764 	{
765 		mPair->Write(textPool, depth+1);
766 		mPair = (CGPValue *)mPair->GetNext();
767 	}
768 
769 	while(mSubGroup)
770 	{
771 		mSubGroup->Write(textPool, depth+1);
772 		mSubGroup = (CGPGroup *)mSubGroup->GetNext();
773 	}
774 
775 	if (depth >= 0)
776 	{
777 		for(i=0;i<depth;i++)
778 		{
779 			(*textPool)->AllocText("\t", false, textPool);
780 		}
781 		(*textPool)->AllocText("}\r\n", false, textPool);
782 	}
783 
784 	return true;
785 }
786 
787 /************************************************************************************************
788  * CGPGroup::FindPair
789  *    This function will search for the pair with the specified key name.  Multiple keys may be
790  *    searched if you specify "||" inbetween each key name in the string.  The first key to be
791  *    found (from left to right) will be returned.
792  *
793  * Input
794  *    key: the name of the key(s) to be searched for.
795  *
796  * Output / Return
797  *    the group belonging to the first key found or 0 if no group was found.
798  *
799  ************************************************************************************************/
FindPair(const char * key)800 CGPValue *CGPGroup::FindPair(const char *key)
801 {
802 	CGPValue		*pair;
803 	size_t			length;
804 	const char		*pos, *separator, *next;
805 
806 	pos = key;
807 	while(pos[0])
808 	{
809 		separator = strstr(pos, "||");
810 		if (separator)
811 		{
812 			length = separator - pos;
813 			next = separator + 2;
814 		}
815 		else
816 		{
817 			length = strlen(pos);
818 			next = pos + length;
819 		}
820 
821 		pair = mPairs;
822 		while(pair)
823 		{
824 			if (strlen(pair->GetName()) == length &&
825 				Q_stricmpn(pair->GetName(), pos, length) == 0)
826 			{
827 				return pair;
828 			}
829 
830 			pair = pair->GetNext();
831 		}
832 
833 		pos = next;
834 	}
835 
836 	return 0;
837 }
838 
FindPairValue(const char * key,const char * defaultVal)839 const char *CGPGroup::FindPairValue(const char *key, const char *defaultVal)
840 {
841 	CGPValue		*pair = FindPair(key);
842 
843 	if (pair)
844 	{
845 		return pair->GetTopValue();
846 	}
847 
848 	return defaultVal;
849 }
850 
851 
852 
853 
854 
855 
856 
857 
858 
859 
860 
861 
862 
863 
864 
CGenericParser2(void)865 CGenericParser2::CGenericParser2(void) :
866 	mTextPool(0),
867 	mWriteable(false)
868 {
869 }
870 
~CGenericParser2(void)871 CGenericParser2::~CGenericParser2(void)
872 {
873 	Clean();
874 }
875 
Parse(char ** dataPtr,bool cleanFirst,bool writeable)876 bool CGenericParser2::Parse(char **dataPtr, bool cleanFirst, bool writeable)
877 {
878 	CTextPool	*topPool;
879 
880 	if (cleanFirst)
881 	{
882 		Clean();
883 	}
884 
885 	if (!mTextPool)
886 	{
887 		mTextPool = new CTextPool;
888 	}
889 
890 	SetWriteable(writeable);
891 	mTopLevel.SetWriteable(writeable);
892 	topPool = mTextPool;
893 	bool ret = mTopLevel.Parse(dataPtr, &topPool);
894 
895 	return ret;
896 }
897 
Clean(void)898 void CGenericParser2::Clean(void)
899 {
900 	mTopLevel.Clean();
901 
902 	CleanTextPool(mTextPool);
903 	mTextPool = 0;
904 }
905 
Write(CTextPool * textPool)906 bool CGenericParser2::Write(CTextPool *textPool)
907 {
908 	return mTopLevel.Write(&textPool, -1);
909 }
910 
911 
912 
913 
914 
915 
916 
917 
918 
919 // The following groups of routines are used for a C interface into GP2.
920 // C++ users should just use the objects as normally and not call these routines below
921 //
922 // CGenericParser2 (void *) routines
GP_Parse(char ** dataPtr,bool cleanFirst,bool writeable)923 TGenericParser2 GP_Parse(char **dataPtr, bool cleanFirst, bool writeable)
924 {
925 	CGenericParser2		*parse;
926 
927 	parse = new CGenericParser2;
928 	if (parse->Parse(dataPtr, cleanFirst, writeable))
929 	{
930 		return parse;
931 	}
932 
933 	delete parse;
934 	return 0;
935 }
936 
GP_Clean(TGenericParser2 GP2)937 void GP_Clean(TGenericParser2 GP2)
938 {
939 	if (!GP2)
940 	{
941 		return;
942 	}
943 
944 	((CGenericParser2 *)GP2)->Clean();
945 }
946 
GP_Delete(TGenericParser2 * GP2)947 void GP_Delete(TGenericParser2 *GP2)
948 {
949 	if (!GP2 || !(*GP2))
950 	{
951 		return;
952 	}
953 
954 	delete ((CGenericParser2 *)(*GP2));
955 	(*GP2) = 0;
956 }
957 
GP_GetBaseParseGroup(TGenericParser2 GP2)958 TGPGroup GP_GetBaseParseGroup(TGenericParser2 GP2)
959 {
960 	if (!GP2)
961 	{
962 		return 0;
963 	}
964 
965 	return ((CGenericParser2 *)GP2)->GetBaseParseGroup();
966 }
967 
968 
969 
970 
971 // CGPGroup (void *) routines
GPG_GetName(TGPGroup GPG)972 const char	*GPG_GetName(TGPGroup GPG)
973 {
974 	if (!GPG)
975 	{
976 		return "";
977 	}
978 
979 	return ((CGPGroup *)GPG)->GetName();
980 }
981 
GPG_GetName(TGPGroup GPG,char * Value)982 bool GPG_GetName(TGPGroup GPG, char *Value)
983 {
984 	if (!GPG)
985 	{
986 		Value[0] = 0;
987 		return false;
988 	}
989 
990 	strcpy(Value, ((CGPGroup *)GPG)->GetName());
991 	return true;
992 }
993 
GPG_GetNext(TGPGroup GPG)994 TGPGroup GPG_GetNext(TGPGroup GPG)
995 {
996 	if (!GPG)
997 	{
998 		return 0;
999 	}
1000 
1001 	return ((CGPGroup *)GPG)->GetNext();
1002 }
1003 
GPG_GetInOrderNext(TGPGroup GPG)1004 TGPGroup GPG_GetInOrderNext(TGPGroup GPG)
1005 {
1006 	if (!GPG)
1007 	{
1008 		return 0;
1009 	}
1010 
1011 	return ((CGPGroup *)GPG)->GetInOrderNext();
1012 }
1013 
GPG_GetInOrderPrevious(TGPGroup GPG)1014 TGPGroup GPG_GetInOrderPrevious(TGPGroup GPG)
1015 {
1016 	if (!GPG)
1017 	{
1018 		return 0;
1019 	}
1020 
1021 	return ((CGPGroup *)GPG)->GetInOrderPrevious();
1022 }
1023 
GPG_GetPairs(TGPGroup GPG)1024 TGPGroup GPG_GetPairs(TGPGroup GPG)
1025 {
1026 	if (!GPG)
1027 	{
1028 		return 0;
1029 	}
1030 
1031 	return ((CGPGroup *)GPG)->GetPairs();
1032 }
1033 
GPG_GetInOrderPairs(TGPGroup GPG)1034 TGPGroup GPG_GetInOrderPairs(TGPGroup GPG)
1035 {
1036 	if (!GPG)
1037 	{
1038 		return 0;
1039 	}
1040 
1041 	return ((CGPGroup *)GPG)->GetInOrderPairs();
1042 }
1043 
GPG_GetSubGroups(TGPGroup GPG)1044 TGPGroup GPG_GetSubGroups(TGPGroup GPG)
1045 {
1046 	if (!GPG)
1047 	{
1048 		return 0;
1049 	}
1050 
1051 	return ((CGPGroup *)GPG)->GetSubGroups();
1052 }
1053 
GPG_GetInOrderSubGroups(TGPGroup GPG)1054 TGPGroup GPG_GetInOrderSubGroups(TGPGroup GPG)
1055 {
1056 	if (!GPG)
1057 	{
1058 		return 0;
1059 	}
1060 
1061 	return ((CGPGroup *)GPG)->GetInOrderSubGroups();
1062 }
1063 
GPG_FindSubGroup(TGPGroup GPG,const char * name)1064 TGPGroup GPG_FindSubGroup(TGPGroup GPG, const char *name)
1065 {
1066 	if (!GPG)
1067 	{
1068 		return 0;
1069 	}
1070 
1071 	return ((CGPGroup *)GPG)->FindSubGroup(name);
1072 }
1073 
GPG_FindPair(TGPGroup GPG,const char * key)1074 TGPValue GPG_FindPair(TGPGroup GPG, const char *key)
1075 {
1076 	if (!GPG)
1077 	{
1078 		return 0;
1079 	}
1080 
1081 	return ((CGPGroup *)GPG)->FindPair(key);
1082 }
1083 
GPG_FindPairValue(TGPGroup GPG,const char * key,const char * defaultVal)1084 const char *GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal)
1085 {
1086 	if (!GPG)
1087 	{
1088 		return defaultVal;
1089 	}
1090 
1091 	return ((CGPGroup *)GPG)->FindPairValue(key, defaultVal);
1092 }
1093 
GPG_FindPairValue(TGPGroup GPG,const char * key,const char * defaultVal,char * Value)1094 bool GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal, char *Value)
1095 {
1096 	strcpy(Value, GPG_FindPairValue(GPG, key, defaultVal));
1097 
1098 	return true;
1099 }
1100 
1101 
1102 
1103 
1104 // CGPValue (void *) routines
GPV_GetName(TGPValue GPV)1105 const char	*GPV_GetName(TGPValue GPV)
1106 {
1107 	if (!GPV)
1108 	{
1109 		return "";
1110 	}
1111 
1112 	return ((CGPValue *)GPV)->GetName();
1113 }
1114 
GPV_GetName(TGPValue GPV,char * Value)1115 bool GPV_GetName(TGPValue GPV, char *Value)
1116 {
1117 	if (!GPV)
1118 	{
1119 		Value[0] = 0;
1120 		return false;
1121 	}
1122 
1123 	strcpy(Value, ((CGPValue *)GPV)->GetName());
1124 	return true;
1125 }
1126 
GPV_GetNext(TGPValue GPV)1127 TGPValue GPV_GetNext(TGPValue GPV)
1128 {
1129 	if (!GPV)
1130 	{
1131 		return 0;
1132 	}
1133 
1134 	return ((CGPValue *)GPV)->GetNext();
1135 }
1136 
GPV_GetInOrderNext(TGPValue GPV)1137 TGPValue GPV_GetInOrderNext(TGPValue GPV)
1138 {
1139 	if (!GPV)
1140 	{
1141 		return 0;
1142 	}
1143 
1144 	return ((CGPValue *)GPV)->GetInOrderNext();
1145 }
1146 
GPV_GetInOrderPrevious(TGPValue GPV)1147 TGPValue GPV_GetInOrderPrevious(TGPValue GPV)
1148 {
1149 	if (!GPV)
1150 	{
1151 		return 0;
1152 	}
1153 
1154 	return ((CGPValue *)GPV)->GetInOrderPrevious();
1155 }
1156 
GPV_IsList(TGPValue GPV)1157 bool GPV_IsList(TGPValue GPV)
1158 {
1159 	if (!GPV)
1160 	{
1161 		return 0;
1162 	}
1163 
1164 	return ((CGPValue *)GPV)->IsList();
1165 }
1166 
GPV_GetTopValue(TGPValue GPV)1167 const char *GPV_GetTopValue(TGPValue GPV)
1168 {
1169 	if (!GPV)
1170 	{
1171 		return "";
1172 	}
1173 
1174 	return ((CGPValue *)GPV)->GetTopValue();
1175 }
1176 
GPV_GetTopValue(TGPValue GPV,char * Value)1177 bool GPV_GetTopValue(TGPValue GPV, char *Value)
1178 {
1179 	if (!GPV)
1180 	{
1181 		Value[0] = 0;
1182 		return false;
1183 	}
1184 
1185 	strcpy(Value, ((CGPValue *)GPV)->GetTopValue());
1186 
1187 	return true;
1188 }
1189 
GPV_GetList(TGPValue GPV)1190 TGPValue GPV_GetList(TGPValue GPV)
1191 {
1192 	if (!GPV)
1193 	{
1194 		return 0;
1195 	}
1196 
1197 	return ((CGPValue *)GPV)->GetList();
1198 }
1199