Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]
Return to module

File Contents

Contents of /Public_Parser_JSON2-0.8/json.cmod:

#line 1 "src/json.rl"
// vim:syntax=ragel
/* 
 * Pike CMOD parser for JSON.
 * Copyright (C) 2007-2008 Arne Goedeke
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <stdio.h>
//#include "global.h"
#include "interpret.h"
#include "stralloc.h"
#include "mapping.h"
#include "svalue.h"
#include "operators.h"
#include "object.h"
#include "array.h"
#include "builtin_functions.h"
#include "module.h"
#include "gc.h"

#include "json.h"

#include "json_utf8.c"

p_wchar2 *_parse_JSON(p_wchar2 *p, p_wchar2 *pe, struct parser_state *state); 

#include "json_string.c"
#include "json_number.c"
#include "json_array.c"
#include "json_mapping.c"
#include "json_render.c"

#line 79 "src/json.rl"


p_wchar2 *_parse_JSON(p_wchar2 *p, p_wchar2 *pe, struct parser_state *state) {
    p_wchar2 *i = p;
    int cs;
    int c = 0;
    
#line 56 "work/json.cmod"
static const int JSON_start = 1;
static const int JSON_first_final = 12;
static const int JSON_error = 0;

static const int JSON_en_main = 1;

#line 86 "src/json.rl"

    
#line 66 "work/json.cmod"
	{
	cs = JSON_start;
	}
#line 88 "src/json.rl"
    
#line 72 "work/json.cmod"
	{
	if ( p == pe )
		goto _out;
	switch ( cs )
	{
st1:
	if ( ++p == pe )
		goto _out1;
case 1:
	switch( (*p) ) {
		case 13: goto st1;
		case 32: goto st1;
		case 34: goto tr2;
		case 43: goto tr3;
		case 91: goto tr4;
		case 102: goto st2;
		case 110: goto st6;
		case 116: goto st9;
		case 123: goto tr8;
	}
	if ( (*p) < 45 ) {
		if ( 9 <= (*p) && (*p) <= 10 )
			goto st1;
	} else if ( (*p) > 46 ) {
		if ( 48 <= (*p) && (*p) <= 57 )
			goto tr3;
	} else
		goto tr3;
	goto st0;
st0:
	goto _out0;
tr2:
#line 60 "src/json.rl"
	{ PARSE(string, p); {p = (( i))-1;} }
	goto st12;
tr3:
#line 61 "src/json.rl"
	{ PARSE(number, p); {p = (( i))-1;} }
	goto st12;
tr4:
#line 63 "src/json.rl"
	{ PARSE(array, p); {p = (( i))-1;} }
	goto st12;
tr8:
#line 62 "src/json.rl"
	{ PARSE(mapping, p); {p = (( i))-1;} }
	goto st12;
tr12:
#line 67 "src/json.rl"
	{ PUSH_SPECIAL("false"); }
	goto st12;
tr15:
#line 68 "src/json.rl"
	{ PUSH_SPECIAL("null"); }
	goto st12;
tr18:
#line 66 "src/json.rl"
	{ PUSH_SPECIAL("true"); }
	goto st12;
st12:
	if ( ++p == pe )
		goto _out12;
case 12:
#line 78 "src/json.rl"
	{ if (state->level != 0) goto _out12; }
#line 138 "work/json.cmod"
	switch( (*p) ) {
		case 13: goto st12;
		case 32: goto st12;
	}
	if ( 9 <= (*p) && (*p) <= 10 )
		goto st12;
	goto st0;
st2:
	if ( ++p == pe )
		goto _out2;
case 2:
	if ( (*p) == 97 )
		goto st3;
	goto st0;
st3:
	if ( ++p == pe )
		goto _out3;
case 3:
	if ( (*p) == 108 )
		goto st4;
	goto st0;
st4:
	if ( ++p == pe )
		goto _out4;
case 4:
	if ( (*p) == 115 )
		goto st5;
	goto st0;
st5:
	if ( ++p == pe )
		goto _out5;
case 5:
	if ( (*p) == 101 )
		goto tr12;
	goto st0;
st6:
	if ( ++p == pe )
		goto _out6;
case 6:
	if ( (*p) == 117 )
		goto st7;
	goto st0;
st7:
	if ( ++p == pe )
		goto _out7;
case 7:
	if ( (*p) == 108 )
		goto st8;
	goto st0;
st8:
	if ( ++p == pe )
		goto _out8;
case 8:
	if ( (*p) == 108 )
		goto tr15;
	goto st0;
st9:
	if ( ++p == pe )
		goto _out9;
case 9:
	if ( (*p) == 114 )
		goto st10;
	goto st0;
st10:
	if ( ++p == pe )
		goto _out10;
case 10:
	if ( (*p) == 117 )
		goto st11;
	goto st0;
st11:
	if ( ++p == pe )
		goto _out11;
case 11:
	if ( (*p) == 101 )
		goto tr18;
	goto st0;
	}
	_out1: cs = 1; goto _out; 
	_out0: cs = 0; goto _out; 
	_out12: cs = 12; goto _out; 
	_out2: cs = 2; goto _out; 
	_out3: cs = 3; goto _out; 
	_out4: cs = 4; goto _out; 
	_out5: cs = 5; goto _out; 
	_out6: cs = 6; goto _out; 
	_out7: cs = 7; goto _out; 
	_out8: cs = 8; goto _out; 
	_out9: cs = 9; goto _out; 
	_out10: cs = 10; goto _out; 
	_out11: cs = 11; goto _out; 

	_out: {}
	}
#line 89 "src/json.rl"

    if (cs >= JSON_first_final) {
	return p;
    }

    if (!state->validate && c > 0) pop_n_elems(c);

    push_int((int)p);
    return NULL;
}

DECLARATIONS

/*! @module Public
 */

/*! @module Parser
 */

/*! @module JSON2
 *! This module contains a parser to parse JSON into native pike types. The parser has been written
 *! in c using ragel (@[http://www.cs.queensu.ca/~thurston/ragel/]).
 *! The parser is supposed to handle Unicode strings (internally 8, 16 and 32 bit wide strings that is).
 *! There are special functions for handling utf8 encoded Unicode strings.
 *! 
 *! Have a look at @[http://www.json.org] or @[http://www.ietf.org/rfc/rfc4627.txt?number=4627] for
 *! information about what JSON is.
 */

/*! @decl int validate(string s)
 *!
 *! Takes a string and checks if it is valid JSON.
 *! 
 *! @returns
 *! 	In case the string contains valid JSON @expr{-1@} is returned. It is then guarenteed to be parsed
 *! 	without errors by @[parse()].
 *! 	In case the string is not valid JSON, the integer position inside the string
 *! 	where the error occures is returned.
 */
PIKEFUN int validate(string data) {
    p_wchar2 *start;
    struct parser_state state;
    p_wchar2 *p;

    state.validate = 1;
    JSON_CONVERT(data, start);

    state.level = 0;
#ifdef JSON_CUSTOM_TYPES
    state.custom_chars = NULL;
#endif
    state.data = data;

    pop_stack();

    p = _parse_JSON(start, start + data->len, &state);

    if (data->size_shift < 2)
	free(start);

    if (p != NULL) {
	if (p == start + data->len) {
	    push_int(-1);
	    return;
	}

	push_int((int)(p - start) / 4);
	return;
    }

    push_int((int)start);
    f_minus(2);
    push_int(4);
    o_divide();

    return;
}

/*! @decl array|mapping|string|float|int parse(string s)
 *!
 *! Parses a JSON-formatted string and returns the corresponding pike data type.
 *! 
 *! @throws
 *! 	Throws an exception in case the data contained in @expr{s@} is not valid
 *! 	JSON.
 */
PIKEFUN mixed parse(string data) {
    p_wchar2 *start, *stop;
    struct parser_state state;
    int error_offset;

    state.validate = 0;
    JSON_CONVERT(data, start);

    state.level = 0;
#ifdef JSON_CUSTOM_TYPES
    state.custom_chars = NULL;
#endif
    state.data = data;

    stop = _parse_JSON(start, start + data->len, &state);

    if (data->size_shift < 2)
	free(start);

    if (stop != NULL) {
		
	if (stop == start + data->len) {
	    stack_pop_keep_top(); // pop string data
	    return;
	}

	pop_stack(); // pop unlegitimate result
	push_int((int)stop);
    }

    error_offset = (((struct svalue*)(Pike_sp - 1))->u.integer - (int)start) / 4;
    pop_stack();
    push_int(error_offset);
    push_int(error_offset+10);
    f_index(3);
    if (((struct svalue*)(Pike_sp - 1))->type != PIKE_T_STRING) {
	Pike_error("Parsing JSON failed and I dont know where.\n");
    } else {
	push_text("Parsing JSON failed in position %d (%O).\n");
	stack_swap();
	push_int(error_offset);
	stack_swap();
	f_sprintf(3);
	f_aggregate(1);
	f_throw(1);
    }

    return;
}

/*! @decl int validate_utf8(string s)
 *!
 *! Takes a utf8 encoded string and checks if it is valid JSON.
 *! 
 *! @returns
 *! 	In case the string contains valid JSON @expr{-1@} is returned. It is then guarenteed to be parsed
 *! 	without errors by @[parse()].
 *! 	In case the string is not valid JSON, the integer position inside the string
 *! 	where the error occures is returned.
 */
PIKEFUN int validate_utf8(string data) {
    char *start, *stop;
    struct parser_state state;

    switch (data->size_shift) {
    case 0:
        break;
    case 1:
    case 2:
	Pike_error("Strings wider than 1 byte are NOT valid UTF-8.\n");
        break;
    }

    start = (char *)STR0(data);

    state.validate = 1;
    state.level = 0;
#ifdef JSON_CUSTOM_TYPES
    state.custom_chars = NULL;
#endif
    state.data = data;

    pop_stack();
    if ((stop = _parse_JSON_utf8(start, (start + data->len), &state)) == NULL) {

	push_int((int)start);
	f_minus(2);
    } else {
	if (stop == start + data->len) {
	    push_int(-1);
	} else {
	    push_int((int)(stop - start));
	}
    }

    return;
}

/*! @decl array|mapping|string|float|int parse_utf8(string s)
 *!
 *! Parses a utf8 encoded JSON-formatted string and returns the corresponding pike data type.
 *! Should give the same results as @expr{Public.Parser.JSON2.parse(utf8_to_string(s))@}.
 *! 
 *! @throws
 *! 	Throws an exception in case the data contained in @expr{s@} is not valid
 *! 	JSON.
 */
PIKEFUN mixed parse_utf8(string data) {
    char *start, *stop;
    struct parser_state state;
    int error_offset;

    switch (data->size_shift) {
    case 0:
        break;
    case 1:
    case 2:
	Pike_error("Strings wider than 1 byte are NOT valid UTF-8.\n");
        break;
    }

    start = (char *)STR0(data);

    state.validate = 0;
    state.level = 0;
#ifdef JSON_CUSTOM_TYPES
    state.custom_chars = NULL;
#endif
    state.data = data;

    stop = _parse_JSON_utf8(start, (start + data->len), &state);

    if (stop != NULL) {
	if (stop == start + data->len) {
	    stack_pop_keep_top(); // pop string data
	    return;
	}

	pop_stack(); // pop the unlegitimate result
	push_int((int)stop);
    }

    error_offset = (((struct svalue*)(Pike_sp - 1))->u.integer - (int)start);
    pop_stack();
    push_int(error_offset);
    push_int(error_offset+10);
    f_index(3);
    if (((struct svalue*)(Pike_sp - 1))->type != PIKE_T_STRING) {
	Pike_error("Parsing JSON failed and I dont know where.\n");
    } else {
	push_text("Parsing JSON failed in position %d (%O).\n");
	stack_swap();
	push_int(error_offset);
	stack_swap();
	f_sprintf(3);
	f_aggregate(1);
	f_throw(1);
    }

    return;
}

/*! @decl string render(mixed data, int|void flags)
 *! @decl String.Buffer render(mixed data, int flags, String.Buffer buf)
 *!
 *! Encodes a native pike data structure into a Unicode string.
 *! 
 *! @note
 *! 	Multisets and mappings with non-string keys are not supported
 *! 	by JSON.
 *! @throws
 *! 	Throws an exception in case the data contains multisets or a
 *! 	mapping with non-string keys.
 */ 
PIKEFUN string render(mixed value, int|void flags, object|void buf) {
    struct string_builder s;
    ONERROR handle;

    init_string_builder(&s, 0);
    SET_ONERROR (handle, free_string_builder, &s);

    if (flags) {
	json_low_render(&s, value, flags->u.integer & 14, 0);
    } else json_low_render(&s, value, 0, 0);

    if (buf) {
	struct svalue sv;

	pop_n_elems(args);
	push_constant_text("add");
#if PIKE_MAJOR_VERSION < 7 || PIKE_MINOR_VERSION < 7
	object_index_no_free(&sv, buf, Pike_sp-1);
#else
	object_index_no_free(&sv, buf, 0, Pike_sp-1);
#endif
	pop_stack();

	push_svalue(&sv);
	UNSET_ONERROR (handle);
	push_string(finish_string_builder(&s));
	f_call_function(2);
	pop_stack();
	push_object(buf);
    } 

    UNSET_ONERROR (handle);
    RETURN(finish_string_builder(&s));
}

/*! @decl string render_utf8(mixed data, int|void flags)
 *! @decl String.Buffer render_utf8(mixed data, int flags, String.Buffer buf)
 *!
 *! Encodes a native pike data structure into a UTF8 encoded Unicode string.
 *! 
 *! @note
 *! 	Multisets and mappings with non-string keys are not supported
 *! 	by JSON.
 *! @throws
 *! 	Throws an exception in case the data contains multisets or a
 *! 	mapping with non-string keys.
 */ 
PIKEFUN string render_utf8(mixed value, int|void flags, object|void buf) {
    struct string_builder s;
    ONERROR handle;

    init_string_builder(&s, 0);
    SET_ONERROR (handle, free_string_builder, &s);

    if (flags) {
	json_low_render(&s, value, FLAG_UTF8 | (flags->u.integer & 14), 0);
    } else json_low_render(&s, value, FLAG_UTF8, 0);


    if (buf) {
	struct svalue sv;

	pop_n_elems(args);
	push_constant_text("add");
#if PIKE_MAJOR_VERSION < 7 || PIKE_MINOR_VERSION < 7
	object_index_no_free(&sv, buf, Pike_sp-1);
#else
	object_index_no_free(&sv, buf, 0, Pike_sp-1);
#endif
	pop_stack();

	push_svalue(&sv);
	UNSET_ONERROR (handle);
	push_string(finish_string_builder(&s));
	f_call_function(2);
	pop_stack();
	push_object(buf);
    } 

    UNSET_ONERROR (handle);
    RETURN(finish_string_builder(&s));
}

/*! @endmodule
 */
/*! @endmodule
 */
/*! @endmodule
 */

gotpike.org | Copyright © 2004 - 2011 | Pike is a trademark of Department of Computer and Information Science, Linköping University