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