Back to index

php5  5.3.10
Defines | Enumerations | Functions | Variables
JSON_parser.c File Reference
#include <stdio.h>
#include "JSON_parser.h"

Go to the source code of this file.

Defines

#define true   1
#define false   0
#define __   -1 /* the universal error code */
#define FREE_BUFFERS()   smart_str_free(&buf); smart_str_free(&key);
#define SWAP_BUFFERS(from, to)
#define JSON_RESET_TYPE()   type = -1;

Enumerations

enum  classes {
  C_SPACE, C_WHITE, C_LCURB, C_RCURB,
  C_LSQRB, C_RSQRB, C_COLON, C_COMMA,
  C_QUOTE, C_BACKS, C_SLASH, C_PLUS,
  C_MINUS, C_POINT, C_ZERO, C_DIGIT,
  C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D,
  C_LOW_E, C_LOW_F, C_LOW_L, C_LOW_N,
  C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U,
  C_ABCDF, C_E, C_ETC, NR_CLASSES
}
enum  states {
  GO, OK, OB, KE,
  CO, VA, AR, ST,
  ES, U1, U2, U3,
  U4, MI, ZE, IN,
  FR, E1, E2, E3,
  T1, T2, T3, F1,
  F2, F3, F4, N1,
  N2, N3, NR_STATES
}
enum  modes { MODE_ARRAY, MODE_DONE, MODE_KEY, MODE_OBJECT }

Functions

static int push (JSON_parser jp, int mode)
static int pop (JSON_parser jp, int mode)
JSON_parser new_JSON_parser (int depth)
int free_JSON_parser (JSON_parser jp)
static int dehexchar (char c)
static void json_create_zval (zval **z, smart_str *buf, int type)
static void utf16_to_utf8 (smart_str *buf, unsigned short utf16)
static void attach_zval (JSON_parser jp, int up, int cur, smart_str *key, int assoc TSRMLS_DC)
int parse_JSON (JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int assoc TSRMLS_DC)

Variables

static const int ascii_class [128]
static const int state_transition_table [NR_STATES][NR_CLASSES]

Define Documentation

#define __   -1 /* the universal error code */

Definition at line 37 of file JSON_parser.c.

#define false   0

Definition at line 36 of file JSON_parser.c.

#define FREE_BUFFERS ( )    smart_str_free(&buf); smart_str_free(&key);

Definition at line 402 of file JSON_parser.c.

#define JSON_RESET_TYPE ( )    type = -1;

Definition at line 413 of file JSON_parser.c.

#define SWAP_BUFFERS (   from,
  to 
)
Value:
do { \
        char *t1 = from.c; \
        int t2 = from.a; \
        from.c = to.c; \
        from.a = to.a; \
        to.c = t1; \
        to.a = t2; \
        to.len = from.len; \
        from.len = 0; \
        } while(0);

Definition at line 403 of file JSON_parser.c.

#define true   1

Definition at line 35 of file JSON_parser.c.


Enumeration Type Documentation

enum classes
Enumerator:
C_SPACE 
C_WHITE 
C_LCURB 
C_RCURB 
C_LSQRB 
C_RSQRB 
C_COLON 
C_COMMA 
C_QUOTE 
C_BACKS 
C_SLASH 
C_PLUS 
C_MINUS 
C_POINT 
C_ZERO 
C_DIGIT 
C_LOW_A 
C_LOW_B 
C_LOW_C 
C_LOW_D 
C_LOW_E 
C_LOW_F 
C_LOW_L 
C_LOW_N 
C_LOW_R 
C_LOW_S 
C_LOW_T 
C_LOW_U 
C_ABCDF 
C_E 
C_ETC 
NR_CLASSES 

Definition at line 44 of file JSON_parser.c.

             {
    C_SPACE,  /* space */
    C_WHITE,  /* other whitespace */
    C_LCURB,  /* {  */
    C_RCURB,  /* } */
    C_LSQRB,  /* [ */
    C_RSQRB,  /* ] */
    C_COLON,  /* : */
    C_COMMA,  /* , */
    C_QUOTE,  /* " */
    C_BACKS,  /* \ */
    C_SLASH,  /* / */
    C_PLUS,   /* + */
    C_MINUS,  /* - */
    C_POINT,  /* . */
    C_ZERO ,  /* 0 */
    C_DIGIT,  /* 123456789 */
    C_LOW_A,  /* a */
    C_LOW_B,  /* b */
    C_LOW_C,  /* c */
    C_LOW_D,  /* d */
    C_LOW_E,  /* e */
    C_LOW_F,  /* f */
    C_LOW_L,  /* l */
    C_LOW_N,  /* n */
    C_LOW_R,  /* r */
    C_LOW_S,  /* s */
    C_LOW_T,  /* t */
    C_LOW_U,  /* u */
    C_ABCDF,  /* ABCDF */
    C_E,      /* E */
    C_ETC,    /* everything else */
    NR_CLASSES
};
enum modes
Enumerator:
MODE_ARRAY 
MODE_DONE 
MODE_KEY 
MODE_OBJECT 

Definition at line 190 of file JSON_parser.c.

enum states
Enumerator:
GO 
OK 
OB 
KE 
CO 
VA 
AR 
ST 
ES 
U1 
U2 
U3 
U4 
MI 
ZE 
IN 
FR 
E1 
E2 
E3 
T1 
T2 
T3 
F1 
F2 
F3 
F4 
N1 
N2 
N3 
NR_STATES 

Definition at line 110 of file JSON_parser.c.

            {
    GO,  /* start    */
    OK,  /* ok       */
    OB,  /* object   */
    KE,  /* key      */
    CO,  /* colon    */
    VA,  /* value    */
    AR,  /* array    */
    ST,  /* string   */
    ES,  /* escape   */
    U1,  /* u1       */
    U2,  /* u2       */
    U3,  /* u3       */
    U4,  /* u4       */
    MI,  /* minus    */
    ZE,  /* zero     */
    IN,  /* integer  */
    FR,  /* fraction */
    E1,  /* e        */
    E2,  /* ex       */
    E3,  /* exp      */
    T1,  /* tr       */
    T2,  /* tru      */
    T3,  /* true     */
    F1,  /* fa       */
    F2,  /* fal      */
    F3,  /* fals     */
    F4,  /* false    */
    N1,  /* nu       */
    N2,  /* nul      */
    N3,  /* null     */
    NR_STATES
};

Function Documentation

static void attach_zval ( JSON_parser  jp,
int  up,
int  cur,
smart_str key,
int assoc  TSRMLS_DC 
) [static]

Definition at line 376 of file JSON_parser.c.

{
    zval *root = jp->the_zstack[up];
    zval *child =  jp->the_zstack[cur];
    int up_mode = jp->stack[up];

    if (up_mode == MODE_ARRAY)
    {
        add_next_index_zval(root, child);
    }
    else if (up_mode == MODE_OBJECT)
    {
        if (!assoc)
        {
            add_property_zval_ex(root, (key->len ? key->c : "_empty_"), (key->len ? (key->len + 1) : sizeof("_empty_")), child TSRMLS_CC);
            Z_DELREF_P(child);
        }
        else
        {
            add_assoc_zval_ex(root, (key->len ? key->c : ""), (key->len ? (key->len + 1) : sizeof("")), child);
        }
        key->len = 0;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dehexchar ( char  c) [static]

Definition at line 273 of file JSON_parser.c.

{
    if (c >= '0' && c <= '9')
    {
        return c - '0';
    }
    else if (c >= 'A' && c <= 'F')
    {
        return c - ('A' - 10);
    }
    else if (c >= 'a' && c <= 'f')
    {
        return c - ('a' - 10);
    }
    else
    {
        return -1;
    }
}

Here is the caller graph for this function:

Definition at line 263 of file JSON_parser.c.

{
    efree((void*)jp->stack);
    if (jp->the_zstack != &jp->the_static_zstack[0]) {
        efree(jp->the_zstack);
    }
    efree((void*)jp);
    return false;
}

Here is the caller graph for this function:

static void json_create_zval ( zval **  z,
smart_str buf,
int  type 
) [static]

Definition at line 294 of file JSON_parser.c.

{
    ALLOC_INIT_ZVAL(*z);

    if (type == IS_LONG)
    {
              if (buf->c[0] == '-') {
                     buf->len--;
              }

              if (buf->len >= MAX_LENGTH_OF_LONG - 1) {
                     if (buf->len == MAX_LENGTH_OF_LONG - 1) {
                            int cmp = strcmp(buf->c + (buf->c[0] == '-'), long_min_digits);

                            if (!(cmp < 0 || (cmp == 0 && buf->c[0] == '-'))) {
                                   goto use_double;
                            }
                     } else {
                            goto use_double;
                     }
              }

              ZVAL_LONG(*z, strtol(buf->c, NULL, 10));
    }
    else if (type == IS_DOUBLE)
    {
use_double:
        ZVAL_DOUBLE(*z, zend_strtod(buf->c, NULL));
    }
    else if (type == IS_STRING)
    {
        ZVAL_STRINGL(*z, buf->c, buf->len, 1);
    }
    else if (type == IS_BOOL)
    {
        ZVAL_BOOL(*z, (*(buf->c) == 't'));
    }
    else /* type == IS_NULL) || type unknown */
    {
        ZVAL_NULL(*z);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 242 of file JSON_parser.c.

{
    JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct));
    jp->state = GO;
    jp->depth = depth;
    jp->top = -1;
       jp->error_code = PHP_JSON_ERROR_NONE;
    jp->stack = (int*)ecalloc(depth, sizeof(int));
    if (depth > JSON_PARSER_DEFAULT_DEPTH) {
        jp->the_zstack = (zval **)safe_emalloc(depth, sizeof(zval), 0);
    } else {
        jp->the_zstack = &jp->the_static_zstack[0];
    }
    push(jp, MODE_DONE);
    return jp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int parse_JSON ( JSON_parser  jp,
zval *  z,
unsigned short  utf16_json[],
int  length,
int assoc  TSRMLS_DC 
)

Definition at line 423 of file JSON_parser.c.

{
    int next_char;  /* the next character */
    int next_class;  /* the next character class */
    int next_state;  /* the next state */
    int the_index;

    smart_str buf = {0};
    smart_str key = {0};

    unsigned short utf16 = 0;
    int type;

       JSON_RESET_TYPE();

    for (the_index = 0; the_index < length; the_index += 1) {
        next_char = utf16_json[the_index];
              if (next_char >= 128) {
                     next_class = C_ETC;
              } else {
                     next_class = ascii_class[next_char];
                     if (next_class <= __) {
                            jp->error_code = PHP_JSON_ERROR_CTRL_CHAR;
                            FREE_BUFFERS();
                            return false;
                     }
              }
/*
    Get the next state from the transition table.
*/
        next_state = state_transition_table[jp->state][next_class];
        if (next_state >= 0) {
/*
    Change the state and iterate
*/
                     if (type == IS_STRING) {
                   if (next_state == ST && jp->state != U4) {
                       if (jp->state != ES) {
                           utf16_to_utf8(&buf, next_char);
                       } else {
                           switch (next_char) {
                               case 'b':
                                   smart_str_appendc(&buf, '\b');
                                   break;
                               case 't':
                                   smart_str_appendc(&buf, '\t');
                                   break;
                               case 'n':
                                   smart_str_appendc(&buf, '\n');
                                   break;
                               case 'f':
                                   smart_str_appendc(&buf, '\f');
                                   break;
                               case 'r':
                                   smart_str_appendc(&buf, '\r');
                                   break;
                               default:
                                   utf16_to_utf8(&buf, next_char);
                                   break;
                           }
                       }
                   } else if (next_state == U2) {
                       utf16 = dehexchar(next_char) << 12;
                   } else if (next_state == U3) {
                       utf16 += dehexchar(next_char) << 8;
                   } else if (next_state == U4) {
                       utf16 += dehexchar(next_char) << 4;
                   } else if (next_state == ST && jp->state == U4) {
                       utf16 += dehexchar(next_char);
                       utf16_to_utf8(&buf, utf16);
                   }
               } else if (type < IS_LONG && (next_class == C_DIGIT || next_class == C_ZERO)) {
                   type = IS_LONG;
                   smart_str_appendc(&buf, next_char);
               } else if (type == IS_LONG && next_state == E1) {
                   type = IS_DOUBLE;
                   smart_str_appendc(&buf, next_char);
               } else if (type < IS_DOUBLE && next_class == C_POINT) {
                   type = IS_DOUBLE;
                   smart_str_appendc(&buf, next_char);
               } else if (type < IS_STRING && next_class == C_QUOTE) {
                   type = IS_STRING;
               } else if (type < IS_BOOL && ((jp->state == T3 && next_state == OK) || (jp->state == F4 && next_state == OK))) {
                   type = IS_BOOL;
               } else if (type < IS_NULL && jp->state == N3 && next_state == OK) {
                   type = IS_NULL;
               } else if (type != IS_STRING && next_class > C_WHITE) {
                   utf16_to_utf8(&buf, next_char);
               }
              jp->state = next_state;
              } else {
/*
    Perform one of the predefined actions.
*/
            switch (next_state) {
/* empty } */
            case -9:
                if (!pop(jp, MODE_KEY)) {
                    FREE_BUFFERS();
                    return false;
                }
                jp->state = OK;
                break;
/* } */
            case -8:
                if (type != -1 && jp->stack[jp->top] == MODE_OBJECT)
                {
                    zval *mval;
                    smart_str_0(&buf);

                    json_create_zval(&mval, &buf, type);

                    if (!assoc) {
                        add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC);
                        Z_DELREF_P(mval);
                    } else {
                        add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
                    }
                    key.len = 0;
                    buf.len = 0;
                    JSON_RESET_TYPE();
                }


                if (!pop(jp, MODE_OBJECT)) {
                    FREE_BUFFERS();
                    return false;
                }
                jp->state = OK;
                break;
/* ] */
            case -7:
            {
                if (type != -1 && jp->stack[jp->top] == MODE_ARRAY)
                {
                    zval *mval;
                    smart_str_0(&buf);

                    json_create_zval(&mval, &buf, type);
                    add_next_index_zval(jp->the_zstack[jp->top], mval);
                    buf.len = 0;
                    JSON_RESET_TYPE();
                }

                if (!pop(jp, MODE_ARRAY)) {
                    FREE_BUFFERS();
                    return false;
                }
                jp->state = OK;
            }
                     break;
/* { */
            case -6:
                if (!push(jp, MODE_KEY)) {
                    FREE_BUFFERS();
                    return false;
                }

                jp->state = OB;
                if (jp->top > 0) {
                    zval *obj;

                    if (jp->top == 1) {
                        obj = z;
                     } else {
                        ALLOC_INIT_ZVAL(obj);
                    }

                    if (!assoc) {
                        object_init(obj);
                    } else {
                        array_init(obj);
                    }

                    jp->the_zstack[jp->top] = obj;

                    if (jp->top > 1) {
                        attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
                    }

                    JSON_RESET_TYPE();
                }

                break;
/* [ */
            case -5:
                if (!push(jp, MODE_ARRAY)) {
                    FREE_BUFFERS();
                    return false;
                }
                jp->state = AR;

                if (jp->top > 0) {
                    zval *arr;

                    if (jp->top == 1) {
                        arr = z;
                    } else {
                        ALLOC_INIT_ZVAL(arr);
                    }

                    array_init(arr);
                    jp->the_zstack[jp->top] = arr;

                    if (jp->top > 1) {
                        attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
                    }

                    JSON_RESET_TYPE();
                }

                break;

/* " */
            case -4:
                switch (jp->stack[jp->top]) {
                case MODE_KEY:
                    jp->state = CO;
                    smart_str_0(&buf);
                    SWAP_BUFFERS(buf, key);
                    JSON_RESET_TYPE();
                    break;
                case MODE_ARRAY:
                case MODE_OBJECT:
                    jp->state = OK;
                    break;
                            case MODE_DONE:
                                   if (type == IS_STRING) {
                                          smart_str_0(&buf);
                                          ZVAL_STRINGL(z, buf.c, buf.len, 1);
                                          jp->state = OK;
                                          break;
                                   }
                                   /* fall through if not IS_STRING */
                default:
                    FREE_BUFFERS();
                    jp->error_code = PHP_JSON_ERROR_SYNTAX;
                    return false;
                }
                break;
/* , */
            case -3:
            {
                zval *mval;

                if (type != -1 &&
                    (jp->stack[jp->top] == MODE_OBJECT ||
                     jp->stack[jp->top] == MODE_ARRAY))
                {
                    smart_str_0(&buf);
                    json_create_zval(&mval, &buf, type);
                }

                switch (jp->stack[jp->top]) {
                    case MODE_OBJECT:
                        if (pop(jp, MODE_OBJECT) && push(jp, MODE_KEY)) {
                            if (type != -1) {
                                if (!assoc) {
                                    add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC);
                                    Z_DELREF_P(mval);
                                } else {
                                    add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
                                }
                                key.len = 0;
                            }
                            jp->state = KE;
                        }
                        break;
                    case MODE_ARRAY:
                        if (type != -1) {
                            add_next_index_zval(jp->the_zstack[jp->top], mval);
                        }
                        jp->state = VA;
                        break;
                    default:
                        FREE_BUFFERS();
                        jp->error_code = PHP_JSON_ERROR_SYNTAX;
                        return false;
                }
                buf.len = 0;
                JSON_RESET_TYPE();
            }
            break;
/* : */
            case -2:
                if (pop(jp, MODE_KEY) && push(jp, MODE_OBJECT)) {
                    jp->state = VA;
                    break;
                }
/*
    syntax error
*/
            default:
                {
                                   jp->error_code = PHP_JSON_ERROR_SYNTAX;
                    FREE_BUFFERS();
                    return false;
                }
            }
        }
    }

    FREE_BUFFERS();
       if (jp->state == OK && pop(jp, MODE_DONE)) {
              return true;
       }

       jp->error_code = PHP_JSON_ERROR_SYNTAX;
       return false;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int pop ( JSON_parser  jp,
int  mode 
) [static]

Definition at line 219 of file JSON_parser.c.

{
    if (jp->top < 0 || jp->stack[jp->top] != mode) {
              jp->error_code = PHP_JSON_ERROR_STATE_MISMATCH;
        return false;
    }
    jp->top -= 1;
    return true;
}

Here is the caller graph for this function:

static int push ( JSON_parser  jp,
int  mode 
) [static]

Definition at line 202 of file JSON_parser.c.

{
    jp->top += 1;
    if (jp->top >= jp->depth) {
              jp->error_code = PHP_JSON_ERROR_DEPTH;
        return false;
    }
    jp->stack[jp->top] = mode;
    return true;
}

Here is the caller graph for this function:

static void utf16_to_utf8 ( smart_str buf,
unsigned short  utf16 
) [static]

Definition at line 338 of file JSON_parser.c.

{
    if (utf16 < 0x80)
    {
        smart_str_appendc(buf, (unsigned char) utf16);
    }
    else if (utf16 < 0x800)
    {
        smart_str_appendc(buf, 0xc0 | (utf16 >> 6));
        smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
    }
    else if ((utf16 & 0xfc00) == 0xdc00
                && buf->len >= 3
                && ((unsigned char) buf->c[buf->len - 3]) == 0xed
                && ((unsigned char) buf->c[buf->len - 2] & 0xf0) == 0xa0
                && ((unsigned char) buf->c[buf->len - 1] & 0xc0) == 0x80)
    {
        /* found surrogate pair */
        unsigned long utf32;

        utf32 = (((buf->c[buf->len - 2] & 0xf) << 16)
                    | ((buf->c[buf->len - 1] & 0x3f) << 10)
                    | (utf16 & 0x3ff)) + 0x10000;
        buf->len -= 3;

        smart_str_appendc(buf, (unsigned char) (0xf0 | (utf32 >> 18)));
        smart_str_appendc(buf, 0x80 | ((utf32 >> 12) & 0x3f));
        smart_str_appendc(buf, 0x80 | ((utf32 >> 6) & 0x3f));
        smart_str_appendc(buf, 0x80 | (utf32 & 0x3f));
    }
    else
    {
        smart_str_appendc(buf, 0xe0 | (utf16 >> 12));
        smart_str_appendc(buf, 0x80 | ((utf16 >> 6) & 0x3f));
        smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
    }
}

Here is the caller graph for this function:


Variable Documentation

const int ascii_class[128] [static]

Definition at line 145 of file JSON_parser.c.