apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From minf...@apache.org
Subject svn commit: r1835350 - in /apr/apr-util/branches/1.7.x: CHANGES build.conf include/apr_json.h json/ json/apr_json.c json/apr_json_decode.c json/apr_json_encode.c test/Makefile.in test/abts_tests.h test/testjson.c test/testutil.h
Date Sun, 08 Jul 2018 11:42:12 GMT
Author: minfrin
Date: Sun Jul  8 11:42:12 2018
New Revision: 1835350

URL: http://svn.apache.org/viewvc?rev=1835350&view=rev
Log:
Backport r1835348:

apr_json: Add support for encoding and decoding RFC8259 JSON.

Submitted by: Moriyoshi Koizumi <mozo mozo jp>

Added:
    apr/apr-util/branches/1.7.x/include/apr_json.h
    apr/apr-util/branches/1.7.x/json/
    apr/apr-util/branches/1.7.x/json/apr_json.c
    apr/apr-util/branches/1.7.x/json/apr_json_decode.c
    apr/apr-util/branches/1.7.x/json/apr_json_encode.c
    apr/apr-util/branches/1.7.x/test/testjson.c
Modified:
    apr/apr-util/branches/1.7.x/CHANGES
    apr/apr-util/branches/1.7.x/build.conf
    apr/apr-util/branches/1.7.x/test/Makefile.in
    apr/apr-util/branches/1.7.x/test/abts_tests.h
    apr/apr-util/branches/1.7.x/test/testutil.h

Modified: apr/apr-util/branches/1.7.x/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/CHANGES?rev=1835350&r1=1835349&r2=1835350&view=diff
==============================================================================
--- apr/apr-util/branches/1.7.x/CHANGES [utf-8] (original)
+++ apr/apr-util/branches/1.7.x/CHANGES [utf-8] Sun Jul  8 11:42:12 2018
@@ -1,6 +1,9 @@
                                                      -*- coding: utf-8 -*-
 Changes with APR-util 1.7.0
 
+  *) apr_json: Add support for encoding and decoding RFC8259 JSON.
+     [Moriyoshi Koizumi <mozo mozo jp>]
+
   *) New apr_crypto_prng API and apr_crypto_random[_thread]_bytes() functions.
      [Yann Ylavic]
 

Modified: apr/apr-util/branches/1.7.x/build.conf
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/build.conf?rev=1835350&r1=1835349&r2=1835350&view=diff
==============================================================================
--- apr/apr-util/branches/1.7.x/build.conf (original)
+++ apr/apr-util/branches/1.7.x/build.conf Sun Jul  8 11:42:12 2018
@@ -23,6 +23,7 @@ paths =
   dbm/sdbm/*.c
   encoding/*.c
   hooks/*.c
+  json/*.c
   ldap/apr_ldap_stub.c
   ldap/apr_ldap_url.c
   misc/*.c

Added: apr/apr-util/branches/1.7.x/include/apr_json.h
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/include/apr_json.h?rev=1835350&view=auto
==============================================================================
--- apr/apr-util/branches/1.7.x/include/apr_json.h (added)
+++ apr/apr-util/branches/1.7.x/include/apr_json.h Sun Jul  8 11:42:12 2018
@@ -0,0 +1,248 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file apr_json.h
+ * @brief APR-UTIL JSON Library
+ */
+#ifndef APR_JSON_H
+#define APR_JSON_H
+
+/**
+ * @defgroup APR_Util_JSON JSON Encoding and Decoding
+ * @ingroup APR_Util
+ * @{
+ */
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_tables.h"
+#include "apr_hash.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @package Apache JSON library
+ *
+ * RFC8259 compliant JSON encoding and decoding library.
+ *
+ * https://tools.ietf.org/html/rfc8259
+ *
+ * This API generates UTF-8 encoded JSON, and writes it to the
+ * bucket brigade specified. All strings are verified as valid UTF-8
+ * before processing, with invalid UTF-8 characters replaced.
+ *
+ * This API parses UTF-8 encoded JSON, and returns the result as
+ * a set of structures. All JSON strings are unescaped. Any bad
+ * characters or formatting will cause parsing to be terminated
+ * and an error returned, along with the offset of the error.
+ *
+ * Whitespace may be optionally preserved or ignored as required
+ * during generation and parsing.
+ *
+ * The ordering of object keys is preserved, allowing the decode and
+ * encode process to reproduce an identical result. This maintains
+ * stable behaviour during unit tests.
+ */
+
+/**
+ * When passing a string to one of the encode functions, this value can be
+ * passed to indicate a string-valued key, and have the length computed
+ * automatically.
+ */
+#define APR_JSON_VALUE_STRING      (-1)
+
+/**
+ * Flag indicating no special processing.
+ */
+#define APR_JSON_FLAGS_NONE 0
+
+/**
+ * Flag indicating include whitespace.
+ */
+#define APR_JSON_FLAGS_WHITESPACE 1
+
+/**
+ * A structure to hold a JSON object.
+ */
+typedef struct apr_json_object_t apr_json_object_t;
+
+/**
+ * Enum that represents the type of the given JSON value.
+ */
+typedef enum apr_json_type_e {
+    APR_JSON_OBJECT,
+    APR_JSON_ARRAY,
+    APR_JSON_STRING,
+    APR_JSON_LONG,
+    APR_JSON_DOUBLE,
+    APR_JSON_BOOLEAN,
+    APR_JSON_NULL
+} apr_json_type_e;
+
+/**
+ * A structure to hold a UTF-8 encoded JSON string.
+ */
+typedef struct apr_json_string_t {
+    /** pointer to the string */
+    const char *p;
+    /** string length */
+    apr_size_t len;
+} apr_json_string_t;
+
+/**
+ * A structure that holds a JSON value.
+ *
+ * Use apr_json_value_create() to allocate.
+ */
+typedef struct apr_json_value_t {
+    /** preceding whitespace, if any */
+    const char *pre;
+    /** trailing whitespace, if any */
+    const char *post;
+    /** type of the value */
+    apr_json_type_e type;
+    /** actual value. which member is valid depends on type. */
+    union {
+        /** JSON object */
+        apr_json_object_t *object;
+        /** JSON array */
+        apr_array_header_t *array;
+        /** JSON floating point value */
+        double dnumber;
+        /** JSON long integer value */
+        apr_int64_t lnumber;
+        /** JSON UTF-8 encoded string value */
+        apr_json_string_t string;
+        /** JSON boolean value */
+        int boolean;
+    } value;
+} apr_json_value_t;
+
+/**
+ * A structure to hold a JSON object key value pair.
+ *
+ * Use apr_json_object_set() to allocate.
+ */
+typedef struct apr_json_kv_t {
+    /** Links to the rest of the kv pairs */
+    APR_RING_ENTRY(apr_json_kv_t) link;
+    /** the key */
+    apr_json_value_t *k;
+    /** the value */
+    apr_json_value_t *v;
+} apr_json_kv_t;
+
+/**
+ * A structure to hold a JSON object.
+ *
+ * Use apr_json_object_create() to allocate.
+ */
+typedef struct apr_json_object_t {
+    /** The key value pairs in the object are in this list */
+    APR_RING_HEAD(apr_json_object_list_t, apr_json_kv_t) list;
+    /** JSON object */
+    apr_hash_t *hash;
+} apr_json_object_t;
+
+/**
+ * Allocate and return a apr_json_value_t structure.
+ *
+ * @param pool The pool to allocate from.
+ * @return The apr_json_value_t structure.
+ */
+APU_DECLARE(apr_json_value_t *) apr_json_value_create(apr_pool_t *pool)
+        __attribute__((nonnull(1)));
+
+/**
+ * Allocate and return a apr_json_object_t structure.
+ *
+ * @param pool The pool to allocate from.
+ * @return The apr_json_object_t structure.
+ */
+APU_DECLARE(apr_json_object_t *) apr_json_object_create(apr_pool_t *pool)
+        __attribute__((nonnull(1)));
+
+/**
+ * Associate a value with a key in a JSON object.
+ * @param obj The JSON object.
+ * @param key Pointer to the key.
+ * @param val Value to associate with the key.
+ * @remark If the value is NULL the key value pair is deleted.
+ */
+APU_DECLARE(void) apr_json_object_set(apr_json_object_t *obj,
+        apr_json_value_t *key, apr_json_value_t *val,
+        apr_pool_t *pool) __attribute__((nonnull(1, 2, 4)));
+
+/**
+ * Look up the value associated with a key in a JSON object.
+ * @param ht The hash table
+ * @param key Pointer to the key
+ * @return Returns NULL if the key is not present.
+ */
+APU_DECLARE(apr_json_kv_t *)
+        apr_json_object_get(apr_json_object_t *obj, const char *key)
+        __attribute__((nonnull(1, 2)));
+
+/**
+ * Decode utf8-encoded JSON string into apr_json_value_t.
+ * @param retval the result
+ * @param injson utf8-encoded JSON string.
+ * @param size length of the input string.
+ * @param offset number of characters processed.
+ * @param flags set to APR_JSON_FLAGS_WHITESPACE to preserve whitespace,
+ *   or APR_JSON_FLAGS_NONE to filter whitespace.
+ * @param level maximum nesting level we are prepared to decode.
+ * @param pool pool used to allocate the result from.
+ * @return APR_SUCCESS on success, APR_EOF if the JSON text is truncated.
+ *   APR_BADCH when a decoding error has occurred (the location of the error
+ *   is at offset), APR_EINVAL if the level has been exceeded, or
+ *   APR_ENOTIMPL on platforms where not implemented.
+ */
+APU_DECLARE(apr_status_t) apr_json_decode(apr_json_value_t ** retval,
+        const char *injson, apr_ssize_t size, apr_off_t * offset,
+        int flags, int level, apr_pool_t * pool)
+        __attribute__((nonnull(1, 2, 7)));
+
+/**
+ * Encode data represented as apr_json_value_t to utf8-encoded JSON string
+ * and append it to the specified brigade.
+ *
+ * All JSON strings are checked for invalid UTF-8 character sequences,
+ * and if found invalid sequences are replaced with the replacement
+ * character "�" (U+FFFD).
+ *
+ * @param brigade brigade the result will be appended to.
+ * @param flush optional flush function for the brigade. Can be NULL.
+ * @param ctx optional contaxt for the flush function. Can be NULL.
+ * @param json the JSON data.
+ * @param flags set to APR_JSON_FLAGS_WHITESPACE to preserve whitespace,
+ *   or APR_JSON_FLAGS_NONE to filter whitespace.
+ * @param pool pool used to allocate the buckets from.
+ * @return APR_SUCCESS on success, or APR_ENOTIMPL on platforms where not
+ *   implemented.
+ */
+APU_DECLARE(apr_status_t) apr_json_encode(apr_bucket_brigade * brigade,
+        apr_brigade_flush flush, void *ctx, const apr_json_value_t * json,
+        int flags, apr_pool_t * pool) __attribute__((nonnull(1, 4, 6)));
+
+#ifdef __cplusplus
+}
+#endif
+/** @} */
+#endif /* APR_JSON_H */

Added: apr/apr-util/branches/1.7.x/json/apr_json.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/json/apr_json.c?rev=1835350&view=auto
==============================================================================
--- apr/apr-util/branches/1.7.x/json/apr_json.c (added)
+++ apr/apr-util/branches/1.7.x/json/apr_json.c Sun Jul  8 11:42:12 2018
@@ -0,0 +1,74 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "apr_json.h"
+
+#define APR_JSON_OBJECT_INSERT_TAIL(o, e) do {                              \
+        apr_json_kv_t *ap__b = (e);                                        \
+        APR_RING_INSERT_TAIL(&(o)->list, ap__b, apr_json_kv_t, link);      \
+        APR_RING_CHECK_CONSISTENCY(&(o)->list, apr_json_kv_t, link);                             \
+    } while (0)
+
+apr_json_value_t *apr_json_value_create(apr_pool_t *pool)
+{
+    return apr_pcalloc(pool, sizeof(apr_json_value_t));
+}
+
+apr_json_object_t *apr_json_object_create(apr_pool_t *pool)
+{
+    apr_json_object_t *object = apr_pcalloc(pool,
+            sizeof(apr_json_object_t));
+    APR_RING_INIT(&object->list, apr_json_kv_t, link);
+    object->hash = apr_hash_make(pool);
+
+    return object;
+}
+
+void apr_json_object_set(apr_json_object_t *object, apr_json_value_t *key,
+        apr_json_value_t *val, apr_pool_t *pool)
+{
+    apr_json_kv_t *kv;
+
+    kv = apr_hash_get(object->hash, key->value.string.p, key->value.string.len);
+
+    if (!val) {
+        if (kv) {
+            apr_hash_set(object->hash, key->value.string.p, key->value.string.len,
+                    NULL);
+            APR_RING_REMOVE((kv), link);
+        }
+        return;
+    }
+
+    if (!kv) {
+        kv = apr_palloc(pool, sizeof(apr_json_kv_t));
+        APR_RING_ELEM_INIT(kv, link);
+        APR_JSON_OBJECT_INSERT_TAIL(object, kv);
+        apr_hash_set(object->hash, key->value.string.p, key->value.string.len,
+                kv);
+    }
+
+    kv->k = key;
+    kv->v = val;
+}
+
+apr_json_kv_t *apr_json_object_get(apr_json_object_t *object, const char *key)
+{
+    return apr_hash_get(object->hash, key, APR_HASH_KEY_STRING);
+}

Added: apr/apr-util/branches/1.7.x/json/apr_json_decode.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/json/apr_json_decode.c?rev=1835350&view=auto
==============================================================================
--- apr/apr-util/branches/1.7.x/json/apr_json_decode.c (added)
+++ apr/apr-util/branches/1.7.x/json/apr_json_decode.c Sun Jul  8 11:42:12 2018
@@ -0,0 +1,819 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "apr_json.h"
+
+#if !APR_CHARSET_EBCDIC
+
+typedef struct _json_link_t {
+    apr_json_value_t *value;
+    struct _json_link_t *next;
+} json_link_t;
+
+typedef struct apr_json_scanner_t {
+    apr_pool_t *pool;
+    const char *p;
+    const char *e;
+    int flags;
+    int level;
+} apr_json_scanner_t;
+
+static apr_status_t apr_json_decode_value(apr_json_scanner_t * self, apr_json_value_t ** retval);
+
+/* stolen from mod_mime_magic.c :) */
+/* Single hex char to int; -1 if not a hex char. */
+static int hex_to_int(int c)
+{
+    if (isdigit(c))
+        return c - '0';
+    if ((c >= 'a') && (c <= 'f'))
+        return c + 10 - 'a';
+    if ((c >= 'A') && (c <= 'F'))
+        return c + 10 - 'A';
+    return -1;
+}
+
+static apr_ssize_t ucs4_to_utf8(char *out, int code)
+{
+    if (code < 0x00000080) {
+        out[0] = code;
+        return 1;
+    }
+    else if (code < 0x00000800) {
+        out[0] = 0xc0 + (code >> 6);
+        out[1] = 0x80 + (code & 0x3f);
+        return 2;
+    }
+    else if (code < 0x00010000) {
+        out[0] = 0xe0 + (code >> 12);
+        out[1] = 0x80 + ((code >> 6) & 0x3f);
+        out[2] = 0x80 + (code & 0x3f);
+        return 3;
+    }
+    else if (code < 0x00200000) {
+        out[0] = 0xd0 + (code >> 18);
+        out[1] = 0x80 + ((code >> 12) & 0x3f);
+        out[2] = 0x80 + ((code >> 6) & 0x3f);
+        out[3] = 0x80 + (code & 0x3F);
+        return 4;
+    }
+    return 0;
+}
+
+static apr_status_t apr_json_decode_string(apr_json_scanner_t * self, apr_json_string_t * retval)
+{
+    apr_status_t status = APR_SUCCESS;
+    apr_json_string_t string;
+    const char *p = self->p;
+    const char *e;
+    char *q;
+
+    if (self->p >= self->e) {
+        status = APR_EOF;
+        goto out;
+    }
+
+    self->p++; /* eat the leading '"' */
+
+    /* advance past the \ " */
+    string.len = 0;
+    for (p = self->p, e = self->e; p < e;) {
+        if (*p == '"')
+            break;
+        else if (*p == '\\') {
+            p++;
+            if (p >= e) {
+                status = APR_EOF;
+                goto out;
+            }
+            if (*p == 'u') {
+                if (p + 4 >= e) {
+                    status = APR_EOF;
+                    goto out;
+                }
+                p += 5;
+                string.len += 4;/* an UTF-8 character spans at most 4 bytes */
+                break;
+            }
+            else {
+                string.len++;
+                p++;
+            }
+        }
+        else {
+            string.len++;
+            p++;
+        }
+    }
+
+    string.p = q = apr_pcalloc(self->pool, string.len + 1);
+    e = p;
+
+#define VALIDATE_UTF8_SUCCEEDING_BYTE(p) \
+    if (*(unsigned char *)(p) < 0x80 || *(unsigned char *)(p) >= 0xc0) { \
+        status = APR_BADCH; \
+        goto out; \
+    }
+
+    for (p = self->p; p < e;) {
+        switch (*(unsigned char *)p) {
+        case '\\':
+            p++;
+            switch (*p) {
+            case 'u':
+                /* THIS IS REQUIRED TO BE A 4 DIGIT HEX NUMBER */
+                {
+                    int cp = 0;
+                    while (p < e) {
+                        int d = hex_to_int(*p);
+                        if (d < 0) {
+                            status = APR_BADCH;
+                            goto out;
+                        }
+                        cp = (cp << 4) | d;
+                        p++;
+                    }
+                    if (cp >= 0xd800 && cp < 0xdc00) {
+                        /* surrogate pair */
+                        int sc = 0;
+                        if (p + 6 > e) {
+                            status = APR_EOF;
+                            goto out;
+                        }
+                        if (p[0] != '\\' && p[1] != 'u') {
+                            status = APR_BADCH;
+                            goto out;
+                        }
+                        while (p < e) {
+                            int d = hex_to_int(*p);
+                            if (d < 0) {
+                                status = APR_BADCH;
+                                goto out;
+                            }
+                            sc = (sc << 4) | d;
+                            p++;
+                        }
+                        cp = ((cp & 0x3ff) << 10) | (sc & 0x3ff);
+                        if ((cp >= 0xd800 && cp < 0xe000) || (cp >= 0x110000)) {
+                            status = APR_BADCH;
+                            goto out;
+                        }
+                    }
+                    else if (cp >= 0xdc00 && cp < 0xe000) {
+                        status = APR_BADCH;
+                        goto out;
+                    }
+                    q += ucs4_to_utf8(q, cp);
+                }
+                break;
+            case '\\':
+                *q++ = '\\';
+                p++;
+                break;
+            case '/':
+                *q++ = '/';
+                p++;
+                break;
+            case 'n':
+                *q++ = '\n';
+                p++;
+                break;
+            case 'r':
+                *q++ = '\r';
+                p++;
+                break;
+            case 't':
+                *q++ = '\t';
+                p++;
+                break;
+            case 'f':
+                *q++ = '\f';
+                p++;
+                break;
+            case 'b':
+                *q++ = '\b';
+                p++;
+                break;
+            case '"':
+                *q++ = '"';
+                p++;
+                break;
+            default:
+                status = APR_BADCH;
+                goto out;
+            }
+            break;
+
+        case 0xc0:
+        case 0xc1:
+        case 0xc2:
+        case 0xc3:
+        case 0xc4:
+        case 0xc5:
+        case 0xc6:
+        case 0xc7:
+        case 0xc8:
+        case 0xc9:
+        case 0xca:
+        case 0xcb:
+        case 0xcc:
+        case 0xcd:
+        case 0xce:
+        case 0xcf:
+        case 0xd0:
+        case 0xd1:
+        case 0xd2:
+        case 0xd3:
+        case 0xd4:
+        case 0xd5:
+        case 0xd6:
+        case 0xd7:
+        case 0xd8:
+        case 0xd9:
+        case 0xda:
+        case 0xdb:
+        case 0xdc:
+        case 0xdd:
+        case 0xde:
+        case 0xdf:
+            if (p + 1 >= e) {
+                status = APR_EOF;
+                goto out;
+            }
+            *q++ = *p++;
+            VALIDATE_UTF8_SUCCEEDING_BYTE(p);
+            *q++ = *p++;
+            break;
+
+        case 0xe0:
+        case 0xe1:
+        case 0xe2:
+        case 0xe3:
+        case 0xe4:
+        case 0xe5:
+        case 0xe6:
+        case 0xe7:
+        case 0xe8:
+        case 0xe9:
+        case 0xea:
+        case 0xeb:
+        case 0xec:
+        case 0xed:
+        case 0xee:
+        case 0xef:
+            if (p + 2 >= e) {
+                status = APR_EOF;
+                goto out;
+            }
+            *q++ = *p++;
+            VALIDATE_UTF8_SUCCEEDING_BYTE(p);
+            *q++ = *p++;
+            VALIDATE_UTF8_SUCCEEDING_BYTE(p);
+            *q++ = *p++;
+            break;
+
+        case 0xf0:
+        case 0xf1:
+        case 0xf2:
+        case 0xf3:
+        case 0xf4:
+        case 0xf5:
+        case 0xf6:
+        case 0xf7:
+            if (p + 3 >= e) {
+                status = APR_EOF;
+                goto out;
+            }
+            if (((unsigned char *)p)[0] >= 0xf5 || ((unsigned char *)p)[1] >= 0x90) {
+                status = APR_BADCH;
+                goto out;
+            }
+            *q++ = *p++;
+            VALIDATE_UTF8_SUCCEEDING_BYTE(p);
+            *q++ = *p++;
+            VALIDATE_UTF8_SUCCEEDING_BYTE(p);
+            *q++ = *p++;
+            VALIDATE_UTF8_SUCCEEDING_BYTE(p);
+            *q++ = *p++;
+            break;
+
+        case 0xf8:
+        case 0xf9:
+        case 0xfa:
+        case 0xfb:
+            if (p + 4 >= e) {
+                status = APR_EOF;
+                goto out;
+            }
+            status = APR_BADCH;
+            goto out;
+
+        case 0xfc:
+        case 0xfd:
+            if (p + 5 >= e) {
+                status = APR_EOF;
+                goto out;
+            }
+            status = APR_BADCH;
+            goto out;
+
+        default:
+            *q++ = *p++;
+            break;
+        }
+    }
+#undef VALIDATE_UTF8_SUCCEEDING_BYTE
+    p++; /* eat the trailing '"' */
+    *retval = string;
+out:
+    self->p = p;
+    return status;
+}
+
+static apr_status_t apr_json_decode_array(apr_json_scanner_t * self,
+        apr_array_header_t ** retval)
+{
+    apr_status_t status = APR_SUCCESS;
+    apr_pool_t *link_pool = NULL;
+    json_link_t *head = NULL, *tail = NULL;
+    apr_size_t count = 0;
+
+    if ((status = apr_pool_create(&link_pool, self->pool)))
+        return status;
+
+    if (self->p >= self->e) {
+        status = APR_EOF;
+        goto out;
+    }
+
+    self->level--;
+    if (self->level < 0) {
+        return APR_EINVAL;
+    }
+
+    self->p++; /* toss of the leading [ */
+
+    for (;;) {
+        apr_json_value_t *element;
+        json_link_t *new_node;
+
+        if (self->p == self->e) {
+            status = APR_EOF;
+            goto out;
+        }
+
+        if (*self->p == ']') {
+            self->p++;
+            break;
+        }
+
+        if (APR_SUCCESS != (status = apr_json_decode_value(self, &element))) {
+            goto out;
+        }
+
+        new_node = apr_pcalloc(link_pool, sizeof(json_link_t));
+        new_node->value = element;
+        if (tail) {
+            tail->next = new_node;
+        }
+        else {
+            head = new_node;
+        }
+        tail = new_node;
+        count++;
+
+        if (self->p == self->e) {
+            status = APR_EOF;
+            goto out;
+        }
+
+        if (*self->p == ',') {
+            self->p++;
+        }
+        else if (*self->p != ']') {
+            status = APR_BADCH;
+            goto out;
+        }
+    }
+
+    {
+        json_link_t *node;
+        apr_array_header_t *array = apr_array_make(self->pool, count, sizeof(apr_json_value_t *));
+        for (node = head; node; node = node->next) {
+            *((apr_json_value_t **) (apr_array_push(array))) = node->value;
+        }
+        *retval = array;
+    }
+
+    self->level++;
+
+out:
+    if (link_pool) {
+        apr_pool_destroy(link_pool);
+    }
+    return status;
+}
+
+static apr_status_t apr_json_decode_object(apr_json_scanner_t * self,
+        apr_json_object_t ** retval)
+{
+    apr_status_t status = APR_SUCCESS;
+
+    apr_json_object_t *object = apr_json_object_create(self->pool);
+
+    if (self->p >= self->e) {
+        return APR_EOF;
+    }
+
+    self->level--;
+    if (self->level < 0) {
+        return APR_EINVAL;
+    }
+
+    self->p++; /* toss of the leading { */
+
+    for (;;) {
+        apr_json_value_t *key;
+        apr_json_value_t *value;
+
+        if (self->p == self->e) {
+            status = APR_EOF;
+            goto out;
+        }
+
+        if (*self->p == '}') {
+            self->p++;
+            break;
+        }
+
+        if ((status = apr_json_decode_value(self, &key)))
+            goto out;
+
+        if (key->type != APR_JSON_STRING) {
+            status = APR_BADCH;
+            goto out;
+        }
+
+        if (self->p == self->e) {
+            status = APR_EOF;
+            goto out;
+        }
+
+        if (*self->p != ':') {
+            status = APR_BADCH;
+            goto out;
+        }
+
+        self->p++; /* eat the ':' */
+
+        if (self->p == self->e) {
+            status = APR_EOF;
+            goto out;
+        }
+
+        if ((status = apr_json_decode_value(self, &value)))
+            goto out;
+
+        apr_json_object_set(object, key, value, self->pool);
+
+        if (self->p == self->e) {
+            status = APR_EOF;
+            goto out;
+        }
+
+        if (*self->p == ',') {
+            self->p++;
+        }
+        else if (*self->p != '}') {
+            status = APR_BADCH;
+            goto out;
+        }
+    }
+
+    self->level++;
+
+    *retval = object;
+out:
+    return status;
+}
+
+static apr_status_t apr_json_decode_boolean(apr_json_scanner_t * self, int *retval)
+{
+    if (self->p >= self->e)
+        return APR_EOF;
+
+    if (self->e - self->p >= 4 && strncmp("true", self->p, 4) == 0 &&
+        (self->p == self->e ||
+                (!isalnum(((unsigned char *)self->p)[4]) &&
+                        ((unsigned char *)self->p)[4] != '_'))) {
+        self->p += 4;
+        *retval = 1;
+        return APR_SUCCESS;
+    }
+    else if (self->e - self->p >= 5 && strncmp("false", self->p, 5) == 0 &&
+             (self->p == self->e ||
+                     (!isalnum(((unsigned char *)self->p)[5]) &&
+                             ((unsigned char *)self->p)[5] != '_'))) {
+        self->p += 5;
+        *retval = 0;
+        return APR_SUCCESS;
+    }
+    return APR_BADCH;
+}
+
+static apr_status_t apr_json_decode_number(apr_json_scanner_t * self, apr_json_value_t * retval)
+{
+    apr_status_t status = APR_SUCCESS;
+    int treat_as_float = 0, exp_occurred = 0;
+    const char *p = self->p, *e = self->e;
+
+    if (p >= e)
+        return APR_EOF;
+
+    {
+        unsigned char c = *(unsigned char *)p;
+        if (c == '-') {
+            p++;
+            if (p >= e)
+                return APR_EOF;
+            c = *(unsigned char *)p;
+        }
+        if (c == '.') {
+            p++;
+            if (p >= e)
+                return APR_EOF;
+            c = *(unsigned char *)p;
+            treat_as_float = 1;
+        }
+        if (!isdigit(c)) {
+            status = APR_BADCH;
+            goto out;
+        }
+        p++;
+    }
+
+    if (!treat_as_float) {
+        while (p < e) {
+            unsigned char c = *(unsigned char *)p;
+            if (c == 'e' || c == 'E') {
+                p++;
+                if (p >= e)
+                    return APR_EOF;
+                c = *(unsigned char *)p;
+                if (c == '-') {
+                    p++;
+                    if (p >= e)
+                        return APR_EOF;
+                    c = *(unsigned char *)p;
+                }
+                if (!isdigit(c)) {
+                    status = APR_BADCH;
+                    goto out;
+                }
+                treat_as_float = 1;
+                exp_occurred = 1;
+                break;
+            }
+            else if (c == '.') {
+                p++;
+                treat_as_float = 1;
+                break;
+            }
+            else if (!isdigit(c))
+                break;
+            p++;
+        }
+    }
+    else {
+        while (p < e) {
+            unsigned char c = *(unsigned char *)p;
+            if (c == 'e' || c == 'E') {
+                p++;
+                if (p >= e)
+                    return APR_EOF;
+                c = *(unsigned char *)p;
+                if (c == '-') {
+                    p++;
+                    if (p >= e)
+                        return APR_EOF;
+                    c = *(unsigned char *)p;
+                }
+                if (!isdigit(c)) {
+                    status = APR_BADCH;
+                    goto out;
+                }
+                exp_occurred = 1;
+                break;
+            }
+            else if (!isdigit(c))
+                break;
+            p++;
+        }
+    }
+
+    if (treat_as_float) {
+        if (!exp_occurred) {
+            while (p < e) {
+                unsigned char c = *(unsigned char *)p;
+                if (c == 'e' || c == 'E') {
+                    p++;
+                    if (p >= e)
+                        return APR_EOF;
+                    c = *(unsigned char *)p;
+                    if (c == '-') {
+                        p++;
+                        if (p >= e)
+                            return APR_EOF;
+                        c = *(unsigned char *)p;
+                    }
+                    if (!isdigit(c)) {
+                        status = APR_BADCH;
+                        goto out;
+                    }
+                    exp_occurred = 1;
+                    break;
+                }
+                else if (!isdigit(c))
+                    break;
+                p++;
+            }
+        }
+        if (exp_occurred) {
+            if (p >= e || !isdigit(*(unsigned char *)p))
+                return APR_EOF;
+            while (++p < e && isdigit(*(unsigned char *)p));
+        }
+    }
+
+    if (treat_as_float) {
+        retval->type = APR_JSON_DOUBLE;
+        retval->value.dnumber = strtod(self->p, NULL);
+    }
+    else {
+        retval->type = APR_JSON_LONG;
+        retval->value.lnumber = strtol(self->p, NULL, 10);
+    }
+
+out:
+    self->p = p;
+    return status;
+}
+
+static apr_status_t apr_json_decode_null(apr_json_scanner_t * self)
+{
+    if (self->e - self->p >= 4 && strncmp("null", self->p, 4) == 0 &&
+        (self->p == self->e ||
+                (!isalnum(((unsigned char *)self->p)[4]) &&
+                        ((unsigned char *)self->p)[4] != '_'))) {
+        self->p += 4;
+        return APR_SUCCESS;
+    }
+    return APR_BADCH;
+}
+
+static apr_status_t apr_json_decode_space(apr_json_scanner_t * self,
+        const char **space)
+{
+    const char *p = self->p;
+    char *s;
+    int len = 0;
+
+    *space = NULL;
+
+    if (self->p >= self->e) {
+        return APR_SUCCESS;
+    }
+
+    while (p < self->e && isspace(*(unsigned char *)p)) {
+        p++;
+        len++;
+    }
+
+    if (self->flags & APR_JSON_FLAGS_WHITESPACE) {
+        if (len) {
+            *space = s = apr_palloc(self->pool, len + 1);
+
+            while (self->p < self->e && isspace(*(unsigned char *) self->p)) {
+                *s++ = *self->p++;
+            }
+            *s = 0;
+
+        }
+    } else {
+        self->p = p;
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t apr_json_decode_value(apr_json_scanner_t * self, apr_json_value_t ** retval)
+{
+    apr_json_value_t value;
+    apr_status_t status = APR_SUCCESS;
+
+    status = apr_json_decode_space(self, &value.pre);
+
+    if (status == APR_SUCCESS) {
+        switch (*(unsigned char *) self->p) {
+        case '"':
+            value.type = APR_JSON_STRING;
+            status = apr_json_decode_string(self, &value.value.string);
+            break;
+        case '[':
+            value.type = APR_JSON_ARRAY;
+            status = apr_json_decode_array(self, &value.value.array);
+            break;
+        case '{':
+            value.type = APR_JSON_OBJECT;
+            status = apr_json_decode_object(self, &value.value.object);
+            break;
+        case 'n':
+            value.type = APR_JSON_NULL;
+            status = apr_json_decode_null(self);
+            break;
+        case 't':
+        case 'f':
+            value.type = APR_JSON_BOOLEAN;
+            status = apr_json_decode_boolean(self, &value.value.boolean);
+            break;
+        case '-':
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            status = apr_json_decode_number(self, &value);
+            break;
+        default:
+            status = APR_BADCH;
+        }
+    }
+
+    if (status == APR_SUCCESS) {
+        status = apr_json_decode_space(self, &value.post);
+    }
+
+    if (status == APR_SUCCESS) {
+        *retval = apr_json_value_create(self->pool);
+        **retval = value;
+    }
+    return status;
+}
+
+apr_status_t apr_json_decode(apr_json_value_t ** retval, const char *injson,
+        apr_ssize_t injson_size, apr_off_t * offset, int flags, int level,
+        apr_pool_t * pool)
+{
+    apr_status_t status;
+    apr_json_scanner_t scanner;
+
+    scanner.p = injson;
+    scanner.e = injson
+            + (injson_size == APR_JSON_VALUE_STRING ? strlen(injson) : injson_size);
+    scanner.pool = pool;
+    scanner.flags = flags;
+    scanner.level = level;
+
+    if (APR_SUCCESS == (status = apr_json_decode_value(&scanner, retval))) {
+        if (scanner.p != scanner.e) {
+            /* trailing craft */
+            status = APR_BADCH;
+        }
+    }
+
+    if (offset) {
+        *offset = scanner.p - injson;
+    }
+
+    return status;
+}
+
+#else
+/* we do not yet support JSON on EBCDIC platforms, but will do in future */
+apr_status_t apr_json_decode(apr_json_value_t ** retval, const char *injson,
+        apr_size_t injson_size, apr_pool_t * pool)
+{
+    return APR_ENOTIMPL;
+}
+#endif

Added: apr/apr-util/branches/1.7.x/json/apr_json_encode.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/json/apr_json_encode.c?rev=1835350&view=auto
==============================================================================
--- apr/apr-util/branches/1.7.x/json/apr_json_encode.c (added)
+++ apr/apr-util/branches/1.7.x/json/apr_json_encode.c Sun Jul  8 11:42:12 2018
@@ -0,0 +1,300 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_json.h"
+
+#if !APR_CHARSET_EBCDIC
+
+typedef struct apr_json_serializer_t {
+    apr_pool_t *pool;
+    apr_bucket_brigade *brigade;
+    apr_brigade_flush flush;
+    void *ctx;
+    int flags;
+} apr_json_serializer_t;
+
+static apr_status_t apr_json_encode_value(apr_json_serializer_t * self,
+                                            const apr_json_value_t * value);
+
+static apr_status_t apr_json_brigade_write(apr_json_serializer_t * self,
+               const char *chunk, apr_size_t chunk_len, const char *escaped)
+{
+    apr_status_t status;
+
+    status = apr_brigade_write(self->brigade, self->flush, self->ctx, chunk, chunk_len);
+    if (APR_SUCCESS == status) {
+        status = apr_brigade_puts(self->brigade, self->flush, self->ctx, escaped);
+    }
+
+    return status;
+}
+
+static apr_status_t apr_json_brigade_printf(apr_json_serializer_t * self,
+               const char *chunk, apr_size_t chunk_len, const char *fmt, ...)
+{
+    va_list ap;
+    apr_status_t status;
+
+    status = apr_brigade_write(self->brigade, self->flush, self->ctx, chunk,
+            chunk_len);
+    if (APR_SUCCESS == status) {
+        va_start(ap, fmt);
+        status = apr_brigade_vprintf(self->brigade, self->flush, self->ctx, fmt,
+                ap);
+        va_end(ap);
+    }
+
+    return status;
+}
+
+static apr_status_t apr_json_encode_string(apr_json_serializer_t * self,
+        const apr_json_string_t * string)
+{
+    apr_status_t status;
+    const char *p, *e, *chunk;
+    const char invalid[4] = { 0xEF, 0xBF, 0xBD, 0x00 };
+    unsigned char c;
+
+    status = apr_brigade_putc(self->brigade, self->flush, self->ctx, '\"');
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    for (p = chunk = string->p, e = string->p + string->len; p < e; p++) {
+        switch (*p) {
+        case '\n':
+            status = apr_json_brigade_write(self, chunk, p - chunk, "\\n");
+            chunk = p + 1;
+            break;
+        case '\r':
+            status = apr_json_brigade_write(self, chunk, p - chunk, "\\r");
+            chunk = p + 1;
+            break;
+        case '\t':
+            status = apr_json_brigade_write(self, chunk, p - chunk, "\\t");
+            chunk = p + 1;
+            break;
+        case '\b':
+            status = apr_json_brigade_write(self, chunk, p - chunk, "\\b");
+            chunk = p + 1;
+            break;
+        case '\f':
+            status = apr_json_brigade_write(self, chunk, p - chunk, "\\f");
+            chunk = p + 1;
+            break;
+        case '\\':
+            status = apr_json_brigade_write(self, chunk, p - chunk, "\\\\");
+            chunk = p + 1;
+            break;
+        case '"':
+            status = apr_json_brigade_write(self, chunk, p - chunk, "\\\"");
+            chunk = p + 1;
+            break;
+        default:
+            c = (unsigned char)(*p);
+            apr_size_t left = e - p;
+            if (c < 0x20) {
+                status = apr_json_brigade_printf(self, chunk, p - chunk,
+                        "\\u%04x", c);
+                chunk = p + 1;
+            }
+            else if (((c >> 7) == 0x00)) {
+                /* 1 byte */
+            }
+            else if (left > 1 && ((c >> 5) == 0x06) && p[1]) {
+                /* 2 bytes */
+                if (left < 2 || (p[1] >> 6) != 0x02) {
+                    status = apr_json_brigade_write(self, chunk, p - chunk,
+                            invalid);
+                    chunk = p + 1;
+                }
+            }
+            else if (((c >> 4) == 0x0E)) {
+                /* 3 bytes */
+                if (left < 3 || (p[1] >> 6) != 0x02 || (p[2] >> 6) != 0x02) {
+                    status = apr_json_brigade_write(self, chunk, p - chunk,
+                            invalid);
+                    chunk = p + 1;
+                }
+            }
+            else if ((c >> 3) == 0x1E) {
+                /* 4 bytes */
+                if (left < 4 || (p[1] >> 6) != 0x02 || (p[2] >> 6) != 0x02 || (p[3] >> 6) != 0x02) {
+                    status = apr_json_brigade_write(self, chunk, p - chunk,
+                            invalid);
+                    chunk = p + 1;
+                }
+            }
+            else {
+                status = apr_json_brigade_write(self, chunk, p - chunk,
+                        invalid);
+                chunk = p + 1;
+            }
+            break;
+        }
+
+        if (APR_SUCCESS != status) {
+            return status;
+        }
+    }
+
+    if (chunk < p) {
+        status = apr_brigade_write(self->brigade, self->flush, self->ctx, chunk, p - chunk);
+        if (APR_SUCCESS != status) {
+            return status;
+        }
+    }
+
+    return apr_brigade_putc(self->brigade, self->flush, self->ctx, '\"');
+}
+
+
+static apr_status_t apr_json_encode_array(apr_json_serializer_t * self, apr_array_header_t * array)
+{
+    apr_status_t status;
+    apr_size_t i;
+
+    status = apr_brigade_putc(self->brigade, self->flush, self->ctx, '[');
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    for (i = 0; i < array->nelts; i++) {
+
+        if (i > 0) {
+            status = apr_brigade_putc(self->brigade, self->flush, self->ctx, ',');
+            if (APR_SUCCESS != status) {
+                return status;
+            }
+        }
+
+        status = apr_json_encode_value(self, ((apr_json_value_t **) array->elts)[i]);
+        if (APR_SUCCESS != status) {
+            return status;
+        }
+
+    }
+
+    return apr_brigade_putc(self->brigade, self->flush, self->ctx, ']');
+}
+
+static apr_status_t apr_json_encode_object(apr_json_serializer_t * self, apr_json_object_t * object)
+{
+    apr_status_t status;
+    apr_json_kv_t *kv;
+    int first = 1;
+    status = apr_brigade_putc(self->brigade, self->flush, self->ctx, '{');
+    if (APR_SUCCESS != status) {
+        return status;
+    }
+
+    for (kv = APR_RING_FIRST(&(object)->list);
+         kv != APR_RING_SENTINEL(&(object)->list, apr_json_kv_t, link);
+         kv = APR_RING_NEXT((kv), link)) {
+
+        if (!first) {
+            status = apr_brigade_putc(self->brigade, self->flush, self->ctx, ',');
+            if (APR_SUCCESS != status) {
+                return status;
+            }
+        }
+
+        {
+            status = apr_json_encode_value(self, kv->k);
+            if (APR_SUCCESS != status) {
+                return status;
+            }
+
+            status = apr_brigade_putc(self->brigade, self->flush, self->ctx, ':');
+            if (APR_SUCCESS != status) {
+                return status;
+            }
+
+            status = apr_json_encode_value(self, kv->v);
+            if (APR_SUCCESS != status) {
+                return status;
+            }
+        }
+        first = 0;
+    }
+    return apr_brigade_putc(self->brigade, self->flush, self->ctx, '}');
+}
+
+static apr_status_t apr_json_encode_value(apr_json_serializer_t * self, const apr_json_value_t * value)
+{
+    apr_status_t status = APR_SUCCESS;
+
+    if (value->pre && (self->flags & APR_JSON_FLAGS_WHITESPACE)) {
+        status = apr_brigade_puts(self->brigade, self->flush, self->ctx,
+                value->pre);
+    }
+
+    if (APR_SUCCESS == status) {
+        switch (value->type) {
+        case APR_JSON_STRING:
+            status = apr_json_encode_string(self, &value->value.string);
+            break;
+        case APR_JSON_LONG:
+            status = apr_brigade_printf(self->brigade, self->flush, self->ctx,
+                    "%" APR_INT64_T_FMT, value->value.lnumber);
+            break;
+        case APR_JSON_DOUBLE:
+            status = apr_brigade_printf(self->brigade, self->flush, self->ctx,
+                    "%lf", value->value.dnumber);
+            break;
+        case APR_JSON_BOOLEAN:
+            status = apr_brigade_puts(self->brigade, self->flush, self->ctx,
+                    value->value.boolean ? "true" : "false");
+            break;
+        case APR_JSON_NULL:
+            status = apr_brigade_puts(self->brigade, self->flush, self->ctx,
+                    "null");
+            break;
+        case APR_JSON_OBJECT:
+            status = apr_json_encode_object(self, value->value.object);
+            break;
+        case APR_JSON_ARRAY:
+            status = apr_json_encode_array(self, value->value.array);
+            break;
+        default:
+            return APR_EINVAL;
+        }
+    }
+
+    if (APR_SUCCESS == status && value->post
+            && (self->flags & APR_JSON_FLAGS_WHITESPACE)) {
+        status = apr_brigade_puts(self->brigade, self->flush, self->ctx,
+                value->post);
+    }
+
+    return status;
+}
+
+apr_status_t apr_json_encode(apr_bucket_brigade * brigade, apr_brigade_flush flush,
+                void *ctx, const apr_json_value_t * json, int flags, apr_pool_t * pool)
+{
+    apr_json_serializer_t serializer = {pool, brigade, flush, ctx, flags};
+    return apr_json_encode_value(&serializer, json);
+}
+
+#else
+ /* we do not yet support JSON on EBCDIC platforms, but will do in future */
+apr_status_t apr_json_encode(apr_bucket_brigade * brigade, apr_brigade_flush flush,
+                void *ctx, const apr_json_value_t * json, apr_pool_t * pool)
+{
+    return APR_ENOTIMPL;
+}
+#endif

Modified: apr/apr-util/branches/1.7.x/test/Makefile.in
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/test/Makefile.in?rev=1835350&r1=1835349&r2=1835350&view=diff
==============================================================================
--- apr/apr-util/branches/1.7.x/test/Makefile.in (original)
+++ apr/apr-util/branches/1.7.x/test/Makefile.in Sun Jul  8 11:42:12 2018
@@ -17,7 +17,8 @@ STDTEST_PORTABLE = dbd testall
 TESTS = teststrmatch.lo testuri.lo testuuid.lo testbuckets.lo testpass.lo \
 	testmd4.lo testmd5.lo testldap.lo testdate.lo testdbm.lo testdbd.lo \
 	testxml.lo testrmm.lo testreslist.lo testqueue.lo testxlate.lo \
-	testmemcache.lo testcrypto.lo testsiphash.lo testredis.lo
+	testmemcache.lo testcrypto.lo testsiphash.lo testredis.lo \
+	testjson.lo
 
 PROGRAMS = $(STDTEST_PORTABLE)
 

Modified: apr/apr-util/branches/1.7.x/test/abts_tests.h
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/test/abts_tests.h?rev=1835350&r1=1835349&r2=1835350&view=diff
==============================================================================
--- apr/apr-util/branches/1.7.x/test/abts_tests.h (original)
+++ apr/apr-util/branches/1.7.x/test/abts_tests.h Sun Jul  8 11:42:12 2018
@@ -42,7 +42,8 @@ const struct testlist {
     {testdbm},
     {testqueue},
     {testreslist},
-    {testsiphash}
+    {testsiphash},
+    {testjson}
 };
 
 #endif /* APR_TEST_INCLUDES */

Added: apr/apr-util/branches/1.7.x/test/testjson.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/test/testjson.c?rev=1835350&view=auto
==============================================================================
--- apr/apr-util/branches/1.7.x/test/testjson.c (added)
+++ apr/apr-util/branches/1.7.x/test/testjson.c Sun Jul  8 11:42:12 2018
@@ -0,0 +1,139 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_json.h"
+
+#include "abts.h"
+#include "testutil.h"
+
+static void test_json_identity(abts_case * tc, void *data)
+{
+    apr_json_value_t *json = NULL;
+    apr_json_kv_t *image, *width, *ids, *title,
+            *animated, *thumbnail, *height;
+    apr_bucket_alloc_t *ba;
+    apr_bucket_brigade *bb;
+    const char *src;
+    char buf[1024];
+    apr_size_t len = sizeof(buf);
+    apr_off_t offset = 0;
+
+    ba = apr_bucket_alloc_create(p);
+    bb = apr_brigade_create(p, ba);
+
+    src = "{"
+        "  \"Image\" : {"
+        "    \"Width\" : 800 ,"
+        "    \"IDs\" : [116, 943, 234, 38793],"
+        "    \"Title\" : \"View from 15th Floor\","
+        "    \"Animated\" : false,"
+        "    \"Thumbnail\" : {"
+        "      \"Height\" : 125,"
+        "      \"Width\" : 100,"
+        "      \"Url\" : \"http://www.example.com/image/481989943\""
+        "    },"
+        "    \"Height\" : 600 "
+        "  }"
+        "}";
+
+    apr_json_decode(&json, src, APR_JSON_VALUE_STRING, &offset, APR_JSON_FLAGS_WHITESPACE,
+            10, p);
+    apr_json_encode(bb, NULL, NULL, json, APR_JSON_FLAGS_WHITESPACE, p);
+    apr_brigade_flatten(bb, buf, &len);
+    apr_json_decode(&json, buf, len, &offset, APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+    ABTS_STR_NEQUAL(tc, src, buf, len);
+
+    ABTS_INT_EQUAL(tc, len, offset);
+    ABTS_INT_EQUAL(tc, APR_JSON_OBJECT, json->type);
+    image = apr_hash_get(json->value.object->hash, "Image", 5);
+    ABTS_PTR_NOTNULL(tc, image);
+    width = apr_hash_get(image->v->value.object->hash, "Width", 5);
+    ABTS_PTR_NOTNULL(tc, width);
+    ABTS_INT_EQUAL(tc, APR_JSON_LONG, width->v->type);
+    ABTS_INT_EQUAL(tc, 800, width->v->value.lnumber);
+    ids = apr_hash_get(image->v->value.object->hash, "IDs", 3);
+    ABTS_PTR_NOTNULL(tc, ids);
+    ABTS_INT_EQUAL(tc, APR_JSON_ARRAY, ids->v->type);
+    title = apr_hash_get(image->v->value.object->hash, "Title", 5);
+    ABTS_PTR_NOTNULL(tc, title);
+    ABTS_INT_EQUAL(tc, APR_JSON_STRING, title->v->type);
+    animated = apr_hash_get(image->v->value.object->hash, "Animated", 8);
+    ABTS_PTR_NOTNULL(tc, animated);
+    ABTS_INT_EQUAL(tc, APR_JSON_BOOLEAN, animated->v->type);
+    ABTS_TRUE(tc, !animated->v->value.boolean);
+    thumbnail = apr_hash_get(image->v->value.object->hash, "Thumbnail", 9);
+    ABTS_PTR_NOTNULL(tc, thumbnail);
+    ABTS_INT_EQUAL(tc, APR_JSON_OBJECT, thumbnail->v->type);
+    height = apr_hash_get(image->v->value.object->hash, "Height", 6);
+    ABTS_PTR_NOTNULL(tc, height);
+    ABTS_INT_EQUAL(tc, APR_JSON_LONG, height->v->type);
+    ABTS_INT_EQUAL(tc, 600, height->v->value.lnumber);
+
+}
+
+static void test_json_level(abts_case * tc, void *data)
+{
+    apr_json_value_t *json = NULL;
+    apr_status_t status;
+    const char *src;
+    apr_off_t offset = 0;
+
+    src = "{"
+        "\"One\":{"
+        "\"Two\":{"
+        "\"Three\":{";
+
+    status = apr_json_decode(&json, src, APR_JSON_VALUE_STRING, &offset,
+            APR_JSON_FLAGS_WHITESPACE, 2, p);
+
+    ABTS_INT_EQUAL(tc, APR_EINVAL, status);
+
+}
+
+static void test_json_eof(abts_case * tc, void *data)
+{
+    apr_json_value_t *json = NULL;
+    apr_status_t status;
+    const char *src;
+    apr_off_t offset = 0;
+
+    src = "{"
+        "\"One\":{"
+        "\"Two\":{"
+        "\"Three\":{";
+
+    status = apr_json_decode(&json, src, APR_JSON_VALUE_STRING, &offset,
+            APR_JSON_FLAGS_WHITESPACE, 10, p);
+
+    ABTS_INT_EQUAL(tc, APR_EOF, status);
+
+}
+
+abts_suite *testjson(abts_suite * suite)
+{
+    suite = ADD_SUITE(suite);
+
+    abts_run_test(suite, test_json_identity, NULL);
+    abts_run_test(suite, test_json_level, NULL);
+    abts_run_test(suite, test_json_eof, NULL);
+
+    return suite;
+}

Modified: apr/apr-util/branches/1.7.x/test/testutil.h
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.7.x/test/testutil.h?rev=1835350&r1=1835349&r2=1835350&view=diff
==============================================================================
--- apr/apr-util/branches/1.7.x/test/testutil.h (original)
+++ apr/apr-util/branches/1.7.x/test/testutil.h Sun Jul  8 11:42:12 2018
@@ -69,5 +69,6 @@ abts_suite *testxlate(abts_suite *suite)
 abts_suite *testrmm(abts_suite *suite);
 abts_suite *testdbm(abts_suite *suite);
 abts_suite *testsiphash(abts_suite *suite);
+abts_suite *testjson(abts_suite *suite);
 
 #endif /* APR_TEST_INCLUDES */



Mime
View raw message