Package: python-cjson Version: 1.0.5-4build1 Severity: normal
I've written a patch that fixes this and is resonably fast. I'm sure there are faster ways to do this, but this is about how much time I'm willing to spend on it :) -- no debconf information
Index: python-cjson-1.0.5/cjson.c =================================================================== --- python-cjson-1.0.5.orig/cjson.c +++ python-cjson-1.0.5/cjson.c @@ -19,6 +19,9 @@ int all_unicode; // make all output strings unicode if true } JSONData; +unsigned int *strutil_remove_index(unsigned int *arr, size_t *num_elements, int index); +char *strutil_do_removal(const char *s_in, size_t s_in_len, unsigned int *mask, size_t num_elements); + static PyObject* encode_object(PyObject *object); static PyObject* encode_string(PyObject *object); static PyObject* encode_unicode(PyObject *object); @@ -120,9 +123,12 @@ int c, escaping, has_unicode, string_escape; Py_ssize_t len; char *ptr; + unsigned int *escaped_solidus_mask = NULL; + size_t escaped_solidus_mask_size = 0; // look for the closing quote escaping = has_unicode = string_escape = False; + ptr = jsondata->ptr + 1; while (True) { c = *ptr; @@ -145,6 +151,11 @@ case 'u': has_unicode = True; break; + case '/': + escaped_solidus_mask = strutil_remove_index(escaped_solidus_mask, + &escaped_solidus_mask_size, + ptr - jsondata->ptr - 2); + /* Intentionally not break'ing */ case '"': case 'r': case 'n': @@ -164,9 +175,22 @@ if (has_unicode || jsondata->all_unicode) object = PyUnicode_DecodeUnicodeEscape(jsondata->ptr+1, len, NULL); - else if (string_escape) - object = PyString_DecodeEscape(jsondata->ptr+1, len, NULL, 0, NULL); - else + else if (string_escape) { + char *s; + s = jsondata->ptr+1; + + if (escaped_solidus_mask_size) { + s = strutil_do_removal(s, len, escaped_solidus_mask, escaped_solidus_mask_size); + len = len - escaped_solidus_mask_size; + } + + object = PyString_DecodeEscape(s, len, NULL, 0, NULL); + + if (escaped_solidus_mask_size) { + free(s); + free(escaped_solidus_mask); + } + } else object = PyString_FromStringAndSize(jsondata->ptr+1, len); if (object == NULL) { Index: python-cjson-1.0.5/jsontest.py =================================================================== --- python-cjson-1.0.5.orig/jsontest.py +++ python-cjson-1.0.5/jsontest.py @@ -91,6 +91,12 @@ s = cjson.encode(r'/') self.assertEqual(r'"\/"', _removeWhitespace(s)) +# Disabled by Soren Hansen. It's supposed to be escaped, +# so verifying that it isn't is nonsense. +# def testWriteNonEscapedSolidus(self): +# s = cjson.encode(r'/') +# self.assertEqual(r'"/"', _removeWhitespace(s)) + def testWriteEscapedReverseSolidus(self): s = cjson.encode("\\") self.assertEqual(r'"\\"', _removeWhitespace(s)) Index: python-cjson-1.0.5/strutil.c =================================================================== --- /dev/null +++ python-cjson-1.0.5/strutil.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2011 Dan Pascu. See LICENSE for details. + * Author: Soren Hansen <so...@linux2go.dk> + * + * Utility functions for cjson (kept separate to make unit testing easier). + * + * To run the tests: + * ./test_strutil.sh + * + * Disclaimer: + * I don't think it is very pretty. At all. I do think it's pretty fast, + * though. + */ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> + +#define ARRAY_SIZE_INCREMENTS 256 + +static size_t size_to_allocate(int bit); +unsigned int *strutil_remove_index(unsigned int *arr, size_t *num_elements, int index); +char *strutil_do_removal(const char *s_in, size_t s_in_len, unsigned int *mask, size_t num_elements); + +static size_t +size_to_allocate(int num_elements) { + return (((num_elements+255)/ARRAY_SIZE_INCREMENTS))*ARRAY_SIZE_INCREMENTS; +} + +unsigned int *strutil_remove_index(unsigned int *arr, size_t *num_elements, int index) { + size_t required_size; + + required_size = size_to_allocate(*num_elements+1); + if (required_size > size_to_allocate(*num_elements)) { + if ((arr = realloc(arr, sizeof(int)*required_size)) == NULL) + return NULL; + } + arr[(*num_elements)++] = index; + return arr; +} + +char *strutil_do_removal(const char *s_in, size_t s_in_len, + unsigned int *arr, size_t num_elements) { + const char *in_ptr; + char *s_out = malloc(s_in_len - num_elements); + char *out_ptr; + int i = 0; + int last_index = s_in_len; + int width; + + /* Point to last element of each of the arrays */ + in_ptr = s_in + s_in_len; + out_ptr = s_out + s_in_len - num_elements; + + for (i=num_elements-1;i>=0;i--,in_ptr--) { + width = last_index-arr[i]-1; + out_ptr -= width; + in_ptr -= width; + memcpy(out_ptr, in_ptr, width); + last_index = arr[i]; + } + memcpy(s_out, s_in, last_index); + return s_out; +} + +#ifdef TEST +void test_strutil_do_removal(void) { + unsigned int *arr = NULL; + size_t num_elements = 0; + char *s_in = "X123456X789X123X"; + char *s_out; + + /* Mark all the X's for removal */ + arr = strutil_remove_index(arr, &num_elements, 0); + arr = strutil_remove_index(arr, &num_elements, 7); + arr = strutil_remove_index(arr, &num_elements, 11); + arr = strutil_remove_index(arr, &num_elements, 15); + + s_out = strutil_do_removal(s_in, strlen(s_in), arr, num_elements); + assert(strcmp(s_out, "123456789123") == 0); + free(s_out); + free(arr); +} + +void test_required_size_for_bit(void) { + assert(size_to_allocate(0) == 0); + assert(size_to_allocate(1) == 256); + assert(size_to_allocate(255) == 256); + assert(size_to_allocate(256) == 256); + assert(size_to_allocate(257) == 512); +} + +int main(int argc, char *argv[]) { + test_required_size_for_bit(); + test_strutil_do_removal(); + return 0; +} +#endif Index: python-cjson-1.0.5/test_strutil.sh =================================================================== --- /dev/null +++ python-cjson-1.0.5/test_strutil.sh @@ -0,0 +1,5 @@ +#!/bin/sh +set -e +gcc -Wall -pg -fprofile-arcs -o strutil_unittest -O0 -DTEST strutil.c -lm +#gcc -o strutil_unittest -DTEST strutil.c -lm +./strutil_unittest Index: python-cjson-1.0.5/setup.py =================================================================== --- python-cjson-1.0.5.orig/setup.py +++ python-cjson-1.0.5/setup.py @@ -25,6 +25,6 @@ "Topic :: Software Development :: Libraries :: Python Modules" ], ext_modules = [ - Extension(name='cjson', sources=['cjson.c'], define_macros=macros) + Extension(name='cjson', sources=['cjson.c','strutil.c'], define_macros=macros) ] )