Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

changed exception handling

  • Loading branch information...
commit fb0f61b56fc87e6004fe60ce1045075a852c8a1f 1 parent 0916b56
@ohler55 authored
View
4 README.md
@@ -42,7 +42,9 @@ A fast XML parser and Object marshaller as a Ruby gem.
- Fixed bug in SAX parser where raising an exception in the handler routines
would not cleanup. The test put together by griffinmyers was a huge help.
- - [TBD] Reduced stack use in a few places to improve fiber support.
+ - Reduced stack use in a several places to improve fiber support.
+
+ - Changed exception handling to assure proper cleanup with new stack minimizing.
## <a name="description">Description</a>
View
64 ext/ox/err.c
@@ -0,0 +1,64 @@
+/* err.c
+ * Copyright (c) 2011, Peter Ohler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+
+#include "err.h"
+
+void
+ox_err_set(Err e, VALUE clas, const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ e->clas = clas;
+ vsnprintf(e->msg, sizeof(e->msg) - 1, format, ap);
+ va_end(ap);
+}
+
+void
+ox_err_raise(Err e) {
+ rb_raise(e->clas, "%s", e->msg);
+}
+
+void
+_ox_err_set_with_location(Err err, const char *msg, const char *xml, const char *current, const char* file, int line) {
+ int xline = 1;
+ int col = 1;
+
+ for (; xml < current && '\n' != *current; current--) {
+ col++;
+ }
+ for (; xml < current; current--) {
+ if ('\n' == *current) {
+ xline++;
+ }
+ }
+ ox_err_set(err, ox_parse_error_class, "%s at line %d, column %d [%s:%d]\n", msg, xline, col, file, line);
+}
View
61 ext/ox/err.h
@@ -0,0 +1,61 @@
+/* err.h
+ * Copyright (c) 2011, Peter Ohler
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OX_ERR_H__
+#define __OX_ERR_H__
+
+#include "ruby.h"
+
+#define set_error(err, msg, xml, current) _ox_err_set_with_location(err, msg, xml, current, __FILE__, __LINE__)
+
+typedef struct _Err {
+ VALUE clas;
+ char msg[128];
+} *Err;
+
+extern VALUE ox_arg_error_class;
+extern VALUE ox_parse_error_class;
+
+extern void ox_err_set(Err e, VALUE clas, const char *format, ...);
+extern void _ox_err_set_with_location(Err err, const char *msg, const char *xml, const char *current, const char* file, int line);
+extern void ox_err_raise(Err e);
+
+inline static void
+err_init(Err e) {
+ e->clas = Qnil;
+ *e->msg = '\0';
+}
+
+inline static int
+err_has(Err e) {
+ return (Qnil != e->clas);
+}
+
+#endif /* __OX_ERR_H__ */
View
12 ext/ox/gen_load.c
@@ -109,7 +109,8 @@ create_prolog_doc(PInfo pi, const char *target, Attr attrs) {
VALUE sym;
if (!helper_stack_empty(&pi->helpers)) { /* top level object */
- rb_raise(rb_eSyntaxError, "Prolog must be the first element in an XML document.\n");
+ ox_err_set(&pi->err, rb_eSyntaxError, "Prolog must be the first element in an XML document.\n");
+ return;
}
doc = rb_obj_alloc(ox_document_clas);
ah = rb_hash_new();
@@ -176,7 +177,8 @@ instruct(PInfo pi, const char *target, Attr attrs, const char *content) {
for (; 0 != attrs->name; attrs++) {
if (0 == strcmp("version", attrs->name)) {
if (0 != strcmp("1.0", attrs->value)) {
- rb_raise(rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
+ ox_err_set(&pi->err, rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
+ return;
}
}
/* ignore other instructions */
@@ -194,7 +196,8 @@ nomode_instruct(PInfo pi, const char *target, Attr attrs, const char *content) {
for (; 0 != attrs->name; attrs++) {
if (0 == strcmp("version", attrs->name)) {
if (0 != strcmp("1.0", attrs->value)) {
- rb_raise(rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
+ ox_err_set(&pi->err, rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
+ return;
}
} else if (0 == strcmp("mode", attrs->name)) {
if (0 == strcmp("object", attrs->value)) {
@@ -208,7 +211,8 @@ nomode_instruct(PInfo pi, const char *target, Attr attrs, const char *content) {
pi->obj = Qnil;
helper_stack_init(&pi->helpers);
} else {
- rb_raise(rb_eSyntaxError, "%s is not a valid processing instruction mode.\n", attrs->value);
+ ox_err_set(&pi->err, rb_eSyntaxError, "%s is not a valid processing instruction mode.\n", attrs->value);
+ return;
}
}
}
View
2  ext/ox/helper.h
@@ -62,7 +62,7 @@ helper_stack_empty(HelperStack stack) {
inline static int
helper_stack_depth(HelperStack stack) {
- return (stack->tail - stack->head);
+ return (int)(stack->tail - stack->head);
}
inline static void
View
66 ext/ox/obj_load.c
@@ -199,7 +199,8 @@ parse_ulong(const char *s, PInfo pi) {
if ('0' <= *s && *s <= '9') {
n = n * 10 + (*s - '0');
} else {
- raise_error("Invalid number for a julian day", pi->str, pi->s);
+ set_error(&pi->err, "Invalid number for a julian day", pi->str, pi->s);
+ return Qundef;
}
}
return ULONG2NUM(n);
@@ -237,7 +238,8 @@ classname2class(const char *name, PInfo pi, VALUE base_class) {
*s = '\0';
n++;
if (':' != *n) {
- raise_error("Invalid classname, expected another ':'", pi->str, pi->s);
+ set_error(&pi->err, "Invalid classname, expected another ':'", pi->str, pi->s);
+ return Qundef;
}
if (Qundef == (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
return Qundef;
@@ -310,7 +312,8 @@ get_id_from_attrs(PInfo pi, Attr a) {
if ('0' <= c && c <= '9') {
id = id * 10 + (c - '0');
} else {
- raise_error("bad number format", pi->str, pi->s);
+ set_error(&pi->err, "bad number format", pi->str, pi->s);
+ return 0;
}
}
return id;
@@ -419,10 +422,12 @@ add_text(PInfo pi, char *text, int closed) {
Helper h = helper_stack_peek(&pi->helpers);
if (!closed) {
- raise_error("Text not closed", pi->str, pi->s);
+ set_error(&pi->err, "Text not closed", pi->str, pi->s);
+ return;
}
if (0 == h) {
- raise_error("Unexpected text", pi->str, pi->s);
+ set_error(&pi->err, "Unexpected text", pi->str, pi->s);
+ return;
}
if (DEBUG <= pi->options->trace) {
char indent[128];
@@ -462,7 +467,8 @@ add_text(PInfo pi, char *text, int closed) {
if ('0' <= c && c <= '9') {
n = n * 10 + (c - '0');
} else {
- raise_error("bad number format", pi->str, pi->s);
+ set_error(&pi->err, "bad number format", pi->str, pi->s);
+ return;
}
}
if (neg) {
@@ -490,7 +496,9 @@ add_text(PInfo pi, char *text, int closed) {
{
VALUE args[1];
- *args = parse_ulong(text, pi);
+ if (Qundef == (*args = parse_ulong(text, pi))) {
+ return;
+ }
h->obj = rb_funcall2(ox_date_class, ox_jd_id, 1, args);
break;
}
@@ -587,7 +595,8 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
}
}
if ('\0' != ename[1]) {
- raise_error("Invalid element name", pi->str, pi->s);
+ set_error(&pi->err, "Invalid element name", pi->str, pi->s);
+ return;
}
h = helper_stack_push(&pi->helpers, get_var_sym_from_attrs(attrs, (void*)pi->options->rb_enc), Qundef, *ename);
switch (h->type) {
@@ -644,7 +653,7 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
break;
case RawCode:
if (hasChildren) {
- h->obj = ox_parse(pi->s, ox_gen_callbacks, &pi->s, pi->options);
+ h->obj = ox_parse(pi->s, ox_gen_callbacks, &pi->s, pi->options, &pi->err);
if (0 != pi->circ_array) {
circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
}
@@ -653,13 +662,17 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
}
break;
case ExceptionCode:
- h->obj = get_obj_from_attrs(attrs, pi, rb_eException);
+ if (Qundef == (h->obj = get_obj_from_attrs(attrs, pi, rb_eException))) {
+ return;
+ }
if (0 != pi->circ_array && Qnil != h->obj) {
circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
}
break;
case ObjectCode:
- h->obj = get_obj_from_attrs(attrs, pi, ox_bag_clas);
+ if (Qundef == (h->obj = get_obj_from_attrs(attrs, pi, ox_bag_clas))) {
+ return;
+ }
if (0 != pi->circ_array && Qnil != h->obj) {
circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
}
@@ -671,11 +684,14 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
}
#else
- raise_error("Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
+ set_error(&pi->err, "Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
+ return;
#endif
break;
case ClassCode:
- h->obj = get_class_from_attrs(attrs, pi, ox_bag_clas);
+ if (Qundef == (h->obj = get_class_from_attrs(attrs, pi, ox_bag_clas))) {
+ return;
+ }
break;
case RefCode:
h->obj = Qundef;
@@ -683,11 +699,13 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
h->obj = circ_array_get(pi->circ_array, get_id_from_attrs(pi, attrs));
}
if (Qundef == h->obj) {
- raise_error("Invalid circular reference", pi->str, pi->s);
+ set_error(&pi->err, "Invalid circular reference", pi->str, pi->s);
+ return;
}
break;
default:
- raise_error("Invalid element name", pi->str, pi->s);
+ set_error(&pi->err, "Invalid element name", pi->str, pi->s);
+ return;
break;
}
if (DEBUG <= pi->options->trace) {
@@ -735,7 +753,8 @@ end_element(PInfo pi, const char *ename) {
#if HAS_RSTRUCT
rb_struct_aset(ph->obj, h->var, h->obj);
#else
- raise_error("Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
+ set_error(&pi->err, "Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
+ return;
#endif
break;
case HashCode:
@@ -751,10 +770,12 @@ end_element(PInfo pi, const char *ename) {
} else if (ox_excl_id == h->var) {
RSTRUCT_PTR(ph->obj)[2] = h->obj;
} else {
- raise_error("Invalid range attribute", pi->str, pi->s);
+ set_error(&pi->err, "Invalid range attribute", pi->str, pi->s);
+ return;
}
#else
- raise_error("Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
+ set_error(&pi->err, "Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
+ return;
#endif
break;
case KeyCode:
@@ -775,7 +796,8 @@ end_element(PInfo pi, const char *ename) {
ph->obj = rb_complex_new(ph->obj, h->obj);
}
#else
- raise_error("Complex Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
+ set_error(&pi->err, "Complex Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
+ return;
#endif
break;
case RationalCode:
@@ -790,11 +812,13 @@ end_element(PInfo pi, const char *ename) {
#endif
}
#else
- raise_error("Rational Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
+ set_error(&pi->err, "Rational Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
+ return;
#endif
break;
default:
- raise_error("Corrupt parse stack, container is wrong type", pi->str, pi->s);
+ set_error(&pi->err, "Corrupt parse stack, container is wrong type", pi->str, pi->s);
+ return;
break;
}
}
View
59 ext/ox/ox.c
@@ -385,21 +385,26 @@ to_obj(VALUE self, VALUE ruby_xml) {
size_t len;
VALUE obj;
struct _Options options = ox_default_options;
+ struct _Err err;
+ err_init(&err);
Check_Type(ruby_xml, T_STRING);
/* the xml string gets modified so make a copy of it */
len = RSTRING_LEN(ruby_xml) + 1;
+ x = defuse_bom(StringValuePtr(ruby_xml), &options);
if (SMALL_XML < len) {
xml = ALLOC_N(char, len);
} else {
xml = ALLOCA_N(char, len);
}
- memcpy(xml, StringValuePtr(ruby_xml), len);
- x = defuse_bom(xml, &options);
- obj = ox_parse(x, ox_obj_callbacks, 0, &options);
+ memcpy(xml, x, len);
+ obj = ox_parse(xml, ox_obj_callbacks, 0, &options, &err);
if (SMALL_XML < len) {
xfree(xml);
}
+ if (err_has(&err)) {
+ ox_err_raise(&err);
+ }
return obj;
}
@@ -416,26 +421,31 @@ to_gen(VALUE self, VALUE ruby_xml) {
size_t len;
VALUE obj;
struct _Options options = ox_default_options;
+ struct _Err err;
+ err_init(&err);
Check_Type(ruby_xml, T_STRING);
/* the xml string gets modified so make a copy of it */
len = RSTRING_LEN(ruby_xml) + 1;
+ x = defuse_bom(StringValuePtr(ruby_xml), &options);
if (SMALL_XML < len) {
xml = ALLOC_N(char, len);
} else {
xml = ALLOCA_N(char, len);
}
- memcpy(xml, StringValuePtr(ruby_xml), len);
- x = defuse_bom(xml, &options);
- obj = ox_parse(x, ox_gen_callbacks, 0, &options);
+ memcpy(xml, x, len);
+ obj = ox_parse(xml, ox_gen_callbacks, 0, &options, &err);
if (SMALL_XML < len) {
xfree(xml);
}
+ if (err_has(&err)) {
+ ox_err_raise(&err);
+ }
return obj;
}
static VALUE
-load(char *xml, int argc, VALUE *argv, VALUE self, VALUE encoding) {
+load(char *xml, int argc, VALUE *argv, VALUE self, VALUE encoding, Err err) {
VALUE obj;
struct _Options options = ox_default_options;
@@ -500,19 +510,19 @@ load(char *xml, int argc, VALUE *argv, VALUE self, VALUE encoding) {
xml = defuse_bom(xml, &options);
switch (options.mode) {
case ObjMode:
- obj = ox_parse(xml, ox_obj_callbacks, 0, &options);
+ obj = ox_parse(xml, ox_obj_callbacks, 0, &options, err);
break;
case GenMode:
- obj = ox_parse(xml, ox_gen_callbacks, 0, &options);
+ obj = ox_parse(xml, ox_gen_callbacks, 0, &options, err);
break;
case LimMode:
- obj = ox_parse(xml, ox_limited_callbacks, 0, &options);
+ obj = ox_parse(xml, ox_limited_callbacks, 0, &options, err);
break;
case NoMode:
- obj = ox_parse(xml, ox_nomode_callbacks, 0, &options);
+ obj = ox_parse(xml, ox_nomode_callbacks, 0, &options, err);
break;
default:
- obj = ox_parse(xml, ox_gen_callbacks, 0, &options);
+ obj = ox_parse(xml, ox_gen_callbacks, 0, &options, err);
break;
}
return obj;
@@ -542,7 +552,9 @@ load_str(int argc, VALUE *argv, VALUE self) {
size_t len;
VALUE obj;
VALUE encoding;
-
+ struct _Err err;
+
+ err_init(&err);
Check_Type(*argv, T_STRING);
/* the xml string gets modified so make a copy of it */
len = RSTRING_LEN(*argv) + 1;
@@ -563,10 +575,13 @@ load_str(int argc, VALUE *argv, VALUE self) {
encoding = Qnil;
#endif
memcpy(xml, StringValuePtr(*argv), len);
- obj = load(xml, argc - 1, argv + 1, self, encoding);
+ obj = load(xml, argc - 1, argv + 1, self, encoding, &err);
if (SMALL_XML < len) {
xfree(xml);
}
+ if (err_has(&err)) {
+ ox_err_raise(&err);
+ }
return obj;
}
@@ -595,7 +610,9 @@ load_file(int argc, VALUE *argv, VALUE self) {
FILE *f;
size_t len;
VALUE obj;
-
+ struct _Err err;
+
+ err_init(&err);
Check_Type(*argv, T_STRING);
path = StringValuePtr(*argv);
if (0 == (f = fopen(path, "r"))) {
@@ -610,15 +627,19 @@ load_file(int argc, VALUE *argv, VALUE self) {
}
fseek(f, 0, SEEK_SET);
if (len != fread(xml, 1, len, f)) {
- fclose(f);
- rb_raise(rb_eLoadError, "Failed to read %ld bytes from %s.\n", (long)len, path);
+ ox_err_set(&err, rb_eLoadError, "Failed to read %ld bytes from %s.\n", (long)len, path);
+ obj = Qnil;
+ } else {
+ xml[len] = '\0';
+ obj = load(xml, argc - 1, argv + 1, self, Qnil, &err);
}
fclose(f);
- xml[len] = '\0';
- obj = load(xml, argc - 1, argv + 1, self, Qnil);
if (SMALL_XML < len) {
xfree(xml);
}
+ if (err_has(&err)) {
+ ox_err_raise(&err);
+ }
return obj;
}
View
6 ext/ox/ox.h
@@ -59,6 +59,7 @@ enum st_retval {ST_CONTINUE = 0, ST_STOP = 1, ST_DELETE = 2, ST_CHECK};
#include "cache.h"
+#include "err.h"
#include "type.h"
#include "attr.h"
#include "helper.h"
@@ -160,6 +161,7 @@ typedef struct _Options {
/* parse information structure */
struct _PInfo {
struct _HelperStack helpers;
+ struct _Err err;
char *str; /* buffer being read from */
char *s; /* current position in buffer */
VALUE obj;
@@ -170,7 +172,7 @@ struct _PInfo {
char last; /* last character read, rarely set */
};
-extern VALUE ox_parse(char *xml, ParseCallbacks pcb, char **endp, Options options);
+extern VALUE ox_parse(char *xml, ParseCallbacks pcb, char **endp, Options options, Err err);
extern void _ox_raise_error(const char *msg, const char *xml, const char *current, const char* file, int line);
extern void ox_sax_define(void);
@@ -235,11 +237,9 @@ extern VALUE ox_utf8_encoding;
extern void *ox_utf8_encoding;
#endif
-extern VALUE ox_arg_error_class;
extern VALUE ox_date_class;
extern VALUE ox_empty_string;
extern VALUE ox_encoding_sym;
-extern VALUE ox_parse_error_class;
extern VALUE ox_stringio_class;
extern VALUE ox_struct_class;
extern VALUE ox_time_class;
View
146 ext/ox/parse.c
@@ -35,6 +35,7 @@
#include "ruby.h"
#include "ox.h"
+#include "err.h"
#include "attr.h"
#include "helper.h"
@@ -101,18 +102,20 @@ next_white(PInfo pi) {
}
VALUE
-ox_parse(char *xml, ParseCallbacks pcb, char **endp, Options options) {
+ox_parse(char *xml, ParseCallbacks pcb, char **endp, Options options, Err err) {
struct _PInfo pi;
int body_read = 0;
if (0 == xml) {
- raise_error("Invalid arg, xml string can not be null", xml, 0);
+ set_error(err, "Invalid arg, xml string can not be null", xml, 0);
+ return Qnil;
}
if (DEBUG <= options->trace) {
printf("Parsing xml:\n%s\n", xml);
}
/* initialize parse info */
helper_stack_init(&pi.helpers);
+ err_init(&pi.err);
pi.str = xml;
pi.s = xml;
pi.pcb = pcb;
@@ -129,7 +132,9 @@ ox_parse(char *xml, ParseCallbacks pcb, char **endp, Options options) {
break;
}
if ('<' != *pi.s) { /* all top level entities start with < */
- raise_error("invalid format, expected <", pi.str, pi.s);
+ set_error(err, "invalid format, expected <", pi.str, pi.s);
+ helper_stack_cleanup(&pi.helpers);
+ return Qnil;
}
pi.s++; /* past < */
switch (*pi.s) {
@@ -140,11 +145,15 @@ ox_parse(char *xml, ParseCallbacks pcb, char **endp, Options options) {
case '!': /* comment or doctype */
pi.s++;
if ('\0' == *pi.s) {
- raise_error("invalid format, DOCTYPE or comment not terminated", pi.str, pi.s);
+ set_error(err, "invalid format, DOCTYPE or comment not terminated", pi.str, pi.s);
+ helper_stack_cleanup(&pi.helpers);
+ return Qnil;
} else if ('-' == *pi.s) {
pi.s++; /* skip - */
if ('-' != *pi.s) {
- raise_error("invalid format, bad comment format", pi.str, pi.s);
+ set_error(err, "invalid format, bad comment format", pi.str, pi.s);
+ helper_stack_cleanup(&pi.helpers);
+ return Qnil;
} else {
pi.s++; /* skip second - */
read_comment(&pi);
@@ -153,17 +162,27 @@ ox_parse(char *xml, ParseCallbacks pcb, char **endp, Options options) {
pi.s += 7;
read_doctype(&pi);
} else {
- raise_error("invalid format, DOCTYPE or comment expected", pi.str, pi.s);
+ set_error(err, "invalid format, DOCTYPE or comment expected", pi.str, pi.s);
+ helper_stack_cleanup(&pi.helpers);
+ return Qnil;
}
break;
case '\0':
- raise_error("invalid format, document not terminated", pi.str, pi.s);
+ set_error(err, "invalid format, document not terminated", pi.str, pi.s);
+ helper_stack_cleanup(&pi.helpers);
+ return Qnil;
default:
read_element(&pi);
body_read = 1;
break;
}
+ if (err_has(&pi.err)) {
+ *err = pi.err;
+ helper_stack_cleanup(&pi.helpers);
+ return Qnil;
+ }
}
+ helper_stack_cleanup(&pi.helpers);
return pi.obj;
}
@@ -205,10 +224,13 @@ read_instruction(PInfo pi) {
*content = '\0';
attr_stack_init(&attrs);
- target = read_name_token(pi);
+ if (0 == (target = read_name_token(pi))) {
+ return;
+ }
end = pi->s;
if (0 == (cend = gather_content(pi->s, content, sizeof(content) - 1))) {
- raise_error("processing instruction content too large or not terminated", pi->str, pi->s);
+ set_error(&pi->err, "processing instruction content too large or not terminated", pi->str, pi->s);
+ return;
}
next_non_white(pi);
c = *pi->s;
@@ -218,10 +240,14 @@ read_instruction(PInfo pi) {
pi->last = 0;
if ('\0' == *pi->s) {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, processing instruction not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, processing instruction not terminated", pi->str, pi->s);
+ return;
}
next_non_white(pi);
- attr_name = read_name_token(pi);
+ if (0 == (attr_name = read_name_token(pi))) {
+ attr_stack_cleanup(&attrs);
+ return;
+ }
end = pi->s;
next_non_white(pi);
if ('=' != *pi->s++) {
@@ -231,7 +257,10 @@ read_instruction(PInfo pi) {
*end = '\0'; /* terminate name */
/* read value */
next_non_white(pi);
- attr_value = read_quoted_value(pi);
+ if (0 == (attr_value = read_quoted_value(pi))) {
+ attr_stack_cleanup(&attrs);
+ return;
+ }
attr_stack_push(&attrs, attr_name, attr_value);
next_non_white(pi);
if ('\0' == pi->last) {
@@ -249,7 +278,8 @@ read_instruction(PInfo pi) {
if (attrs_ok) {
if ('>' != *pi->s++) {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, processing instruction not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, processing instruction not terminated", pi->str, pi->s);
+ return;
}
} else {
pi->s = cend + 1;
@@ -278,7 +308,8 @@ read_doctype(PInfo pi) {
while (1) {
c = *pi->s++;
if ('\0' == c) {
- raise_error("invalid format, prolog not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, prolog not terminated", pi->str, pi->s);
+ return;
} else if ('<' == c) {
depth++;
} else if ('>' == c) {
@@ -309,7 +340,8 @@ read_comment(PInfo pi) {
comment = pi->s;
end = strstr(pi->s, "-->");
if (0 == end) {
- raise_error("invalid format, comment not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, comment not terminated", pi->str, pi->s);
+ return;
}
for (s = end - 1; pi->s < s && !done; s--) {
switch(*s) {
@@ -349,7 +381,9 @@ read_element(PInfo pi) {
int done = 0;
attr_stack_init(&attrs);
- ename = read_name_token(pi);
+ if (0 == (ename = read_name_token(pi))) {
+ return 0;
+ }
end = pi->s;
elen = end - ename;
next_non_white(pi);
@@ -361,7 +395,8 @@ read_element(PInfo pi) {
if ('>' != *pi->s) {
/*printf("*** '%s' ***\n", pi->s); */
attr_stack_cleanup(&attrs);
- raise_error("invalid format, element not closed", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, element not closed", pi->str, pi->s);
+ return 0;
}
pi->s++; /* past > */
pi->pcb->add_element(pi, ename, attrs.head, hasChildren);
@@ -380,13 +415,15 @@ read_element(PInfo pi) {
switch (c) {
case '\0':
attr_stack_cleanup(&attrs);
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return 0;
case '/':
/* Element with just attributes. */
pi->s++;
if ('>' != *pi->s) {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, element not closed", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, element not closed", pi->str, pi->s);
+ return 0;
}
pi->s++;
pi->pcb->add_element(pi, ename, attrs.head, hasChildren);
@@ -404,7 +441,10 @@ read_element(PInfo pi) {
default:
/* Attribute name so it's an element and the attribute will be */
/* added to it. */
- attr_name = read_name_token(pi);
+ if (0 == (attr_name = read_name_token(pi))) {
+ attr_stack_cleanup(&attrs);
+ return 0;
+ }
end = pi->s;
next_non_white(pi);
if ('=' != *pi->s++) {
@@ -417,17 +457,21 @@ read_element(PInfo pi) {
break;
} else {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, no attribute value", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, no attribute value", pi->str, pi->s);
+ return 0;
}
}
*end = '\0'; /* terminate name */
/* read value */
next_non_white(pi);
- attr_value = read_quoted_value(pi);
+ if (0 == (attr_value = read_quoted_value(pi))) {
+ return 0;
+ }
if (0 != strchr(attr_value, '&')) {
if (0 != collapse_special(pi, (char*)attr_value)) {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, special character does not end with a semicolon", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, special character does not end with a semicolon", pi->str, pi->s);
+ return 0;
}
}
attr_stack_push(&attrs, attr_name, attr_value);
@@ -452,7 +496,8 @@ read_element(PInfo pi) {
c = *pi->s++;
if ('\0' == c) {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return 0;
}
if ('<' == c) {
char *slash;
@@ -470,7 +515,8 @@ read_element(PInfo pi) {
read_cdata(pi);
} else {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, invalid comment or CDATA format", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, invalid comment or CDATA format", pi->str, pi->s);
+ return 0;
}
break;
case '?': /* processing instruction */
@@ -480,7 +526,10 @@ read_element(PInfo pi) {
case '/':
slash = pi->s;
pi->s++;
- name = read_name_token(pi);
+ if (0 == (name = read_name_token(pi))) {
+ attr_stack_cleanup(&attrs);
+ return 0;
+ }
end = pi->s;
next_non_white(pi);
c = *pi->s;
@@ -491,12 +540,14 @@ read_element(PInfo pi) {
pi->pcb->end_element(pi, ename);
return name;
} else {
- raise_error("invalid format, elements overlap", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, elements overlap", pi->str, pi->s);
+ return 0;
}
}
if ('>' != c) {
attr_stack_cleanup(&attrs);
- raise_error("invalid format, element not closed", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, element not closed", pi->str, pi->s);
+ return 0;
}
if (first && start != slash - 1) {
/* some white space between start and here so add as text */
@@ -512,7 +563,8 @@ read_element(PInfo pi) {
if (TolerantEffort == pi->options->effort) {
return 0;
} else {
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return 0;
}
default:
first = 0;
@@ -528,6 +580,8 @@ read_element(PInfo pi) {
pi->pcb->end_element(pi, ename);
return name;
}
+ } else if (err_has(&pi->err)) {
+ return 0;
}
break;
}
@@ -571,7 +625,8 @@ read_text(PInfo pi) {
pi->s--;
break;
case '\0':
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return;
default:
if (end <= (b + (('&' == c) ? 7 : 0))) { /* extra 8 for special just in case it is sequence of bytes */
unsigned long size;
@@ -633,7 +688,8 @@ read_reduced_text(PInfo pi) {
pi->s--;
break;
case '\0':
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return;
default:
if (end <= (b + spc + (('&' == c) ? 7 : 0))) { /* extra 8 for special just in case it is sequence of bytes */
unsigned long size;
@@ -694,7 +750,8 @@ read_name_token(PInfo pi) {
return start;
case '\0':
/* documents never terminate after a name token */
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return 0;
break; /* to avoid warnings */
default:
break;
@@ -711,7 +768,8 @@ read_cdata(PInfo pi) {
start = pi->s;
end = strstr(pi->s, "]]>");
if (end == 0) {
- raise_error("invalid format, CDATA not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, CDATA not terminated", pi->str, pi->s);
+ return;
}
*end = '\0';
pi->s = end + 3;
@@ -752,19 +810,22 @@ read_quoted_value(PInfo pi) {
value = pi->s;
for (; *pi->s != term; pi->s++) {
if ('\0' == *pi->s) {
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return 0;
}
}
*pi->s = '\0'; /* terminate value */
pi->s++; /* move past quote */
} else if (StrictEffort == pi->options->effort) {
- raise_error("invalid format, expected a quote character", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, expected a quote character", pi->str, pi->s);
+ return 0;
} else if (TolerantEffort == pi->options->effort) {
value = pi->s;
for (; 1; pi->s++) {
switch (*pi->s) {
case '\0':
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return 0;
case ' ':
case '/':
case '>':
@@ -784,7 +845,8 @@ read_quoted_value(PInfo pi) {
value = pi->s;
next_white(pi);
if ('\0' == *pi->s) {
- raise_error("invalid format, document not terminated", pi->str, pi->s);
+ set_error(&pi->err, "invalid format, document not terminated", pi->str, pi->s);
+ return 0;
}
*pi->s++ = '\0'; /* terminate value */
}
@@ -924,8 +986,9 @@ read_coded_chars(PInfo pi, char *text) {
*text++ = '&';
return text;
} else {
- /*raise_error("Invalid encoding, need UTF-8 or UTF-16 encoding to parse &#nnnn; character sequences.", pi->str, pi->s); */
- raise_error("Invalid encoding, need UTF-8 encoding to parse &#nnnn; character sequences.", pi->str, pi->s);
+ /*set_error(&pi->err, "Invalid encoding, need UTF-8 or UTF-16 encoding to parse &#nnnn; character sequences.", pi->str, pi->s); */
+ set_error(&pi->err, "Invalid encoding, need UTF-8 encoding to parse &#nnnn; character sequences.", pi->str, pi->s);
+ return 0;
}
pi->s = s;
}
@@ -1006,8 +1069,9 @@ collapse_special(PInfo pi, char *str) {
pi->options->rb_enc = ox_utf8_encoding;
b = ucs_to_utf8_chars(b, u);
} else {
- /* raise_error("Invalid encoding, need UTF-8 or UTF-16 encoding to parse &#nnnn; character sequences.", pi->str, pi->s);*/
- raise_error("Invalid encoding, need UTF-8 encoding to parse &#nnnn; character sequences.", pi->str, pi->s);
+ /* set_error(&pi->err, "Invalid encoding, need UTF-8 or UTF-16 encoding to parse &#nnnn; character sequences.", pi->str, pi->s);*/
+ set_error(&pi->err, "Invalid encoding, need UTF-8 encoding to parse &#nnnn; character sequences.", pi->str, pi->s);
+ return 0;
}
s = end + 1;
} else {
View
2  lib/ox/version.rb
@@ -1,5 +1,5 @@
module Ox
# Current version of the module.
- VERSION = '2.0.1b2'
+ VERSION = '2.0.1'
end
View
5 notes
@@ -4,7 +4,10 @@
^c^s show subtree
- todo
- - use helper stack in gen_load and obj_load
+ - handle exceptions differently, place in PInfo and process on return
+ - struct of VALUE (class) and msg[128]
+ - pass as pointer arg after init to ox_parse, defuse_bom
+
- continuous sax parser
Please sign in to comment.
Something went wrong with that request. Please try again.