15670430创建于 2020年12月28日历史提交
/*-------------------------------------------------------------------------
 *
 * json.c: - make json document.
 *
 * Copyright (c) 2018-2019, Postgres Professional
 *
 *-------------------------------------------------------------------------
 */

#include "json.h"

static void json_add_indent(PQExpBuffer buf, int32 level);
static void json_add_escaped(PQExpBuffer buf, const char *str);

static bool add_comma = false;

/*
 * Start or end json token. Currently it is a json object or array.
 *
 * Function modifies level value and adds indent if it appropriate.
 */
void
json_add(PQExpBuffer buf, JsonToken type, int32 *level)
{
    switch (type)
    {
        case JT_BEGIN_ARRAY:
            appendPQExpBufferChar(buf, '[');
            *level += 1;
            add_comma = false;
            break;
        case JT_END_ARRAY:
            *level -= 1;
            if (*level == 0)
                appendPQExpBufferChar(buf, '\n');
            else
                json_add_indent(buf, *level);
            appendPQExpBufferChar(buf, ']');
            add_comma = true;
            break;
        case JT_BEGIN_OBJECT:
            json_add_indent(buf, *level);
            appendPQExpBufferChar(buf, '{');
            *level += 1;
            add_comma = false;
            break;
        case JT_END_OBJECT:
            *level -= 1;
            if (*level == 0)
                appendPQExpBufferChar(buf, '\n');
            else
                json_add_indent(buf, *level);
            appendPQExpBufferChar(buf, '}');
            add_comma = true;
            break;
        default:
            break;
    }
}

/*
 * Add json object's key. If it isn't first key we need to add a comma.
 */
void
json_add_key(PQExpBuffer buf, const char *name, int32 level)
{
    if (add_comma)
        appendPQExpBufferChar(buf, ',');
    json_add_indent(buf, level);

    json_add_escaped(buf, name);
    appendPQExpBufferStr(buf, ": ");

    add_comma = true;
}

/*
 * Add json object's key and value. If it isn't first key we need to add a
 * comma.
 */
void
json_add_value(PQExpBuffer buf, const char *name, const char *value,
                                int32 level, bool escaped)
{
    json_add_key(buf, name, level);

    if (escaped)
        json_add_escaped(buf, value);
    else
        appendPQExpBufferStr(buf, value);
}

static void
json_add_indent(PQExpBuffer buf, int32 level)
{
    uint16  i;

    if (level == 0)
        return;

    appendPQExpBufferChar(buf, '\n');
    for (i = 0; i < level; i++)
        appendPQExpBufferStr(buf, "    ");
}

static void
json_add_escaped(PQExpBuffer buf, const char *str)
{
    const char *p;

    appendPQExpBufferChar(buf, '"');
    for (p = str; *p; p++)
    {
        switch (*p)
        {
            case '\b':
                appendPQExpBufferStr(buf, "\\b");
                break;
            case '\f':
                appendPQExpBufferStr(buf, "\\f");
                break;
            case '\n':
                appendPQExpBufferStr(buf, "\\n");
                break;
            case '\r':
                appendPQExpBufferStr(buf, "\\r");
                break;
            case '\t':
                appendPQExpBufferStr(buf, "\\t");
                break;
            case '"':
                appendPQExpBufferStr(buf, "\\\"");
                break;
            case '\\':
                appendPQExpBufferStr(buf, "\\\\");
                break;
            default:
                if ((unsigned char) *p < ' ')
                    appendPQExpBuffer(buf, "\\u%04x", (int) *p);
                else
                    appendPQExpBufferChar(buf, *p);
                break;
        }
    }
    appendPQExpBufferChar(buf, '"');
}