diff options
Diffstat (limited to 'src/expat_erl.c')
-rw-r--r-- | src/expat_erl.c | 128 |
1 files changed, 112 insertions, 16 deletions
diff --git a/src/expat_erl.c b/src/expat_erl.c index a1a950e3..82be2307 100644 --- a/src/expat_erl.c +++ b/src/expat_erl.c @@ -5,6 +5,107 @@ #include <ei.h> #include <expat.h> +#define EI_ENCODE_STRING_BUG + +#ifdef EI_ENCODE_STRING_BUG + +/* + * Workaround for EI encode_string bug + */ + +#define put8(s,n) do { \ + (s)[0] = (char)((n) & 0xff); \ + (s) += 1; \ +} while (0) + +#define put16be(s,n) do { \ + (s)[0] = ((n) >> 8) & 0xff; \ + (s)[1] = (n) & 0xff; \ + (s) += 2; \ +} while (0) + +#define put32be(s,n) do { \ + (s)[0] = ((n) >> 24) & 0xff; \ + (s)[1] = ((n) >> 16) & 0xff; \ + (s)[2] = ((n) >> 8) & 0xff; \ + (s)[3] = (n) & 0xff; \ + (s) += 4; \ +} while (0) + +int ei_encode_string_len_fixed(char *buf, int *index, const char *p, int len) +{ + char *s = buf + *index; + char *s0 = s; + int i; + + if (len <= 0xffff) { + if (!buf) s += 3; + else { + put8(s,ERL_STRING_EXT); + put16be(s,len); + memmove(s,p,len); /* unterminated string */ + } + s += len; + } + else { + if (!buf) s += 6 + (2*len); + else { + /* strings longer than 65535 are encoded as lists */ + put8(s,ERL_LIST_EXT); + put32be(s,len); + + for (i=0; i<len; i++) { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,p[i]); + } + + put8(s,ERL_NIL_EXT); + } + } + + *index += s-s0; + + return 0; +} + +int ei_encode_string_fixed(char *buf, int *index, const char *p) +{ + return ei_encode_string_len_fixed(buf, index, p, strlen(p)); +} + +int ei_x_encode_string_len_fixed(ei_x_buff* x, const char* s, int len) +{ + int i = x->index; + ei_encode_string_len_fixed(NULL, &i, s, len); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_string_len_fixed(x->buff, &x->index, s, len); +} + +int ei_x_encode_string_fixed(ei_x_buff* x, const char* s) +{ + return ei_x_encode_string_len_fixed(x, s, strlen(s)); +} + +#else + +#define ei_encode_string_len_fixed(buf, index, p, len) \ + ei_encode_string_len(buf, index, p, len) +#define ei_encode_string_fixed(buf, index, p) \ + ei_encode_string(buf, index, p) +#define ei_x_encode_string_len_fixed(x, s, len) \ + ei_x_encode_string_len(x, s, len) +#define ei_x_encode_string_fixed(x, s) \ + ei_x_encode_string(x, s) + +#endif + +#define XML_START 0 +#define XML_END 1 +#define XML_CDATA 2 +#define XML_ERROR 3 + + typedef struct { ErlDrvPort port; XML_Parser parser; @@ -19,19 +120,19 @@ void *erlXML_StartElementHandler(expat_data *d, ei_x_new_with_version(&buf); ei_x_encode_tuple_header(&buf, 2); - ei_x_encode_atom(&buf, "xmlstart"); + ei_x_encode_long(&buf, XML_START); ei_x_encode_tuple_header(&buf, 2); - ei_x_encode_string(&buf, name); + ei_x_encode_string_fixed(&buf, name); for (i = 0; atts[i]; i += 2) {} ei_x_encode_list_header(&buf, i/2); - + for (i = 0; atts[i]; i += 2) { ei_x_encode_tuple_header(&buf, 2); - ei_x_encode_string(&buf, atts[i]); - ei_x_encode_string(&buf, atts[i+1]); + ei_x_encode_string_fixed(&buf, atts[i]); + ei_x_encode_string_fixed(&buf, atts[i+1]); } ei_x_encode_empty_list(&buf); @@ -48,8 +149,8 @@ void *erlXML_EndElementHandler(expat_data *d, ei_x_new_with_version(&buf); ei_x_encode_tuple_header(&buf, 2); - ei_x_encode_atom(&buf, "xmlend"); - ei_x_encode_string(&buf, name); + ei_x_encode_long(&buf, XML_END); + ei_x_encode_string_fixed(&buf, name); driver_output(d->port, buf.buff, buf.index); ei_x_free(&buf); @@ -64,8 +165,8 @@ void *erlXML_CharacterDataHandler(expat_data *d, ei_x_new_with_version(&buf); ei_x_encode_tuple_header(&buf, 2); - ei_x_encode_atom(&buf, "xmlcdata"); - ei_x_encode_string_len(&buf, s, len); + ei_x_encode_long(&buf, XML_CDATA); + ei_x_encode_string_len_fixed(&buf, s, len); driver_output(d->port, buf.buff, buf.index); ei_x_free(&buf); @@ -104,11 +205,6 @@ static void expat_erl_output(ErlDrvData handle, char *buff, int bufflen) char *errstring; ei_x_buff buf; - /*buff[bufflen] = 0; - - fprintf(stderr, "RCVD: '%s'\n", buff); - fflush(stderr);*/ - res = XML_Parse(d->parser, buff, bufflen, 0); if(!res) @@ -118,10 +214,10 @@ static void expat_erl_output(ErlDrvData handle, char *buff, int bufflen) ei_x_new_with_version(&buf); ei_x_encode_tuple_header(&buf, 2); - ei_x_encode_atom(&buf, "xmlerror"); + ei_x_encode_long(&buf, XML_ERROR); ei_x_encode_tuple_header(&buf, 2); ei_x_encode_long(&buf, errcode); - ei_x_encode_string(&buf, errstring); + ei_x_encode_string_fixed(&buf, errstring); driver_output(d->port, buf.buff, buf.index); ei_x_free(&buf); |