1 /* nl-xml-json.c - newLISP XML and JSON interface
2 
3     Copyright (C) 2016 Lutz Mueller
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 #include "newlisp.h"
21 #include "protos.h"
22 
23 #ifdef XML_SUPPORT
24 
25 #define XML_TEXT 0
26 #define XML_CDATA 1
27 #define XML_COMMENT 2
28 #define XML_ELEMENT 3
29 
30 int isWhiteSpaceStringN(char * source, int tagPos);
31 CELL * makeTagSymbolCell(char * tagStart, int tagLen);
32 void performXmlCallback(CELL * cell, char * start);
33 
34 char * typeNames[] =
35   {
36   "TEXT",
37   "CDATA",
38   "COMMENT",
39   "ELEMENT"
40   };
41 
42 CELL * xmlTags = NULL;
43 CELL * typeCell[4];
44 
45 static char * xmlError;
46 static char xmlMsg[64];
47 static char * sourceOrg;
48 static char * source;
49 
50 static SYMBOL * XMLcontext;
51 
52 UINT optionsFlag;
53 #define OPTION_NO_OPTION 0
54 #define OPTION_NO_WHITESPACE 1
55 #define OPTION_NO_EMPTY_ATTRIBUTES 2
56 #define OPTION_NO_COMMENTS 4
57 #define OPTION_TAGS_TO_SYMBOLS 8
58 #define OPTION_SXML_ATTRIBUTES 16
59 
60 
61 typedef struct
62     {
63     char * name;
64     void * next;
65     } TAG_STACK;
66 
67 TAG_STACK * tagStack = NULL;
68 
69 CELL * xmlCallback = NULL;
70 
71 /* setup type tag default cells, if done already just relink */
setupTypeTagCells(void)72 CELL * setupTypeTagCells(void)
73 {
74 int i;
75 
76 if(xmlTags == NULL)
77     {
78     xmlTags = getCell(CELL_EXPRESSION);
79     for(i = 0; i < 4; i++)
80         typeCell[i] = stuffString(typeNames[i]);
81     }
82 
83 /* link cells in a list */
84 xmlTags->contents = (UINT)typeCell[0];
85 for(i = 0; i < 3; i++)
86     typeCell[i]->next = typeCell[i+1];
87 
88 return(xmlTags);
89 }
90 
p_XMLtypeTags(CELL * params)91 CELL * p_XMLtypeTags(CELL * params)
92 {
93 int i;
94 
95 if(params == nilCell)
96     return(copyCell(setupTypeTagCells()));
97 
98 if(xmlTags != NULL)
99     deleteList(xmlTags);
100 
101 xmlTags = getCell(CELL_EXPRESSION);
102 
103 for(i = 0; i < 4; i++)
104     {
105     typeCell[i] = copyCell(evaluateExpression(params));
106     params = params->next;
107     }
108 
109 return(copyCell(setupTypeTagCells()));
110 }
111 
p_XMLparse(CELL * params)112 CELL * p_XMLparse(CELL * params)
113 {
114 CELL * result;
115 
116 if(xmlCallback != NULL)
117     errorProc(ERR_NOT_REENTRANT);
118 
119 params = getString(params, &source);
120 if(params != nilCell)
121     {
122     params = getInteger(params, &optionsFlag);
123     if(params != nilCell)
124         {
125         XMLcontext = getCreateContext(params, TRUE);
126         if(XMLcontext == NULL)
127             return(errorProc(ERR_SYMBOL_OR_CONTEXT_EXPECTED));
128         if(params->next != nilCell)
129             xmlCallback = params->next;
130         else
131             xmlCallback = NULL;
132         }
133     else
134         XMLcontext = currentContext;
135     }
136 else
137     optionsFlag = OPTION_NO_OPTION;
138 
139 setupTypeTagCells();
140 
141 xmlError = NULL;
142 sourceOrg = source;
143 deleteTagStack();
144 
145 result = parseDoc();
146 deleteTagStack();
147 
148 xmlCallback = NULL;
149 
150 if(xmlError != NULL)
151     return nilCell;
152 else
153     return result;
154 }
155 
156 
p_XMLerror(CELL * params)157 CELL * p_XMLerror(CELL * params)
158 {
159 CELL * errorCell;
160 CELL * cell;
161 
162 if(xmlError == NULL)
163     return(nilCell);
164 
165 cell = stuffString(xmlError);
166 errorCell = makeCell(CELL_EXPRESSION, (UINT)cell);
167 
168 cell->next = stuffInteger((UINT)(source - sourceOrg));
169 
170 return errorCell;
171 }
172 
deleteTagStack(void)173 void deleteTagStack(void)
174 {
175 TAG_STACK * oldTagStack;
176 
177 while(tagStack != NULL)
178     {
179     oldTagStack = tagStack;
180     freeMemory(tagStack->name);
181     tagStack = tagStack->next;
182     freeMemory(oldTagStack);
183     }
184 }
185 
186 
parseDoc(void)187 CELL * parseDoc(void)
188 {
189 CELL * node;
190 CELL * lastNode;
191 int closingFlag = FALSE;
192 int tagPos;
193 
194 lastNode = node = getCell(CELL_EXPRESSION);
195 
196 while(!xmlError && !closingFlag)
197     {
198     if((tagPos = find("<", source)) == -1) break;
199     if(tagPos > 0)
200         {
201         if( (tagStack != NULL) || (node->contents != (UINT)nilCell))
202             {
203             if((optionsFlag & OPTION_NO_WHITESPACE) && isWhiteSpaceStringN(source, tagPos))
204                         {;}
205             else lastNode = appendNode(lastNode, makeTextNode(XML_TEXT, stuffStringN(source, tagPos)));
206             }
207         source = source + tagPos;
208         }
209 
210     if(strncmp(source, "<!DOCTYPE", 9) == 0)
211         {
212         parseDTD();
213         continue;
214         }
215 
216     if(*source == '<' && *(source + 1) == '?')
217         {
218         parseProcessingInstruction();
219         continue;
220         }
221 
222     if(memcmp(source, "<!--", 4) == 0)
223         {
224         if(optionsFlag & OPTION_NO_COMMENTS)
225             parseTag("-->");
226         else
227             lastNode = appendNode(lastNode, parseTag("-->"));
228         continue;
229         }
230     if(memcmp(source, "<![CDATA[", 9) == 0)
231         {
232         lastNode = appendNode(lastNode, parseTag("]]>"));
233         continue;
234         }
235 
236     if(*source == '<' && *(source + 1) == '/')
237         {
238         closingFlag = TRUE;
239         parseClosing();
240         continue;
241         }
242 
243     lastNode = appendNode(lastNode, parseTag(">"));
244     }
245 
246 
247 if(xmlError != NULL)
248     {
249     deleteList(node);
250     return nilCell;
251     }
252 
253 return node;
254 }
255 
256 
parseDTD(void)257 void parseDTD(void)
258 {
259 int closeTag, squareTag;
260 int closePos = 0;
261 char * closeTagStr;
262 
263 if((closeTag = find(">", source)) == -1)
264     {
265     xmlError = "error in DTD: expected '>'";
266     return;
267     }
268 
269 squareTag = find("[", source);
270 if(squareTag != -1 && squareTag < closeTag)
271     closeTagStr = "]>";
272 else
273     closeTagStr = ">";
274 
275 while(!xmlError)
276     {
277     if((closePos = find(closeTagStr, source)) == -1)
278         {
279         snprintf(xmlMsg, 63, "expected: %s", closeTagStr);
280         xmlError = xmlMsg;
281         return;
282         }
283     if(*(source + closePos - 1) != ']')
284         break;
285     source = source + closePos + strlen(closeTagStr);
286     }
287 
288 source = source + closePos + strlen(closeTagStr);
289 return;
290 }
291 
292 
parseProcessingInstruction(void)293 void parseProcessingInstruction(void)
294 {
295 int closeTag;
296 
297 if((closeTag = find("?>", source)) == -1)
298     {
299     xmlError = "expecting closing tag sequence '?>'";
300     return;
301     }
302 
303 source = source + closeTag + 2;
304 }
305 
306 
parseClosing(void)307 void parseClosing(void)
308 {
309 int closeTag;
310 char * tagName;
311 TAG_STACK * oldTagStack;
312 
313 if((closeTag = find(">", source)) == -1)
314     {
315     xmlError = "missing closing >";
316     return;
317     }
318 
319 if(tagStack == NULL)
320     {
321     xmlError = "closing tag has no opening";
322     return;
323     }
324 
325 tagName = tagStack->name;
326 if(strncmp(source + 2, tagName, strlen(tagName)) != 0)
327     {
328     xmlError = "closing tag doesn't match";
329     return;
330     }
331 
332 /* pop tagStack */
333 freeMemory(tagName);
334 oldTagStack = tagStack;
335 tagStack = tagStack->next;
336 
337 freeMemory(oldTagStack);
338 
339 source = source + closeTag + 1;
340 }
341 
342 
parseTag(char * closeTagStr)343 CELL * parseTag(char * closeTagStr)
344 {
345 char * newSrc;
346 char * tagStart;
347 int closeTag;
348 CELL * cell;
349 
350 tagStart = source;
351 
352 cell = NULL;
353 closeTag = find(closeTagStr, source);
354 if(*(source + closeTag - 1) == '/')
355     {
356     if(memcmp(closeTagStr,"]]>",3) != 0)
357         {
358         --closeTag;
359         closeTagStr = "/>";
360         }
361     }
362 
363 if(closeTag == -1)
364     {
365     snprintf(xmlMsg, 63, "expected closing tag: %s", closeTagStr);
366     xmlError = xmlMsg;
367     return nilCell;
368     }
369 
370 if(memcmp(source, "<!--", 4) == 0)
371     {
372     if(optionsFlag & OPTION_NO_COMMENTS)
373         cell = nilCell;
374     else
375         {
376         cell = stuffStringN(source + 4, closeTag - 4);
377         cell = makeTextNode(XML_COMMENT, cell);
378         }
379     }
380 
381 if(memcmp(source, "<![CDATA[", 9) == 0)
382     {
383     cell = stuffStringN(source + 9, closeTag - 9);
384     cell = makeTextNode(XML_CDATA, cell);
385     }
386 
387 if(*source == '<' && *(source + 1) == '/')
388     {
389     xmlError = "closing node has no opening";
390     return nilCell;
391     }
392 
393 newSrc = source + closeTag + strlen(closeTagStr);
394 
395 if(cell == NULL)
396     cell = parseNormalTag(source + closeTag, newSrc);
397 else
398     source = newSrc;
399 
400 /* call back with closed tag expression found
401    and opening start and end of source of this
402    tag expression
403 */
404 
405 if(xmlCallback)
406     performXmlCallback(cell, tagStart);
407 
408 return(cell);
409 }
410 
411 
performXmlCallback(CELL * result,char * tagStart)412 void performXmlCallback(CELL * result, char * tagStart)
413 {
414 CELL * list;
415 CELL * cell;
416 CELL * next;
417 int errNo;
418 
419 list = makeCell(CELL_EXPRESSION, (UINT)copyCell(xmlCallback));
420 cell = makeCell(CELL_QUOTE, (UINT)copyCell(result));
421 
422 cell->next = stuffInteger((UINT)(tagStart - sourceOrg));
423 next = cell->next;
424 next->next = stuffInteger((UINT)(source - tagStart));
425 ((CELL*)list->contents)->next = cell;
426 pushResult(list);
427 if(!evaluateExpressionSafe(list, &errNo))
428     {
429     deleteTagStack();
430     longjmp(errorJump, errNo);
431     }
432 }
433 
434 
parseNormalTag(char * endSrc,char * newSrc)435 CELL * parseNormalTag(char * endSrc, char * newSrc)
436 {
437 char * tagStart;
438 int tagLen;
439 CELL * attributes;
440 CELL * childs;
441 CELL * tagCell;
442 TAG_STACK * tag;
443 
444 ++source; /* skip '/' */
445 
446 while((unsigned char)*source <= ' ' && source < endSrc) ++source; /* skip whitespace */
447 
448 tagStart = source;
449 tagLen = 0;
450 while((unsigned char)*source > ' ' && source < endSrc) ++source, ++tagLen; /* find tag end */
451 
452 if(tagLen > MAX_SYMBOL)
453     {
454     xmlError = "tag name too long";
455     return nilCell;
456     }
457 
458 attributes = parseAttributes(endSrc);
459 if(optionsFlag & OPTION_SXML_ATTRIBUTES)
460     {
461     childs = (CELL*)attributes->contents;
462     if(! (childs == nilCell && (optionsFlag & OPTION_NO_EMPTY_ATTRIBUTES)))
463         {
464         attributes->contents = (UINT)stuffSymbol(atSymbol);
465         ((CELL*)(attributes->contents))->next = childs;
466         }
467     }
468 
469 if(xmlError)
470     return nilCell;
471 
472 if(*source == '/' && *(source + 1) == '>')
473     {
474     source = newSrc;
475     if(optionsFlag & OPTION_TAGS_TO_SYMBOLS)
476         tagCell = makeTagSymbolCell(tagStart, tagLen);
477     else
478         tagCell = stuffStringN(tagStart, tagLen);
479     return makeElementNode(tagCell, attributes, getCell(CELL_EXPRESSION));
480     }
481 
482 /* push tag on tagstack */
483 tag = (TAG_STACK*)allocMemory(sizeof(TAG_STACK));
484 tag->name = (char *)callocMemory(tagLen + 1);
485 memcpy(tag->name, tagStart, tagLen);
486 tag->next = tagStack;
487 tagStack = tag;
488 
489 source = newSrc;
490 childs = parseDoc();
491 
492 if(optionsFlag & OPTION_TAGS_TO_SYMBOLS)
493     tagCell = makeTagSymbolCell(tagStart, tagLen);
494 else
495     tagCell = stuffStringN(tagStart, tagLen);
496 
497 return makeElementNode(tagCell, attributes, childs);
498 }
499 
500 
makeTagSymbolCell(char * tagStart,int tagLen)501 CELL * makeTagSymbolCell(char * tagStart, int tagLen)
502 {
503 char * name;
504 char * ptr;
505 CELL * cell;
506 
507 name = (char *)callocMemory(tagLen + 1);
508 memcpy(name, tagStart, tagLen);
509 
510 if(optionsFlag & OPTION_TAGS_TO_SYMBOLS)
511     if((ptr = strstr(name, ":")))  *ptr = '.';
512 
513 cell = stuffSymbol(translateCreateSymbol(name, CELL_NIL, XMLcontext, 1));
514 freeMemory(name);
515 return(cell);
516 }
517 
518 
parseAttributes(char * endSrc)519 CELL * parseAttributes(char * endSrc)
520 {
521 CELL * attributes;
522 CELL * att;
523 CELL * cell;
524 CELL * lastAtt;
525 char * namePos;
526 char * valPos;
527 char quoteChar;
528 int  nameLen, valLen;
529 
530 attributes = getCell(CELL_EXPRESSION);
531 lastAtt = NULL;
532 
533 while(!xmlError && source < endSrc)
534     {
535     while((unsigned char)*source <= ' ' && source < endSrc) source++; /* strip leading space */
536     namePos = source;
537     nameLen = 0;
538     while((unsigned char)*source > ' ' && *source != '=' && source < endSrc) source++, nameLen++; /* get end */
539     if(nameLen == 0) break;
540     if(nameLen > MAX_SYMBOL)
541         {
542         xmlError = "attribute name too long";
543         return nilCell;
544         }
545     while((unsigned char)*source <= ' ' && source < endSrc) source++; /* strip leading space */
546     if(*source != '=')
547         {
548         xmlError = "expected '=' in attributes";
549         deleteList(attributes);
550         return nilCell;
551         }
552     else source++;
553     while((unsigned char)*source <= ' ' && source < endSrc) source++; /* strip spaces */
554     if(*source != '\"' && *source != '\'')
555         {
556         xmlError = "attribute values must be delimited by \" or \' ";
557         deleteList(attributes);
558         return nilCell;
559         }
560     quoteChar = *source;
561     source++;
562     valPos = source;
563     valLen = 0;
564     while(*source != quoteChar && source < endSrc) source++, valLen++;
565     if(*source != quoteChar) valLen = -1;
566     else source++;
567     if(nameLen == 0 || valLen == -1)
568         {
569         xmlError = "incorrect attribute";
570         deleteList(attributes);
571         return nilCell;
572         }
573     att = getCell(CELL_EXPRESSION);
574     if(optionsFlag & OPTION_TAGS_TO_SYMBOLS)
575             cell = makeTagSymbolCell(namePos, nameLen);
576     else
577         cell = stuffStringN(namePos, nameLen);
578     cell->next = stuffStringN(valPos, valLen);
579     att->contents = (UINT)cell;
580     if(lastAtt == NULL)
581         attributes->contents = (UINT)att;
582     else
583         lastAtt->next = att;
584     lastAtt = att;
585     }
586 
587 return attributes;
588 }
589 
590 
appendNode(CELL * node,CELL * newNode)591 CELL * appendNode(CELL * node, CELL * newNode)
592 {
593 if(node->contents == (UINT)nilCell)
594     node->contents = (UINT)newNode;
595 else
596     node->next = newNode;
597 
598 return newNode;
599 }
600 
601 
makeTextNode(int type,CELL * contents)602 CELL * makeTextNode(int type, CELL * contents)
603 {
604 CELL * cell;
605 
606 /* unwrap text node if nil xml-type-tag */
607 if(typeCell[type]->type == CELL_NIL)
608     return(contents);
609 
610 cell = copyCell(typeCell[type]);
611 cell->next = contents;
612 
613 return(makeCell(CELL_EXPRESSION, (UINT)cell));
614 }
615 
616 
makeElementNode(CELL * tagNode,CELL * attributesNode,CELL * childrenNode)617 CELL * makeElementNode(CELL * tagNode, CELL * attributesNode, CELL * childrenNode)
618 {
619 CELL * newNode;
620 CELL * cell;
621 
622 /* unwrap children node, if nil in xml-type-tag */
623 if(typeCell[XML_ELEMENT]->type == CELL_NIL)
624     {
625     cell = childrenNode;
626     childrenNode = (CELL *)childrenNode->contents;
627     cell->contents = (UINT)nilCell;
628     deleteList(cell);
629     }
630 
631 newNode = getCell(CELL_EXPRESSION);
632 if(typeCell[XML_ELEMENT]->type == CELL_NIL)
633     newNode->contents = (UINT)tagNode;
634 else
635     {
636     cell = copyCell(typeCell[XML_ELEMENT]);
637     newNode->contents = (UINT)cell;
638     cell->next = tagNode;
639     }
640 
641 if( (attributesNode->contents == (UINT)nilCell) &&
642     (optionsFlag & OPTION_NO_EMPTY_ATTRIBUTES))
643     {
644     tagNode->next = childrenNode;
645     deleteList(attributesNode);
646     }
647 else
648     {
649     tagNode->next = attributesNode;
650     attributesNode->next = childrenNode;
651     }
652 
653 return newNode;
654 }
655 
656 
find(char * key,char * source)657 int find(char * key, char * source)
658 {
659 char * ptr;
660 
661 ptr = strstr(source, key);
662 if(ptr == NULL) return -1;
663 
664 return(ptr - source);
665 }
666 
667 
isWhiteSpaceStringN(char * source,int tagPos)668 int isWhiteSpaceStringN(char * source, int tagPos)
669 {
670 while(tagPos--) if((unsigned char)*source++ > 32) return(FALSE);
671 return(TRUE);
672 }
673 
674 #endif /* XML_SUPPORT */
675 
676 /* --------------------------------- JSON interface ------------------------- */
677 
678 CELL * getJSONobject(char * jsonStr, char * * restStr);
679 CELL * getJSONstring(char * jsonStr, char * * restStr);
680 CELL * getJSONvalue(char * jsonStr, char * * restStr);
681 CELL * setJSONerror(char * errorText, char * jsonStr);
682 
683 #define ERR_JSON_MISSING_BRACE "missing {"
684 #define ERR_JSON_MISSING_COLON "missing : colon"
685 #define ERR_JSON_INVALID_OBJECT "invalid JSON object"
686 #define ERR_JSON_MISSING_KEY "missing key"
687 #define ERR_JSON_CLOSING_QUOTE "missing closing quote"
688 #define ERR_JSON_INVALID_UNICODE "invalid unicode"
689 #define ERR_JSON_INVALID_NUMBER "invalid JSON number format"
690 #define ERR_JSON_INVALID_ARRAY "invalid JSON array format"
691 #define ERR_JSON_INVALID_VALUE "invalid JSON value format"
692 
693 CELL * lastJSONerror = NULL;
694 char * jsonStrStart;
695 
p_JSONparse(CELL * params)696 CELL * p_JSONparse(CELL * params)
697 {
698 char * restStr;
699 
700 if(lastJSONerror) deleteList(lastJSONerror);
701 lastJSONerror = nilCell;
702 getString(params, &jsonStrStart);
703 return(getJSONvalue(jsonStrStart, &restStr));
704 }
705 
706 
getJSONobject(char * jsonStr,char ** restStr)707 CELL * getJSONobject(char * jsonStr, char * * restStr)
708 {
709 CELL * object;
710 CELL * pair = NULL;
711 CELL * key;
712 char * ptr;
713 
714 
715 /* a JSON object is a (key value) association expression */
716 while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr; /* whitespace */
717 
718 if(*jsonStr != '{')
719     return(setJSONerror(ERR_JSON_MISSING_BRACE, jsonStr));
720 
721 ++jsonStr;
722 /* make object envelope */
723 while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr; /* whitespace */
724 object = getCell(CELL_EXPRESSION);
725 if(*jsonStr == '}')
726     {
727     *restStr = jsonStr + 1;
728     return(object);
729     }
730 
731 /* get a key : value pair */
732 GET_PAIR:
733 if(pair == NULL)
734     {
735     pair = getCell(CELL_EXPRESSION);
736     object->contents = (UINT)pair; /* !!! only the first time then pair->next */
737     }
738 else
739     {
740     pair->next = getCell(CELL_EXPRESSION);
741     pair = pair->next;
742     }
743 
744 /* get key string */
745 if((key = getJSONstring(jsonStr, &ptr)) == nilCell)
746     {
747     deleteList(object);
748     return(nilCell);
749     }
750 pair->contents = (UINT)key;
751 jsonStr = ptr;
752 
753 /* key and value must be separated by : colon */
754 while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr; /* whitespace */
755 if(*jsonStr != ':')
756     {
757     deleteList(object);
758     return(setJSONerror(ERR_JSON_MISSING_COLON, jsonStr));
759     }
760 
761 if((key->next = getJSONvalue(++jsonStr, &ptr)) == nilCell)
762     {
763     deleteList(object);
764     return(nilCell);
765     }
766 
767 jsonStr = ptr;
768 
769 while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr; /* whitespace */
770 if(*jsonStr == '}')
771     {
772     *restStr = jsonStr + 1;
773     return(object);
774     }
775 
776 if(*jsonStr == ',')
777     {
778     ++jsonStr;
779     goto GET_PAIR;
780     }
781 
782 deleteList(object);
783 return(setJSONerror(ERR_JSON_INVALID_OBJECT, jsonStr));
784 }
785 
786 
getJSONstring(char * jsonStr,char ** restStr)787 CELL * getJSONstring(char * jsonStr, char * * restStr)
788 {
789 char * token;
790 char * xlated;
791 size_t size;
792 int i, j;
793 #ifdef SUPPORT_UTF8
794 int len;
795 char buff[8];
796 #endif
797 
798 /* get key string */
799 while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr; /* whitespace */
800 
801 if(*jsonStr != '"') return(setJSONerror(ERR_JSON_MISSING_KEY, jsonStr));
802 
803 token = ++jsonStr, size = 0;
804 while(*jsonStr != '"' && *jsonStr != 0)
805     {
806     if(*jsonStr == '\\')
807         ++jsonStr, ++size;
808     ++jsonStr, ++size;
809     }
810 
811 if(*jsonStr++ != '"') return(setJSONerror(ERR_JSON_CLOSING_QUOTE, jsonStr));
812 
813 *restStr = jsonStr;
814 
815 xlated = alloca(size + 1);
816 i = j = 0;
817 while(i < size)
818     {
819     if(*(token + i) == '\\')
820         {
821         ++i;
822         switch(*(token + i))
823             {
824             case '\\':
825                 *(xlated + j++) = '\\';
826                 break;
827             case '"':
828                 *(xlated + j++) = '"';
829                 break;
830             case '/':
831                 *(xlated + j++) = '/';
832                 break;
833             case 'b':
834                 *(xlated + j++) = '\b';
835                 break;
836             case 'f':
837                 *(xlated + j++) = '\f';
838                 break;
839             case 'n':
840                 *(xlated + j++) = '\n';
841                 break;
842             case 'r':
843                 *(xlated + j++) = '\r';
844                 break;
845             case 't':
846                 *(xlated + j++) = '\t';
847                 break;
848             case 'u':
849                 if(isxdigit((unsigned char)*(token + i + 1)) &&
850                    isxdigit((unsigned char)*(token + i + 2)) &&
851                    isxdigit((unsigned char)*(token + i + 3)) &&
852                    isxdigit((unsigned char)*(token + i + 4)))
853                     {
854 #ifdef SUPPORT_UTF8
855                     buff[0] = '0';
856                     buff[1] = 'x';
857                     memcpy(buff + 2, token + i + 1, 4);
858                     buff[6] = 0;
859                     len = wchar_utf8(strtol(buff, NULL, 16), xlated + j);
860                     j += len;
861 #else
862                     *(xlated + j) = '\\';
863                     memcpy(xlated + j + 1, token + i, 5);
864                     j += 6;
865 #endif
866                     i += 4;
867                     }
868                 else
869                     return(setJSONerror(ERR_JSON_INVALID_UNICODE, jsonStr));
870                 break;
871             default:
872                 *(xlated + j++) = *(token + i);
873                 break;
874             }
875         ++i;
876         }
877     else
878         *(xlated + j++) = *(token + i++);
879     }
880 
881 *(xlated + j) = 0;
882 return(stuffStringN(xlated, j));
883 }
884 
885 
886 /* get value as one of: string, number, object, array, true, false, null */
getJSONvalue(char * jsonStr,char ** restStr)887 CELL * getJSONvalue(char * jsonStr, char * * restStr)
888 {
889 CELL * cell;
890 CELL * array = NULL;
891 CELL * next = NULL;
892 char * ptr;
893 char * number;
894 size_t len;
895 int isFloat = FALSE;
896 double floatNumber;
897 SYMBOL * falseSymbol;
898 SYMBOL * nullSymbol;
899 
900 while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr; /* whitespace */
901 
902 /* string value */
903 if(*jsonStr == '"')
904     {
905     cell = getJSONstring(jsonStr, &ptr);
906     *restStr = ptr;
907     return(cell);
908     }
909 
910 /* check if number digit or + - */
911 if(isDigit((unsigned char)*jsonStr))
912     ptr = jsonStr++;
913 else if((*jsonStr == '-' || *jsonStr == '+') && isDigit((unsigned char)*(jsonStr + 1)))
914     ptr = jsonStr++;
915 else goto NOT_STRING_OR_NUMBER;
916 
917 number = alloca(32);
918 while(isDigit((unsigned char)*jsonStr)) ++jsonStr;
919 if(*jsonStr == '.')
920     {
921     isFloat = TRUE;
922     ++jsonStr;
923     while(isDigit((unsigned char)*jsonStr)) ++jsonStr;
924     }
925 
926 if(*jsonStr == 'e' || *jsonStr == 'E')
927     {
928     isFloat = TRUE;
929     ++jsonStr;
930     if(*jsonStr == '-' || *jsonStr == '+')
931         ++jsonStr;
932     if(!isDigit((unsigned char)*jsonStr))
933         return(setJSONerror(ERR_JSON_INVALID_NUMBER, jsonStr));
934         while(isDigit((unsigned char)*jsonStr)) ++jsonStr;
935     }
936 
937 /* number must end with space or control character  or white space*/
938 if(*jsonStr != ' ' && *jsonStr != '\n' && *jsonStr != '\n' && *jsonStr != '\t' && *jsonStr != '\f' &&
939    *jsonStr != ',' && *jsonStr != '}' && *jsonStr != ']' && *jsonStr != 0)
940     return(setJSONerror(ERR_JSON_INVALID_NUMBER, jsonStr));
941 
942 len = (size_t)jsonStr - (size_t)ptr;
943 memcpy(number, ptr, len);
944 number[len] = 0;
945 *restStr = jsonStr;
946 
947 if(isFloat)
948     {
949     floatNumber = atof(number);
950     return(stuffFloat(floatNumber));
951     }
952 else
953     return(stuffInteger64(atoll(number)));
954 
955 
956 NOT_STRING_OR_NUMBER:
957 /* it's one of object, array, true, false, null */
958 
959 switch(*jsonStr)
960     {
961     case '{':
962         cell = getJSONobject(jsonStr, &ptr);
963         break;
964     case '[':
965         GET_ARRAY_ELEMENT:
966         ++jsonStr;
967         while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr;
968         if(*jsonStr == ']')
969             {
970             *restStr = jsonStr + 1;
971             if(array) return(array);
972             return(getCell(CELL_EXPRESSION));
973             }
974         if((cell = getJSONvalue(jsonStr, &ptr)) == nilCell)
975             {
976             if(array) deleteList(array);
977             return(nilCell);
978             }
979         if(array == NULL)
980             {
981             array = getCell(CELL_EXPRESSION);
982             array->contents = (UINT)cell;
983             }
984         else
985             next->next = cell;
986         next = cell;
987         jsonStr = ptr;
988         /* whitespace */
989         while((unsigned char)*jsonStr <= ' ' && *jsonStr != 0) ++jsonStr;
990         if(*jsonStr == ',') goto GET_ARRAY_ELEMENT;
991         if(*jsonStr == ']')
992             {
993             *restStr = jsonStr + 1;
994             return(array);
995             }
996         deleteList(array);
997         return(setJSONerror(ERR_JSON_INVALID_ARRAY, jsonStr));
998     case 't':
999         if(strncmp(jsonStr, "true", 4) == 0)
1000             {
1001             cell = stuffSymbol(trueSymbol);
1002             ptr = jsonStr + 4;
1003             break;
1004             }
1005     case 'f':
1006         if(strncmp(jsonStr, "false", 5) == 0)
1007             {
1008             falseSymbol = translateCreateSymbol("false", CELL_SYMBOL, mainContext, TRUE);
1009             cell = stuffSymbol(falseSymbol);
1010             ptr = jsonStr + 5;
1011             break;
1012             }
1013     case 'n':
1014         if(strncmp(jsonStr, "null", 4) == 0)
1015             {
1016             nullSymbol = translateCreateSymbol("null", CELL_SYMBOL, mainContext, TRUE);
1017             cell = stuffSymbol(nullSymbol);
1018             ptr = jsonStr + 4;
1019             break;
1020             }
1021     default:
1022     return(setJSONerror(ERR_JSON_INVALID_VALUE, jsonStr));
1023     }
1024 
1025 *restStr = ptr;
1026 return(cell);
1027 }
1028 
1029 
p_JSONerror(CELL * params)1030 CELL * p_JSONerror(CELL * params)
1031 {
1032 return( lastJSONerror == NULL ? nilCell : copyCell(lastJSONerror));
1033 }
1034 
1035 
setJSONerror(char * errorText,char * jsonStr)1036 CELL * setJSONerror(char * errorText, char * jsonStr)
1037 {
1038 CELL * cell = stuffString(errorText);
1039 
1040 if(lastJSONerror) deleteList(lastJSONerror);
1041 
1042 lastJSONerror = getCell(CELL_EXPRESSION);
1043 lastJSONerror->contents = (UINT)cell;
1044 cell->next = stuffInteger((UINT)jsonStr - (UINT)jsonStrStart);
1045 
1046 return(nilCell);
1047 }
1048 
1049 /* eof */
1050 
1051 
1052