Here the diff between the epics version (debian patch unapplyed) and the 
current 2.1.0 version of yajl (debian patch unapplyed).

not that simple...
diff --git a/src/yajl.c b/src/yajl.c
index d477893..fdad3f6 100644
--- a/src/yajl.c
+++ b/src/yajl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,16 +14,16 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "api/yajl_parse.h"
-#include "yajl_lex.h"
-#include "yajl_parser.h"
-#include "yajl_alloc.h"
-
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <assert.h>
 
+#include "yajl_parse.h"
+#include "yajl_lex.h"
+#include "yajl_parser.h"
+#include "yajl_alloc.h"
+
 const char *
 yajl_status_to_string(yajl_status stat)
 {
@@ -62,16 +62,19 @@ yajl_alloc(const yajl_callbacks * callbacks,
     }
 
     hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
+    if (hand == NULL) {
+        return NULL;
+    }
 
     /* copy in pointers to allocation routines */
     memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
 
     hand->callbacks = callbacks;
     hand->ctx = ctx;
-    hand->lexer = NULL; 
+    hand->lexer = NULL;
     hand->bytesConsumed = 0;
     hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
-    hand->flags	    = 0;
+    hand->flags     = yajl_allow_json5 | yajl_allow_comments;
     yajl_bs_init(hand->stateStack, &(hand->alloc));
     yajl_bs_push(hand->stateStack, yajl_state_start);
 
@@ -79,13 +82,16 @@ yajl_alloc(const yajl_callbacks * callbacks,
 }
 
 int
-yajl_config(yajl_handle h, yajl_option opt, ...)
+yajl_config(yajl_handle h, int option, ...)
 {
+    yajl_option opt = option;   /* UB to use an enum in va_start */
     int rv = 1;
     va_list ap;
-    va_start(ap, opt);
+    va_start(ap, option);
 
     switch(opt) {
+        case yajl_allow_json5:
+            opt |= yajl_allow_comments; /* JSON5 allows comments */
         case yajl_allow_comments:
         case yajl_dont_validate_strings:
         case yajl_allow_trailing_garbage:
@@ -124,7 +130,11 @@ yajl_parse(yajl_handle hand, const unsigned char * jsonText,
     if (hand->lexer == NULL) {
         hand->lexer = yajl_lex_alloc(&(hand->alloc),
                                      hand->flags & yajl_allow_comments,
-                                     !(hand->flags & yajl_dont_validate_strings));
+                                     !(hand->flags & yajl_dont_validate_strings),
+                                     hand->flags & yajl_allow_json5);
+    }
+    if (hand->lexer == NULL) {
+        return yajl_status_error;
     }
 
     status = yajl_do_parse(hand, jsonText, jsonTextLen);
@@ -144,7 +154,8 @@ yajl_complete_parse(yajl_handle hand)
     if (hand->lexer == NULL) {
         hand->lexer = yajl_lex_alloc(&(hand->alloc),
                                      hand->flags & yajl_allow_comments,
-                                     !(hand->flags & yajl_dont_validate_strings));
+                                     !(hand->flags & yajl_dont_validate_strings),
+                                     hand->flags & yajl_allow_json5);
     }
 
     return yajl_do_finish(hand);
diff --git a/src/yajl_alloc.c b/src/yajl_alloc.c
index 96ad1d3..2388814 100644
--- a/src/yajl_alloc.c
+++ b/src/yajl_alloc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,25 +20,23 @@
  * free
  */
 
-#include "yajl_alloc.h"
 #include <stdlib.h>
 
+#include "yajl_alloc.h"
+
 static void * yajl_internal_malloc(void *ctx, size_t sz)
 {
-    (void)ctx;
     return malloc(sz);
 }
 
 static void * yajl_internal_realloc(void *ctx, void * previous,
                                     size_t sz)
 {
-    (void)ctx;
     return realloc(previous, sz);
 }
 
 static void yajl_internal_free(void *ctx, void * ptr)
 {
-    (void)ctx;
     free(ptr);
 }
 
diff --git a/src/yajl_alloc.h b/src/yajl_alloc.h
index 203c2f9..406310a 100644
--- a/src/yajl_alloc.h
+++ b/src/yajl_alloc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,19 +16,31 @@
 
 /**
  * \file yajl_alloc.h
- * default memory allocation routines for yajl which use malloc/realloc and
- * free
+ * \brief Memory allocation macros for yajl
+ * \author Lloyd Hilaiel
+ *
+ * These macros are used inside YAJL instead of directly calling
+ * malloc(), realloc() or free(). They call the equivalent method
+ * in their \ref yajl_alloc_funcs parameter \a afs.
  */
 
 #ifndef __YAJL_ALLOC_H__
 #define __YAJL_ALLOC_H__
 
-#include "api/yajl_common.h"
+#include "yajl_common.h"
 
 #define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz))
 #define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr))
 #define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz))
 
-void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+YAJL_API void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif
diff --git a/src/yajl_buf.c b/src/yajl_buf.c
index 55c11ad..4bd8d74 100644
--- a/src/yajl_buf.c
+++ b/src/yajl_buf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,12 +14,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "yajl_buf.h"
-
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "yajl_buf.h"
+
 #define YAJL_BUF_INIT_SIZE 2048
 
 struct yajl_buf_t {
@@ -33,7 +33,7 @@ static
 void yajl_buf_ensure_available(yajl_buf buf, size_t want)
 {
     size_t need;
-    
+
     assert(buf != NULL);
 
     /* first call */
@@ -45,17 +45,7 @@ void yajl_buf_ensure_available(yajl_buf buf, size_t want)
 
     need = buf->len;
 
-    if (((buf->used > want) ? buf->used : want) > (size_t)(buf->used + want)) {
-        /* We cannot allocate more memory than SIZE_MAX. */
-        abort();
-    }
-    while (want >= (need - buf->used)) {
-        if (need >= (size_t)((size_t)(-1)<<1)>>1) {
-            /* need would overflow. */
-            abort();
-        }
-        need <<= 1;
-    }
+    while (want >= (need - buf->used)) need <<= 1;
 
     if (need != buf->len) {
         buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need);
@@ -66,6 +56,10 @@ void yajl_buf_ensure_available(yajl_buf buf, size_t want)
 yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc)
 {
     yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t));
+    if (b == NULL) {
+        return NULL;
+    }
+
     memset((void *) b, 0, sizeof(struct yajl_buf_t));
     b->alloc = alloc;
     return b;
diff --git a/src/yajl_buf.h b/src/yajl_buf.h
index a358246..40a6fbd 100644
--- a/src/yajl_buf.h
+++ b/src/yajl_buf.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,13 +17,13 @@
 #ifndef __YAJL_BUF_H__
 #define __YAJL_BUF_H__
 
-#include "api/yajl_common.h"
+#include "yajl_common.h"
 #include "yajl_alloc.h"
 
 /*
  * Implementation/performance notes.  If this were moved to a header
- * only implementation using #define's where possible we might be 
- * able to sqeeze a little performance out of the guy by killing function
+ * only implementation using #define's where possible we might be
+ * able to squeeze a little performance out of the guy by killing function
  * call overhead.  YMMV.
  */
 
@@ -33,6 +33,10 @@
  */
 typedef struct yajl_buf_t * yajl_buf;
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* allocate a new buffer */
 yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc);
 
@@ -54,4 +58,8 @@ size_t yajl_buf_len(yajl_buf buf);
 /* truncate the buffer */
 void yajl_buf_truncate(yajl_buf buf, size_t len);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/src/yajl_bytestack.h b/src/yajl_bytestack.h
index 9ea7d15..d75e456 100644
--- a/src/yajl_bytestack.h
+++ b/src/yajl_bytestack.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -22,7 +22,7 @@
 #ifndef __YAJL_BYTESTACK_H__
 #define __YAJL_BYTESTACK_H__
 
-#include "api/yajl_common.h"
+#include "yajl_common.h"
 
 #define YAJL_BS_INC 128
 
diff --git a/src/yajl_encode.c b/src/yajl_encode.c
index 0d97cc5..33cc780 100644
--- a/src/yajl_encode.c
+++ b/src/yajl_encode.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,13 +14,13 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "yajl_encode.h"
-
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
+#include "yajl_encode.h"
+
 static void CharToHex(unsigned char c, char * hexBuf)
 {
     const char * hexchar = "0123456789ABCDEF";
@@ -33,13 +33,22 @@ yajl_string_encode(const yajl_print_t print,
                    void * ctx,
                    const unsigned char * str,
                    size_t len,
-                   int escape_solidus)
+                   int escape_solidus,
+                   int output_json5)
 {
     size_t beg = 0;
     size_t end = 0;
     char hexBuf[7];
-    hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
-    hexBuf[6] = 0;
+    char *hexAt;
+    if (output_json5) {
+        hexBuf[0] = '\\'; hexBuf[1] = 'x';
+        hexBuf[4] = 0;
+        hexAt = &hexBuf[2];
+    } else {
+        hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
+        hexBuf[6] = 0;
+        hexAt = &hexBuf[4];
+    }
 
     while (end < len) {
         const char * escaped = NULL;
@@ -57,9 +66,20 @@ yajl_string_encode(const yajl_print_t print,
             case '\f': escaped = "\\f"; break;
             case '\b': escaped = "\\b"; break;
             case '\t': escaped = "\\t"; break;
+            case '\0':
+                if (output_json5) {
+                    escaped = "\\0"; break;
+                }
+                goto ashex;
+            case '\v':
+                if (output_json5) {
+                    escaped = "\\v"; break;
+                }
+                goto ashex;
             default:
                 if ((unsigned char) str[end] < 32) {
-                    CharToHex(str[end], hexBuf + 4);
+            ashex:
+                    CharToHex(str[end], hexAt);
                     escaped = hexBuf;
                 }
                 break;
@@ -75,10 +95,10 @@ yajl_string_encode(const yajl_print_t print,
     print(ctx, (const char *) (str + beg), end - beg);
 }
 
-static void hexToDigit(unsigned int * val, const unsigned char * hex)
+static void hexToDigit(unsigned int * val, unsigned int len, const unsigned char * hex)
 {
     unsigned int i;
-    for (i=0;i<4;i++) {
+    for (i=0;i<len;i++) {
         unsigned char c = hex[i];
         if (c >= 'A') c = (c & ~0x20) - 7;
         c -= '0';
@@ -87,7 +107,7 @@ static void hexToDigit(unsigned int * val, const unsigned char * hex)
     }
 }
 
-static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) 
+static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf)
 {
     if (codepoint < 0x80) {
         utf8Buf[0] = (char) codepoint;
@@ -117,7 +137,7 @@ void yajl_string_decode(yajl_buf buf, const unsigned char * str,
                         size_t len)
 {
     size_t beg = 0;
-    size_t end = 0;    
+    size_t end = 0;
 
     while (end < len) {
         if (str[end] == '\\') {
@@ -128,24 +148,21 @@ void yajl_string_decode(yajl_buf buf, const unsigned char * str,
                 case 'r': unescaped = "\r"; break;
                 case 'n': unescaped = "\n"; break;
                 case '\\': unescaped = "\\"; break;
-                case '/': unescaped = "/"; break;
-                case '"': unescaped = "\""; break;
                 case 'f': unescaped = "\f"; break;
                 case 'b': unescaped = "\b"; break;
                 case 't': unescaped = "\t"; break;
                 case 'u': {
                     unsigned int codepoint = 0;
-                    hexToDigit(&codepoint, str + ++end);
+                    hexToDigit(&codepoint, 4, str + ++end);
                     end+=3;
                     /* check if this is a surrogate */
                     if ((codepoint & 0xFC00) == 0xD800) {
-                        if (end + 2 < len && str[end + 1] == '\\' && str[end + 2] == 'u') {
-                            end++;
+                        if (str[end + 1] == '\\' && str[end + 2] == 'u') {
                             unsigned int surrogate = 0;
-                            hexToDigit(&surrogate, str + end + 2);
+                            hexToDigit(&surrogate, 4, str + ++end + 2);
                             codepoint =
-                                (((codepoint & 0x3F) << 10) | 
-                                 ((((codepoint >> 6) & 0xF) + 1) << 16) | 
+                                (((codepoint & 0x3F) << 10) |
+                                 ((((codepoint >> 6) & 0xF) + 1) << 16) |
                                  (surrogate & 0x3FF));
                             end += 5;
                         } else {
@@ -153,7 +170,7 @@ void yajl_string_decode(yajl_buf buf, const unsigned char * str,
                             break;
                         }
                     }
-                    
+
                     Utf32toUtf8(codepoint, utf8Buf);
                     unescaped = utf8Buf;
 
@@ -165,8 +182,33 @@ void yajl_string_decode(yajl_buf buf, const unsigned char * str,
 
                     break;
                 }
+                /* The following escapes are only valid when parsing JSON5.
+                 * The lexer catches them when allowJson5 is not set.
+                 */
+                case '\n': beg = ++end; continue;
+                case '\r':
+                    if (str[++end] == '\n') ++end;
+                    beg = end;
+                    continue;
+                case '0':
+                    utf8Buf[0] = '\0';
+                    yajl_buf_append(buf, utf8Buf, 1);
+                    beg = ++end;
+                    continue;
+                case 'v': unescaped = "\v"; break;
+                case 'x': {
+                    unsigned int codepoint = 0;
+                    hexToDigit(&codepoint, 2, str + ++end);
+                    end++;
+                    utf8Buf[0] = (char) codepoint;
+                    yajl_buf_append(buf, utf8Buf, 1);
+                    beg = ++end;
+                    continue;
+                }
                 default:
-                    assert("this should never happen" == NULL);
+                    utf8Buf[0] = str[end];
+                    utf8Buf[1] = 0;
+                    unescaped = utf8Buf;
             }
             yajl_buf_append(buf, unescaped, (unsigned int)strlen(unescaped));
             beg = ++end;
@@ -183,13 +225,13 @@ int yajl_string_validate_utf8(const unsigned char * s, size_t len)
 {
     if (!len) return 1;
     if (!s) return 0;
-    
+
     while (len--) {
         /* single byte */
         if (*s <= 0x7f) {
             /* noop */
         }
-        /* two byte */ 
+        /* two byte */
         else if ((*s >> 5) == 0x6) {
             ADV_PTR;
             if (!((*s >> 6) == 0x2)) return 0;
@@ -201,7 +243,7 @@ int yajl_string_validate_utf8(const unsigned char * s, size_t len)
             ADV_PTR;
             if (!((*s >> 6) == 0x2)) return 0;
         }
-        /* four byte */        
+        /* four byte */
         else if ((*s >> 3) == 0x1e) {
             ADV_PTR;
             if (!((*s >> 6) == 0x2)) return 0;
@@ -212,9 +254,33 @@ int yajl_string_validate_utf8(const unsigned char * s, size_t len)
         } else {
             return 0;
         }
-        
+
         s++;
     }
-    
+
+    return 1;
+}
+
+int yajl_string_validate_identifier(const unsigned char * str, size_t len)
+{
+    const unsigned char * s = str;
+    int c;
+
+    if (!len || !str) return 0;
+
+    c = *s++;       /* First character [$_A-Za-z] */
+    if ((c != '$' && c < 'A') ||
+        (c > 'Z' && c != '_' && c < 'a') ||
+        (c > 'z'))
+        return 0;
+
+    while (--len) {
+        c = *s++;   /* Remaining characters [$_A-Za-z0-9] */
+        if ((c != '$' && c < '0') ||
+            (c > '9' && c < 'A') ||
+            (c > 'Z' && c != '_' && c < 'a') ||
+            (c > 'z'))
+            return 0;
+    }
     return 1;
 }
diff --git a/src/yajl_encode.h b/src/yajl_encode.h
index 853a1a7..fd58dec 100644
--- a/src/yajl_encode.h
+++ b/src/yajl_encode.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,17 +18,28 @@
 #define __YAJL_ENCODE_H__
 
 #include "yajl_buf.h"
-#include "api/yajl_gen.h"
+#include "yajl_gen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 void yajl_string_encode(const yajl_print_t printer,
                         void * ctx,
                         const unsigned char * str,
                         size_t length,
-                        int escape_solidus);
+                        int escape_solidus,
+                        int output_json5);
 
 void yajl_string_decode(yajl_buf buf, const unsigned char * str,
                         size_t length);
 
 int yajl_string_validate_utf8(const unsigned char * s, size_t len);
 
+int yajl_string_validate_identifier(const unsigned char * str, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/src/yajl_gen.c b/src/yajl_gen.c
index 0f5c68e..6d93784 100644
--- a/src/yajl_gen.c
+++ b/src/yajl_gen.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,16 +14,16 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "api/yajl_gen.h"
-#include "yajl_buf.h"
-#include "yajl_encode.h"
-
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include <math.h>
 #include <stdarg.h>
 
+#include "epicsMath.h"
+#include "yajl_gen.h"
+#include "yajl_buf.h"
+#include "yajl_encode.h"
+
 typedef enum {
     yajl_gen_start,
     yajl_gen_map_start,
@@ -48,16 +48,17 @@ struct yajl_gen_t
 };
 
 int
-yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...)
+yajl_gen_config(yajl_gen g, int option, ...)
 {
+    yajl_gen_option opt = option;   /* UB to use an enum in va_start */
     int rv = 1;
     va_list ap;
-    va_start(ap, opt);
+    va_start(ap, option);
 
     switch(opt) {
         case yajl_gen_beautify:
         case yajl_gen_validate_utf8:
-        case yajl_gen_escape_solidus:
+        case yajl_gen_json5:
             if (va_arg(ap, int)) g->flags |= opt;
             else g->flags &= ~opt;
             break;
@@ -141,17 +142,17 @@ yajl_gen_free(yajl_gen g)
 }
 
 #define INSERT_SEP \
-    if (g->state[g->depth] == yajl_gen_map_key ||               \
-        g->state[g->depth] == yajl_gen_in_array) {              \
-        g->print(g->ctx, ",", 1);                               \
-        if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);               \
-    } else if (g->state[g->depth] == yajl_gen_map_val) {        \
-        g->print(g->ctx, ":", 1);                               \
-        if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1);                \
-   }
-
-#define INSERT_WHITESPACE                                               \
-    if ((g->flags & yajl_gen_beautify)) {                                                    \
+    if (g->state[g->depth] == yajl_gen_map_key ||                       \
+        g->state[g->depth] == yajl_gen_in_array) {                      \
+        g->print(g->ctx, ",", 1);                                       \
+        if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);  \
+    } else if (g->state[g->depth] == yajl_gen_map_val) {                \
+        g->print(g->ctx, ":", 1);                                       \
+        if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1);   \
+    }
+
+#define INSERT_WHITESPACE \
+    if ((g->flags & yajl_gen_beautify)) {                               \
         if (g->state[g->depth] != yajl_gen_map_val) {                   \
             unsigned int _i;                                            \
             for (_i=0;_i<g->depth;_i++)                                 \
@@ -170,8 +171,8 @@ yajl_gen_free(yajl_gen g)
 /* check that we're not complete, or in error state.  in a valid state
  * to be generating */
 #define ENSURE_VALID_STATE \
-    if (g->state[g->depth] == yajl_gen_error) {   \
-        return yajl_gen_in_error_state;\
+    if (g->state[g->depth] == yajl_gen_error) {             \
+        return yajl_gen_in_error_state;                     \
     } else if (g->state[g->depth] == yajl_gen_complete) {   \
         return yajl_gen_generation_complete;                \
     }
@@ -180,7 +181,7 @@ yajl_gen_free(yajl_gen g)
     if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
 
 #define DECREMENT_DEPTH \
-  if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_generation_complete;
+  if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
 
 #define APPENDED_ATOM \
     switch (g->state[g->depth]) {                   \
@@ -201,8 +202,9 @@ yajl_gen_free(yajl_gen g)
             break;                                  \
     }                                               \
 
-#define FINAL_NEWLINE                                        \
-    if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \
+#define FINAL_NEWLINE \
+    if ((g->flags & yajl_gen_beautify) &&           \
+        g->state[g->depth] == yajl_gen_complete)    \
         g->print(g->ctx, "\n", 1);
 
 yajl_gen_status
@@ -217,23 +219,28 @@ yajl_gen_integer(yajl_gen g, long long int number)
     return yajl_gen_status_ok;
 }
 
-#if defined(_WIN32) || defined(WIN32)
-#include <float.h>
-#define isnan _isnan
-#define isinf !_finite
-#endif
-
 yajl_gen_status
 yajl_gen_double(yajl_gen g, double number)
 {
     char i[32];
+    int special = 1;
     ENSURE_VALID_STATE; ENSURE_NOT_KEY;
-    if (isnan(number) || isinf(number)) return yajl_gen_invalid_number;
-    INSERT_SEP; INSERT_WHITESPACE;
-    sprintf(i, "%.20g", number);
-    if (strspn(i, "0123456789-") == strlen(i)) {
-        strcat(i, ".0");
+    if (isnan(number)) {
+        strcpy(i, "NaN");
+    }
+    else if (isinf(number)) {
+        sprintf(i, "%cInfinity", number < 0 ? '-' : '+');
+    }
+    else {
+        special = 0;
+        sprintf(i, "%.17g", number);
+        if (strspn(i, "0123456789-") == strlen(i)) {
+            strcat(i, ".0");
+        }
     }
+    if (special && !(g->flags & yajl_gen_json5))
+        return yajl_gen_invalid_number;
+    INSERT_SEP; INSERT_WHITESPACE;
     g->print(g->ctx, i, (unsigned int)strlen(i));
     APPENDED_ATOM;
     FINAL_NEWLINE;
@@ -263,9 +270,19 @@ yajl_gen_string(yajl_gen g, const unsigned char * str,
         }
     }
     ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE;
-    g->print(g->ctx, "\"", 1);
-    yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus);
-    g->print(g->ctx, "\"", 1);
+    if (g->flags & yajl_gen_json5 &&
+        (g->state[g->depth] == yajl_gen_map_key ||
+         g->state[g->depth] == yajl_gen_map_start) &&
+        yajl_string_validate_identifier(str, len)) {
+        /* No need to quote this key */
+        g->print(g->ctx, (const char *) str, len);
+    }
+    else {
+        g->print(g->ctx, "\"", 1);
+        yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus,
+            g->flags & yajl_gen_json5);
+        g->print(g->ctx, "\"", 1);
+    }
     APPENDED_ATOM;
     FINAL_NEWLINE;
     return yajl_gen_status_ok;
@@ -286,7 +303,7 @@ yajl_gen_bool(yajl_gen g, int boolean)
 {
     const char * val = boolean ? "true" : "false";
 
-	ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+    ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
     g->print(g->ctx, val, (unsigned int)strlen(val));
     APPENDED_ATOM;
     FINAL_NEWLINE;
diff --git a/src/yajl_lex.c b/src/yajl_lex.c
index 0b6f7cc..f79291c 100644
--- a/src/yajl_lex.c
+++ b/src/yajl_lex.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,14 +14,14 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "yajl_lex.h"
-#include "yajl_buf.h"
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <assert.h>
 #include <string.h>
 
+#include "yajl_lex.h"
+#include "yajl_buf.h"
+
 #ifdef YAJL_LEXER_DEBUG
 static const char *
 tokToStr(yajl_tok tok)
@@ -66,7 +66,7 @@ tokToStr(yajl_tok tok)
  */
 
 struct yajl_lexer_t {
-    /* the overal line and char offset into the data */
+    /* the overall line and char offset into the data */
     size_t lineOff;
     size_t charOff;
 
@@ -87,6 +87,9 @@ struct yajl_lexer_t {
     /* shall we allow comments? */
     unsigned int allowComments;
 
+    /* are we parsing JSON5? */
+    unsigned int allowJson5;
+
     /* shall we validate utf8 inside strings? */
     unsigned int validateUTF8;
 
@@ -102,13 +105,19 @@ struct yajl_lexer_t {
 
 yajl_lexer
 yajl_lex_alloc(yajl_alloc_funcs * alloc,
-               unsigned int allowComments, unsigned int validateUTF8)
+               unsigned int allowComments, unsigned int validateUTF8,
+               unsigned int allowJson5)
 {
     yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t));
+    if (lxr == NULL) {
+        return NULL;
+    }
+
     memset((void *) lxr, 0, sizeof(struct yajl_lexer_t));
     lxr->buf = yajl_buf_alloc(alloc);
     lxr->allowComments = allowComments;
     lxr->validateUTF8 = validateUTF8;
+    lxr->allowJson5 = !!allowJson5;
     lxr->alloc = alloc;
     return lxr;
 }
@@ -121,19 +130,21 @@ yajl_lex_free(yajl_lexer lxr)
     return;
 }
 
-/* a lookup table which lets us quickly determine three things:
+/* a lookup table which lets us quickly determine various things:
  * VEC - valid escaped control char
- * note.  the solidus '/' may be escaped or not.
+ *       Note: the solidus '/' may be escaped or not.
  * IJC - invalid json char
  * VHC - valid hex char
  * NFP - needs further processing (from a string scanning perspective)
  * NUC - needs utf8 checking when enabled (from a string scanning perspective)
+ * VIC - valid identifier char (after the first char)
  */
 #define VEC 0x01
 #define IJC 0x02
 #define VHC 0x04
 #define NFP 0x08
 #define NUC 0x10
+#define VIC 0x20
 
 static const char charLookupTable[256] =
 {
@@ -142,20 +153,20 @@ static const char charLookupTable[256] =
 /*10*/ IJC    , IJC    , IJC    , IJC    , IJC    , IJC    , IJC    , IJC    ,
 /*18*/ IJC    , IJC    , IJC    , IJC    , IJC    , IJC    , IJC    , IJC    ,
 
-/*20*/ 0      , 0      , NFP|VEC|IJC, 0      , 0      , 0      , 0      , 0      ,
+/*20*/ 0      , 0      , NFP|VEC, 0      , VIC    , 0      , 0      , NFP|VEC,
 /*28*/ 0      , 0      , 0      , 0      , 0      , 0      , 0      , VEC    ,
-/*30*/ VHC    , VHC    , VHC    , VHC    , VHC    , VHC    , VHC    , VHC    ,
-/*38*/ VHC    , VHC    , 0      , 0      , 0      , 0      , 0      , 0      ,
+/*30*/ VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC,
+/*38*/ VHC|VIC, VHC|VIC, 0      , 0      , 0      , 0      , 0      , 0      ,
 
-/*40*/ 0      , VHC    , VHC    , VHC    , VHC    , VHC    , VHC    , 0      ,
-/*48*/ 0      , 0      , 0      , 0      , 0      , 0      , 0      , 0      ,
-/*50*/ 0      , 0      , 0      , 0      , 0      , 0      , 0      , 0      ,
-/*58*/ 0      , 0      , 0      , 0      , NFP|VEC|IJC, 0      , 0      , 0      ,
+/*40*/ 0      , VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VIC    ,
+/*48*/ VIC    , VIC    , VIC    , VIC    , VIC    , VIC    , VIC    , VIC    ,
+/*50*/ VIC    , VIC    , VIC    , VIC    , VIC    , VIC    , VIC    , VIC    ,
+/*58*/ VIC    , VIC    , VIC    , 0      , NFP|VEC|IJC, 0  , 0      , VIC    ,
 
-/*60*/ 0      , VHC    , VEC|VHC, VHC    , VHC    , VHC    , VEC|VHC, 0      ,
-/*68*/ 0      , 0      , 0      , 0      , 0      , 0      , VEC    , 0      ,
-/*70*/ 0      , 0      , VEC    , 0      , VEC    , 0      , 0      , 0      ,
-/*78*/ 0      , 0      , 0      , 0      , 0      , 0      , 0      , 0      ,
+/*60*/ 0      , VHC|VIC, VEC|VHC|VIC, VHC|VIC, VHC|VIC, VHC|VIC, VEC|VHC|VIC, VIC,
+/*68*/ VIC    , VIC    , VIC    , VIC    , VIC    , VIC    , VEC|VIC, VIC    ,
+/*70*/ VIC    , VIC    , VEC|VIC, VIC    , VEC|VIC, VIC    , VIC    , VIC    ,
+/*78*/ VIC    , VIC    , VIC    , 0      , 0      , 0      , 0      , 0      ,
 
        NUC    , NUC    , NUC    , NUC    , NUC    , NUC    , NUC    , NUC    ,
        NUC    , NUC    , NUC    , NUC    , NUC    , NUC    , NUC    , NUC    ,
@@ -189,7 +200,7 @@ static const char charLookupTable[256] =
  *
  *  NOTE: on error the offset will point to the first char of the
  *  invalid utf8 */
-#define UTF8_CHECK_EOF if (*offset >= jsonTextLen) { return yajl_tok_eof; }
+#define UTF8_CHECK_EOF if (*offset >= jsonTextLen) return yajl_tok_eof;
 
 static yajl_tok
 yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText,
@@ -266,7 +277,7 @@ yajl_string_scan(const unsigned char * buf, size_t len, int utf8check)
 
 static yajl_tok
 yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText,
-                size_t jsonTextLen, size_t * offset)
+                size_t jsonTextLen, size_t * offset, const char quote)
 {
     yajl_tok tok = yajl_tok_error;
     int hasEscapes = 0;
@@ -301,7 +312,7 @@ yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText,
         curChar = readChar(lexer, jsonText, offset);
 
         /* quote terminates */
-        if (curChar == '"') {
+        if (curChar == quote) {
             tok = yajl_tok_string;
             break;
         }
@@ -321,16 +332,38 @@ yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText,
                     if (!(charLookupTable[curChar] & VHC)) {
                         /* back up to offending char */
                         unreadChar(lexer, offset);
-                        lexer->error = yajl_lex_string_invalid_hex_char;
+                        lexer->error = yajl_lex_string_invalid_hex_u_char;
                         goto finish_string_lex;
                     }
                 }
-            } else if (!(charLookupTable[curChar] & VEC)) {
+            }
+            else if (lexer->allowJson5 && curChar == 'x') {
+                unsigned int i = 0;
+
+                for (i=0;i<2;i++) {
+                    STR_CHECK_EOF;
+                    curChar = readChar(lexer, jsonText, offset);
+                    if (!(charLookupTable[curChar] & VHC)) {
+                        /* back up to offending char */
+                        unreadChar(lexer, offset);
+                        lexer->error = yajl_lex_string_invalid_hex_x_char;
+                        goto finish_string_lex;
+                    }
+                }
+            }
+            else if (lexer->allowJson5 ? (curChar >= '1' && curChar <= '9')
+                : !(charLookupTable[curChar] & VEC)) {
                 /* back up to offending char */
                 unreadChar(lexer, offset);
                 lexer->error = yajl_lex_string_invalid_escaped_char;
                 goto finish_string_lex;
             }
+            else if (lexer->allowJson5 && curChar == '\r') {
+                STR_CHECK_EOF;
+                curChar = readChar(lexer, jsonText, offset);
+                if (curChar != '\n')
+                    unreadChar(lexer, offset);
+            }
         }
         /* when not validating UTF8 it's a simple table lookup to determine
          * if the present character is invalid */
@@ -367,36 +400,83 @@ yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText,
 
 #define RETURN_IF_EOF if (*offset >= jsonTextLen) return yajl_tok_eof;
 
+/* For both identifiers and numbers, we always have to lex one
+ * character too many to know when they are complete.
+ */
+
+static yajl_tok
+yajl_lex_identifier(yajl_lexer lexer, const unsigned char * jsonText,
+                    size_t jsonTextLen, size_t * offset)
+{
+    unsigned char c;
+
+    do {
+        RETURN_IF_EOF;
+        c = readChar(lexer, jsonText, offset);
+    } while (charLookupTable[c] & VIC);
+
+    /* we always go "one too far" */
+    unreadChar(lexer, offset);
+
+    return yajl_tok_identifier;
+}
+
 static yajl_tok
 yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText,
                 size_t jsonTextLen, size_t * offset)
 {
-    /** XXX: numbers are the only entities in json that we must lex
-     *       _beyond_ in order to know that they are complete.  There
-     *       is an ambiguous case for integers at EOF. */
-
+    const char hexDigits[] = "0123456789abcdefABCDEF";
     unsigned char c;
+    int numRd = 0;
 
     yajl_tok tok = yajl_tok_integer;
 
     RETURN_IF_EOF;
     c = readChar(lexer, jsonText, offset);
 
-    /* optional leading minus */
-    if (c == '-') {
+    /* optional leading plus/minus */
+    if (c == '-' || (lexer->allowJson5 && c == '+')) {
         RETURN_IF_EOF;
         c = readChar(lexer, jsonText, offset);
     }
 
-    /* a single zero, or a series of integers */
+    if (c == 'I') {
+        const char * want = "nfinity";
+        do {
+            RETURN_IF_EOF;
+            c = readChar(lexer, jsonText, offset);
+            if (c != *want) {
+                unreadChar(lexer, offset);
+                lexer->error = yajl_lex_invalid_string;
+                return yajl_tok_error;
+            }
+        } while (*(++want));
+        if (!lexer->allowJson5) {
+            unreadChar(lexer, offset);
+            lexer->error = yajl_lex_unallowed_special_number;
+            return yajl_tok_error;
+        }
+        return yajl_tok_double;
+    }
+
+    /* a single zero, hex number, or a series of decimal digits */
     if (c == '0') {
+        numRd++;
         RETURN_IF_EOF;
         c = readChar(lexer, jsonText, offset);
+        if (c == 'x' || c == 'X') {
+            if (lexer->allowJson5) goto got_hex;
+            lexer->error = yajl_lex_unallowed_hex_integer;
+            return yajl_tok_error;
+        }
     } else if (c >= '1' && c <= '9') {
         do {
+            numRd++;
             RETURN_IF_EOF;
             c = readChar(lexer, jsonText, offset);
         } while (c >= '0' && c <= '9');
+    } else if (lexer->allowJson5 && c == '.') {
+        goto got_decimal;
     } else {
         unreadChar(lexer, offset);
         lexer->error = yajl_lex_missing_integer_after_minus;
@@ -405,10 +485,10 @@ yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText,
 
     /* optional fraction (indicates this is floating point) */
     if (c == '.') {
-        int numRd = 0;
-
+  got_decimal:
         RETURN_IF_EOF;
         c = readChar(lexer, jsonText, offset);
+        if (!lexer->allowJson5) numRd = 0;
 
         while (c >= '0' && c <= '9') {
             numRd++;
@@ -448,6 +528,25 @@ yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText,
         tok = yajl_tok_double;
     }
 
+    goto end_number;
+
+  got_hex:
+    RETURN_IF_EOF;
+    c = readChar(lexer, jsonText, offset);
+
+    if (strchr(hexDigits, c)) {
+        do {
+            RETURN_IF_EOF;
+            c = readChar(lexer, jsonText, offset);
+        } while (strchr(hexDigits, c));
+    }
+    else {
+        unreadChar(lexer, offset);
+        lexer->error = yajl_lex_missing_hex_digit_after_0x;
+        return yajl_tok_error;
+    }
+
+  end_number:
     /* we always go "one too far" */
     unreadChar(lexer, offset);
 
@@ -495,6 +594,23 @@ yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText,
     return tok;
 }
 
+/* Macro to reduce code duplication in yajl_lex_lex() */
+#define LEX_WANT(tring) \
+    const char * want = tring; \
+    do { \
+        if (*offset >= jsonTextLen) { \
+            tok = yajl_tok_eof; \
+            goto lexed; \
+        } \
+        c = readChar(lexer, jsonText, offset); \
+        if (c != *want) { \
+            unreadChar(lexer, offset); \
+            lexer->error = yajl_lex_invalid_string; \
+            tok = yajl_tok_error; \
+            goto lexed; \
+        } \
+    } while (*(++want))
+
 yajl_tok
 yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
              size_t jsonTextLen, size_t * offset,
@@ -519,16 +635,16 @@ yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
 
         switch (c) {
             case '{':
-                tok = yajl_tok_left_bracket;
+                tok = yajl_tok_left_brace;
                 goto lexed;
             case '}':
-                tok = yajl_tok_right_bracket;
+                tok = yajl_tok_right_brace;
                 goto lexed;
             case '[':
-                tok = yajl_tok_left_brace;
+                tok = yajl_tok_left_bracket;
                 goto lexed;
             case ']':
-                tok = yajl_tok_right_brace;
+                tok = yajl_tok_right_bracket;
                 goto lexed;
             case ',':
                 tok = yajl_tok_comma;
@@ -540,71 +656,58 @@ yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
                 startOffset++;
                 break;
             case 't': {
-                const char * want = "rue";
-                do {
-                    if (*offset >= jsonTextLen) {
-                        tok = yajl_tok_eof;
-                        goto lexed;
-                    }
-                    c = readChar(lexer, jsonText, offset);
-                    if (c != *want) {
-                        unreadChar(lexer, offset);
-                        lexer->error = yajl_lex_invalid_string;
-                        tok = yajl_tok_error;
-                        goto lexed;
-                    }
-                } while (*(++want));
+                LEX_WANT("rue");
                 tok = yajl_tok_bool;
                 goto lexed;
             }
             case 'f': {
-                const char * want = "alse";
-                do {
-                    if (*offset >= jsonTextLen) {
-                        tok = yajl_tok_eof;
-                        goto lexed;
-                    }
-                    c = readChar(lexer, jsonText, offset);
-                    if (c != *want) {
-                        unreadChar(lexer, offset);
-                        lexer->error = yajl_lex_invalid_string;
-                        tok = yajl_tok_error;
-                        goto lexed;
-                    }
-                } while (*(++want));
+                LEX_WANT("alse");
                 tok = yajl_tok_bool;
                 goto lexed;
             }
             case 'n': {
-                const char * want = "ull";
-                do {
-                    if (*offset >= jsonTextLen) {
-                        tok = yajl_tok_eof;
-                        goto lexed;
-                    }
-                    c = readChar(lexer, jsonText, offset);
-                    if (c != *want) {
-                        unreadChar(lexer, offset);
-                        lexer->error = yajl_lex_invalid_string;
-                        tok = yajl_tok_error;
-                        goto lexed;
-                    }
-                } while (*(++want));
+                LEX_WANT("ull");
                 tok = yajl_tok_null;
                 goto lexed;
             }
+            case 'I': {
+                LEX_WANT("nfinity");
+                if (!lexer->allowJson5) {
+                    unreadChar(lexer, offset);
+                    lexer->error = yajl_lex_unallowed_special_number;
+                    tok = yajl_tok_error;
+                } else {
+                    tok = yajl_tok_double;
+                }
+                goto lexed;
+            }
+            case 'N': {
+                LEX_WANT("aN");
+                if (!lexer->allowJson5) {
+                    unreadChar(lexer, offset);
+                    lexer->error = yajl_lex_unallowed_special_number;
+                    tok = yajl_tok_error;
+                } else {
+                    tok = yajl_tok_double;
+                }
+                goto lexed;
+            }
+            case '\'':
+                if (!lexer->allowJson5) goto invalid;
+                /* Fall through... */
             case '"': {
-                tok = yajl_lex_string(lexer, (const unsigned char *) jsonText,
-                                      jsonTextLen, offset);
+                tok = yajl_lex_string(lexer, jsonText, jsonTextLen, offset, c);
                 goto lexed;
             }
+            case '+': case '.':
+                if (!lexer->allowJson5)
+                    goto invalid;
             case '-':
             case '0': case '1': case '2': case '3': case '4':
             case '5': case '6': case '7': case '8': case '9': {
                 /* integer parsing wants to start from the beginning */
                 unreadChar(lexer, offset);
-                tok = yajl_lex_number(lexer, (const unsigned char *) jsonText,
-                                      jsonTextLen, offset);
+                tok = yajl_lex_number(lexer, jsonText, jsonTextLen, offset);
                 goto lexed;
             }
             case '/':
@@ -636,6 +739,7 @@ yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
                 /* hit error or eof, bail */
                 goto lexed;
             default:
+            invalid:
                 lexer->error = yajl_lex_invalid_char;
                 tok = yajl_tok_error;
                 goto lexed;
@@ -670,6 +774,126 @@ yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
         *outLen -= 2;
     }
 
+#ifdef YAJL_LEXER_DEBUG
+    if (tok == yajl_tok_error) {
+        printf("lexical error: %s\n",
+               yajl_lex_error_to_string(yajl_lex_get_error(lexer)));
+    } else if (tok == yajl_tok_eof) {
+        printf("EOF hit\n");
+    } else {
+        printf("lexed %s: '", tokToStr(tok));
+        fwrite(*outBuf, 1, *outLen, stdout);
+        printf("'\n");
+    }
+#endif
+
+    return tok;
+}
+
+yajl_tok yajl_lex_key(yajl_lexer lexer, const unsigned char * jsonText,
+                    size_t jsonTextLen, size_t * offset,
+                    const unsigned char ** outBuf, size_t * outLen)
+{
+    yajl_tok tok = yajl_tok_error;
+    unsigned char c;
+    size_t startOffset = *offset;
+
+    *outBuf = NULL;
+    *outLen = 0;
+
+    for (;;) {
+        assert(*offset <= jsonTextLen);
+
+        if (*offset >= jsonTextLen) {
+            tok = yajl_tok_eof;
+            goto lexed;
+        }
+
+        c = readChar(lexer, jsonText, offset);
+
+        switch (c) {
+            case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
+                startOffset++;
+                break;
+            case '}':
+                tok = yajl_tok_right_brace;
+                goto lexed;
+            case '\'':
+                if (!lexer->allowJson5) goto invalid;
+                /* Fall through... */
+            case '"': {
+                tok = yajl_lex_string(lexer, jsonText, jsonTextLen, offset, c);
+                goto lexed;
+            }
+            case '/':
+                /* If comments are disabled this is an error. */
+                if (!lexer->allowComments) {
+                    unreadChar(lexer, offset);
+                    lexer->error = yajl_lex_unallowed_comment;
+                    tok = yajl_tok_error;
+                    goto lexed;
+                }
+                /* Comments are enabled, so lex it.
+                 * Possible outcomes are:
+                 * - successful lex (tok_comment, which means continue),
+                 * - malformed comment opening (slash not followed by
+                 *   '*' or '/') (tok_error)
+                 * - eof hit. (tok_eof) */
+                tok = yajl_lex_comment(lexer, jsonText, jsonTextLen, offset);
+                if (tok == yajl_tok_comment) {
+                    /* "error" is silly, but that's the initial
+                     * state of tok.  guilty until proven innocent. */
+                    tok = yajl_tok_error;
+                    yajl_buf_clear(lexer->buf);
+                    lexer->bufInUse = 0;
+                    startOffset = *offset;
+                    break;
+                }
+                /* hit error or eof, bail */
+                goto lexed;
+            default:
+                if (lexer->allowJson5 && (c == '$' || c == '_' ||
+                    (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) {
+                    tok = yajl_lex_identifier(lexer, jsonText, jsonTextLen, offset);
+                }
+                else {
+  invalid:
+                    lexer->error = yajl_lex_invalid_char;
+                    tok = yajl_tok_error;
+                }
+                goto lexed;
+        }
+    }
+
+  lexed:
+    /* need to append to buffer if the buffer is in use or
+     * if it's an EOF token */
+    if (tok == yajl_tok_eof || lexer->bufInUse) {
+        if (!lexer->bufInUse) yajl_buf_clear(lexer->buf);
+        lexer->bufInUse = 1;
+        yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset);
+        lexer->bufOff = 0;
+
+        if (tok != yajl_tok_eof) {
+            *outBuf = yajl_buf_data(lexer->buf);
+            *outLen = yajl_buf_len(lexer->buf);
+            lexer->bufInUse = 0;
+        }
+    } else if (tok != yajl_tok_error) {
+        *outBuf = jsonText + startOffset;
+        *outLen = *offset - startOffset;
+    }
+
+    /* For strings skip the quotes. */
+    if (tok == yajl_tok_string ||
+        tok == yajl_tok_string_with_escapes) {
+        assert(*outLen >= 2);
+        (*outBuf)++;
+        *outLen -= 2;
+    }
+    else if (tok == yajl_tok_identifier) {
+        tok = yajl_tok_string;
+    }
 
 #ifdef YAJL_LEXER_DEBUG
     if (tok == yajl_tok_error) {
@@ -700,9 +924,12 @@ yajl_lex_error_to_string(yajl_lex_error error)
                    "which it may not.";
         case yajl_lex_string_invalid_json_char:
             return "invalid character inside string.";
-        case yajl_lex_string_invalid_hex_char:
+        case yajl_lex_string_invalid_hex_u_char:
             return "invalid (non-hex) character occurs after '\\u' inside "
                    "string.";
+        case yajl_lex_string_invalid_hex_x_char:
+            return "invalid (non-hex) character occurs after '\\x' inside "
+                   "string.";
         case yajl_lex_invalid_char:
             return "invalid char in json text.";
         case yajl_lex_invalid_string:
@@ -714,10 +941,16 @@ yajl_lex_error_to_string(yajl_lex_error error)
                    "decimal point.";
         case yajl_lex_missing_integer_after_minus:
             return "malformed number, a digit is required after the "
-                   "minus sign.";
+                   "plus/minus sign.";
         case yajl_lex_unallowed_comment:
             return "probable comment found in input text, comments are "
                    "not enabled.";
+        case yajl_lex_missing_hex_digit_after_0x:
+            return "malformed number, a hex digit is required after the 0x/0X.";
+        case yajl_lex_unallowed_hex_integer:
+            return "probable hex number found, JSON5 is not enabled.";
+        case yajl_lex_unallowed_special_number:
+            return "special number Infinity or NaN found, JSON5 is not enabled.";
     }
     return "unknown error code";
 }
diff --git a/src/yajl_lex.h b/src/yajl_lex.h
index fd17c00..8363de9 100644
--- a/src/yajl_lex.h
+++ b/src/yajl_lex.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +17,7 @@
 #ifndef __YAJL_LEX_H__
 #define __YAJL_LEX_H__
 
-#include "api/yajl_common.h"
+#include "yajl_common.h"
 
 typedef enum {
     yajl_tok_bool,
@@ -41,27 +41,37 @@ typedef enum {
     yajl_tok_string,
     yajl_tok_string_with_escapes,
 
-    /* comment tokens are not currently returned to the parser, ever */
+    /* These tokens are used within the lexer and never seen by the parser: */
+
+    /* An unquoted map key, for JSON5 only, returned as yajl_tok_string */
+    yajl_tok_identifier,
+
+    /* A comment token, never returned */
     yajl_tok_comment
 } yajl_tok;
 
 typedef struct yajl_lexer_t * yajl_lexer;
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc,
                           unsigned int allowComments,
-                          unsigned int validateUTF8);
+                          unsigned int validateUTF8,
+                          unsigned int allowJson5);
 
 void yajl_lex_free(yajl_lexer lexer);
 
 /**
  * run/continue a lex. "offset" is an input/output parameter.
  * It should be initialized to zero for a
- * new chunk of target text, and upon subsetquent calls with the same
+ * new chunk of target text, and upon subsequent calls with the same
  * target text should passed with the value of the previous invocation.
  *
  * the client may be interested in the value of offset when an error is
  * returned from the lexer.  This allows the client to render useful
- * error messages.
+n * error messages.
  *
  * When you pass the next chunk of data, context should be reinitialized
  * to zero.
@@ -79,6 +89,14 @@ yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
                       size_t jsonTextLen, size_t * offset,
                       const unsigned char ** outBuf, size_t * outLen);
 
+/**
+ * A specialized version of yajl_lex_lex for use when the next token is
+ * a map key, which the parser knows.
+ */
+yajl_tok yajl_lex_key(yajl_lexer lexer, const unsigned char * jsonText,
+                    size_t jsonTextLen, size_t * offset,
+                    const unsigned char ** outBuf, size_t * outLen);
+
 /** have a peek at the next token, but don't move the lexer forward */
 yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
                        size_t jsonTextLen, size_t offset);
@@ -89,13 +107,17 @@ typedef enum {
     yajl_lex_string_invalid_utf8,
     yajl_lex_string_invalid_escaped_char,
     yajl_lex_string_invalid_json_char,
-    yajl_lex_string_invalid_hex_char,
+    yajl_lex_string_invalid_hex_u_char,
+    yajl_lex_string_invalid_hex_x_char,
     yajl_lex_invalid_char,
     yajl_lex_invalid_string,
     yajl_lex_missing_integer_after_decimal,
     yajl_lex_missing_integer_after_exponent,
     yajl_lex_missing_integer_after_minus,
-    yajl_lex_unallowed_comment
+    yajl_lex_unallowed_comment,
+    yajl_lex_missing_hex_digit_after_0x,
+    yajl_lex_unallowed_hex_integer,
+    yajl_lex_unallowed_special_number,
 } yajl_lex_error;
 
 const char * yajl_lex_error_to_string(yajl_lex_error error);
@@ -114,4 +136,8 @@ size_t yajl_lex_current_line(yajl_lexer lexer);
  *  \n or \r */
 size_t yajl_lex_current_char(yajl_lexer lexer);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/src/yajl_parser.c b/src/yajl_parser.c
index 1a528a6..0627215 100644
--- a/src/yajl_parser.c
+++ b/src/yajl_parser.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,12 +14,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "api/yajl_parse.h"
-#include "yajl_lex.h"
-#include "yajl_parser.h"
-#include "yajl_encode.h"
-#include "yajl_bytestack.h"
-
 #include <stdlib.h>
 #include <limits.h>
 #include <errno.h>
@@ -29,33 +23,65 @@
 #include <assert.h>
 #include <math.h>
 
-#define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10))
+#include "yajl_parse.h"
+#include "yajl_lex.h"
+#include "yajl_parser.h"
+#include "yajl_encode.h"
+#include "yajl_bytestack.h"
+
+#include <epicsStdlib.h>
+
+#ifndef LLONG_MAX
+#define LLONG_MAX     0x7FFFFFFFFFFFFFFFLL
+#define LLONG_MIN     (-0x7FFFFFFFFFFFFFFFLL - 1)
+#endif
 
- /* same semantics as strtol */
 long long
-yajl_parse_integer(const unsigned char *number, unsigned int length)
+yajl_parse_integer(const unsigned char *number, size_t length)
 {
     long long ret  = 0;
     long sign = 1;
+    long base = 10;
+    long long max = LLONG_MAX / base;
     const unsigned char *pos = number;
-    if (*pos == '-') { pos++; sign = -1; }
-    if (*pos == '+') { pos++; }
+    const unsigned char *end = number + length;
 
-    while (pos < number + length) {
-        if ( ret > MAX_VALUE_TO_MULTIPLY ) {
-            errno = ERANGE;
-            return sign == 1 ? LLONG_MAX : LLONG_MIN;
-        }
-        ret *= 10;
-        if (LLONG_MAX - ret < (*pos - '0')) {
+    if (*pos == '-') {
+        pos++;
+        sign = -1;
+    }
+    else if (*pos == '+') {
+        pos++;
+    }
+
+    if (*pos == '0' &&
+        (pos[1] == 'x' || pos[1] == 'X')) {
+        base = 16;
+        max = LLONG_MAX / base;
+        pos += 2;
+    }
+
+    while (pos < end) {
+        int digit;
+
+        if (ret > max) {
             errno = ERANGE;
             return sign == 1 ? LLONG_MAX : LLONG_MIN;
         }
-        if (*pos < '0' || *pos > '9') {
+
+        ret *= base;
+        digit = *pos++ - '0';
+        /* Don't have to check for non-digit characters,
+         * the lexer has already rejected any bad digits.
+         */
+        if (digit > 9)
+            digit = (digit - ('A' - '0') + 10) & 0xf;
+
+        if (LLONG_MAX - ret < digit) {
             errno = ERANGE;
             return sign == 1 ? LLONG_MAX : LLONG_MIN;
         }
-        ret += (*pos++ - '0');
+        ret += digit;
     }
 
     return sign * ret;
@@ -145,7 +171,7 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
     return str;
 }
 
-/* check for client cancelation */
+/* check for client cancellation */
 #define _CC_CHK(x)                                                \
     if (!(x)) {                                                   \
         yajl_bs_set(hand->stateStack, yajl_state_parse_error);    \
@@ -223,7 +249,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
             /* for arrays and maps, we advance the state for this
              * depth, then push the state of the next depth.
              * If an error occurs during the parsing of the nesting
-             * enitity, the state at this level will not matter.
+             * entity, the state at this level will not matter.
              * a state that needs pushing will be anything other
              * than state_start */
 
@@ -264,13 +290,13 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
                         _CC_CHK(hand->callbacks->yajl_null(hand->ctx));
                     }
                     break;
-                case yajl_tok_left_bracket:
+                case yajl_tok_left_brace:
                     if (hand->callbacks && hand->callbacks->yajl_start_map) {
                         _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx));
                     }
                     stateToPush = yajl_state_map_start;
                     break;
-                case yajl_tok_left_brace:
+                case yajl_tok_left_bracket:
                     if (hand->callbacks && hand->callbacks->yajl_start_array) {
                         _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx));
                     }
@@ -283,7 +309,6 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
                                         hand->ctx,(const char *) buf, bufLen));
                         } else if (hand->callbacks->yajl_integer) {
                             long long int i = 0;
-                            errno = 0;
                             i = yajl_parse_integer(buf, bufLen);
                             if ((i == LLONG_MIN || i == LLONG_MAX) &&
                                 errno == ERANGE)
@@ -311,8 +336,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
                             yajl_buf_clear(hand->decodeBuf);
                             yajl_buf_append(hand->decodeBuf, buf, bufLen);
                             buf = yajl_buf_data(hand->decodeBuf);
-                            errno = 0;
-                            d = strtod((char *) buf, NULL);
+                            d = epicsStrtod((char *) buf, NULL);
                             if ((d == HUGE_VAL || d == -HUGE_VAL) &&
                                 errno == ERANGE)
                             {
@@ -330,9 +354,11 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
                         }
                     }
                     break;
-                case yajl_tok_right_brace: {
-                    if (yajl_bs_current(hand->stateStack) ==
-                        yajl_state_array_start)
+                case yajl_tok_right_bracket: {
+                    yajl_state s = yajl_bs_current(hand->stateStack);
+                    if (s == yajl_state_array_start ||
+                        ((hand->flags & yajl_allow_json5) &&
+                        (s == yajl_state_array_need_val)))
                     {
                         if (hand->callbacks &&
                             hand->callbacks->yajl_end_array)
@@ -346,7 +372,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
                 }
                 case yajl_tok_colon:
                 case yajl_tok_comma:
-                case yajl_tok_right_bracket:
+                case yajl_tok_right_brace:
                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
                     hand->parseError =
                         "unallowed token at this point in JSON text";
@@ -377,8 +403,8 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
         case yajl_state_map_need_key: {
             /* only difference between these two states is that in
              * start '}' is valid, whereas in need_key, we've parsed
-             * a comma, and a string key _must_ follow */
-            tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
+             * a comma, so unless this is JSON5 a key _must_ follow. */
+            tok = yajl_lex_key(hand->lexer, jsonText, jsonTextLen,
                                offset, &buf, &bufLen);
             switch (tok) {
                 case yajl_tok_eof:
@@ -401,20 +427,23 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
                     }
                     yajl_bs_set(hand->stateStack, yajl_state_map_sep);
                     goto around_again;
-                case yajl_tok_right_bracket:
-                    if (yajl_bs_current(hand->stateStack) ==
-                        yajl_state_map_start)
-                    {
+                case yajl_tok_right_brace: {
+                    yajl_state s = yajl_bs_current(hand->stateStack);
+                    if (s == yajl_state_map_start ||
+                        ((hand->flags & yajl_allow_json5) &&
+                        (s == yajl_state_map_need_key))) {
                         if (hand->callbacks && hand->callbacks->yajl_end_map) {
                             _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
                         }
                         yajl_bs_pop(hand->stateStack);
                         goto around_again;
                     }
+                }
                 default:
                     yajl_bs_set(hand->stateStack, yajl_state_parse_error);
-                    hand->parseError =
-                        "invalid object key (must be a string)"; 
+                    hand->parseError = hand->flags & yajl_allow_json5 ?
+                        "invalid object key (must be a string or identifier)" :
+                        "invalid object key (must be a string)";
                     goto around_again;
             }
         }
@@ -441,7 +470,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
             tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
                                offset, &buf, &bufLen);
             switch (tok) {
-                case yajl_tok_right_bracket:
+                case yajl_tok_right_brace:
                     if (hand->callbacks && hand->callbacks->yajl_end_map) {
                         _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
                     }
@@ -469,7 +498,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
             tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
                                offset, &buf, &bufLen);
             switch (tok) {
-                case yajl_tok_right_brace:
+                case yajl_tok_right_bracket:
                     if (hand->callbacks && hand->callbacks->yajl_end_array) {
                         _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
                     }
@@ -495,4 +524,3 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
     abort();
     return yajl_status_error;
 }
-
diff --git a/src/yajl_parser.h b/src/yajl_parser.h
index c79299a..0cf9e98 100644
--- a/src/yajl_parser.h
+++ b/src/yajl_parser.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2014, Lloyd Hilaiel <m...@lloyd.io>
+ * Copyright (c) 2007-2011, Lloyd Hilaiel <ll...@hilaiel.com>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +17,7 @@
 #ifndef __YAJL_PARSER_H__
 #define __YAJL_PARSER_H__
 
-#include "api/yajl_parse.h"
+#include "yajl_parse.h"
 #include "yajl_bytestack.h"
 #include "yajl_buf.h"
 #include "yajl_lex.h"
@@ -58,6 +58,10 @@ struct yajl_handle_t {
     unsigned int flags;
 };
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 yajl_status
 yajl_do_parse(yajl_handle handle, const unsigned char * jsonText,
               size_t jsonTextLen);
@@ -72,7 +76,10 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
 /* A little built in integer parsing routine with the same semantics as strtol
  * that's unaffected by LOCALE. */
 long long
-yajl_parse_integer(const unsigned char *number, unsigned int length);
+yajl_parse_integer(const unsigned char *number, size_t length);
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif

Reply via email to