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)
       ]
 )

Reply via email to