Beispiel #1
0
static void test_show_object_compound_compact(void)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "first", "one");
    {
        JsonElement *inner = JsonObjectCreate(10);

        JsonObjectAppendString(inner, "third", "three");

        JsonObjectAppendObject(json, "second", inner);
    }
    {
        JsonElement *inner = JsonObjectCreate(10);

        JsonObjectAppendString(inner, "fifth", "five");

        JsonObjectAppendObject(json, "fourth", inner);
    }

    Writer *writer = StringWriter();

    JsonWriteCompact(writer, json);
    char *output = StringWriterClose(writer);

    assert_string_equal("{\"first\":\"one\",\"second\":{\"third\":\"three\"},\"fourth\":{\"fifth\":\"five\"}}", output);

    JsonDestroy(json);
    free(output);
}
Beispiel #2
0
static JsonElement *FnCallToJson(const FnCall *fp)
{
    assert(fp);

    JsonElement *object = JsonObjectCreate(3);

    JsonObjectAppendString(object, "name", fp->name);
    JsonObjectAppendString(object, "type", "function-call");

    JsonElement *argsArray = JsonArrayCreate(5);

    for (Rlist *rp = fp->args; rp != NULL; rp = rp->next)
    {
        switch (rp->val.type)
        {
        case RVAL_TYPE_SCALAR:
            JsonArrayAppendString(argsArray, RlistScalarValue(rp));
            break;

        case RVAL_TYPE_FNCALL:
            JsonArrayAppendObject(argsArray, FnCallToJson(RlistFnCallValue(rp)));
            break;

        default:
            assert(false && "Unknown argument type");
            break;
        }
    }
    JsonObjectAppendArray(object, "arguments", argsArray);

    return object;
}
Beispiel #3
0
static JsonElement *ExportAttributeValueAsJson(Rval rval)
{
    JsonElement *json_attribute = JsonObjectCreate(10);

    switch (rval.rtype)
    {
    case CF_SCALAR:
    {
        char buffer[CF_BUFSIZE];

        EscapeQuotes((const char *) rval.item, buffer, sizeof(buffer));

        JsonObjectAppendString(json_attribute, "type", "string");
        JsonObjectAppendString(json_attribute, "value", buffer);
    }
        return json_attribute;

    case CF_LIST:
    {
        Rlist *rp = NULL;
        JsonElement *list = JsonArrayCreate(10);

        JsonObjectAppendString(json_attribute, "type", "list");

        for (rp = (Rlist *) rval.item; rp != NULL; rp = rp->next)
        {
            JsonArrayAppendObject(list, ExportAttributeValueAsJson((Rval) {rp->item, rp->type}));
        }

        JsonObjectAppendArray(json_attribute, "value", list);
        return json_attribute;
    }

    case CF_FNCALL:
    {
        Rlist *argp = NULL;
        FnCall *call = (FnCall *) rval.item;

        JsonObjectAppendString(json_attribute, "type", "function-call");
        JsonObjectAppendString(json_attribute, "name", call->name);

        {
            JsonElement *arguments = JsonArrayCreate(10);

            for (argp = call->args; argp != NULL; argp = argp->next)
            {
                JsonArrayAppendObject(arguments, ExportAttributeValueAsJson((Rval) {argp->item, argp->type}));
            }

            JsonObjectAppendArray(json_attribute, "arguments", arguments);
        }

        return json_attribute;
    }

    default:
        FatalError("Attempted to export attribute of type: %c", rval.rtype);
        return NULL;
    }
}
Beispiel #4
0
static void test_object_iterator(void **state)
{
    JsonElement *obj = JsonObjectCreate(10);

    JsonObjectAppendString(obj, "first", "one");
    JsonObjectAppendString(obj, "second", "two");
    JsonObjectAppendInteger(obj, "third", 3);
    JsonObjectAppendBool(obj, "fourth", true);
    JsonObjectAppendBool(obj, "fifth", false);


    {
        JsonIterator it = JsonIteratorInit(obj);

        assert_string_equal("first", JsonIteratorNextKey(&it));
        assert_string_equal("second", JsonIteratorNextKey(&it));
        assert_string_equal("third", JsonIteratorNextKey(&it));
        assert_string_equal("fourth", JsonIteratorNextKey(&it));
        assert_string_equal("fifth", JsonIteratorNextKey(&it));
        assert_false(JsonIteratorNextKey(&it));
    }

    {
        JsonIterator it = JsonIteratorInit(obj);

        assert_string_equal("one", JsonPrimitiveGetAsString(JsonIteratorNextValue(&it)));
        assert_string_equal("two", JsonPrimitiveGetAsString(JsonIteratorNextValue(&it)));
        assert_int_equal(3, JsonPrimitiveGetAsInteger(JsonIteratorNextValue(&it)));
        assert_true(JsonPrimitiveGetAsBool(JsonIteratorNextValue(&it)));
        assert_false(JsonPrimitiveGetAsBool(JsonIteratorNextValue(&it)));
        assert_false(JsonIteratorNextValue(&it));
    }

    JsonElementDestroy(obj);
}
Beispiel #5
0
static JsonElement *ExportBodyAsJson(Body *body)
{
    JsonElement *json_body = JsonObjectCreate(10);

    JsonObjectAppendInteger(json_body, "offset", body->offset.start);
    JsonObjectAppendInteger(json_body, "offset-end", body->offset.end);

    JsonObjectAppendString(json_body, "name", body->name);
    JsonObjectAppendString(json_body, "body-type", body->type);

    {
        JsonElement *json_args = JsonArrayCreate(10);
        Rlist *argp = NULL;

        for (argp = body->args; argp != NULL; argp = argp->next)
        {
            JsonArrayAppendString(json_args, argp->item);
        }

        JsonObjectAppendArray(json_body, "arguments", json_args);
    }

    JsonObjectAppendArray(json_body, "classes", ExportBodyClassesAsJson(body->conlist));

    return json_body;
}
Beispiel #6
0
static void test_show_object_compound(void)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "first", "one");
    {
        JsonElement *inner = JsonObjectCreate(10);

        JsonObjectAppendString(inner, "third", "three");

        JsonObjectAppendObject(json, "second", inner);
    }
    {
        JsonElement *inner = JsonObjectCreate(10);

        JsonObjectAppendString(inner, "fifth", "five");

        JsonObjectAppendObject(json, "fourth", inner);
    }

    Writer *writer = StringWriter();

    JsonWrite(writer, json, 0);
    char *output = StringWriterClose(writer);

    assert_string_equal(OBJECT_COMPOUND, output);

    JsonDestroy(json);
    free(output);
}
Beispiel #7
0
static JsonElement *FnCallTypeToJson(const FnCallType *fn_syntax)
{
 JsonElement *json_fn = JsonObjectCreate(10);

 JsonObjectAppendString(json_fn, "status", SyntaxStatusToString(fn_syntax->status));
 JsonObjectAppendString(json_fn, "returnType", DataTypeToString(fn_syntax->dtype));

 {
 JsonElement *params = JsonArrayCreate(10);
 for (int i = 0; fn_syntax->args[i].pattern; i++)
    {
    const FnCallArg *param = &fn_syntax->args[i];

    JsonElement *json_param = JsonObjectCreate(2);
    JsonObjectAppendString(json_param, "type", DataTypeToString(param->dtype));
    JsonObjectAppendString(json_param, "range", param->pattern);
    JsonArrayAppendObject(params, json_param);
    }
 JsonObjectAppendArray(json_fn, "parameters", params);
 }

 JsonObjectAppendBool(json_fn, "variadic", fn_syntax->options & FNCALL_OPTION_VARARG);
 JsonObjectAppendBool(json_fn, "cached", fn_syntax->options & FNCALL_OPTION_CACHED);
 JsonObjectAppendString(json_fn, "category", FnCallCategoryToString(fn_syntax->category));

 return json_fn;
}
Beispiel #8
0
static void test_show_object_compound(void **state)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "first", "one");
    {
        JsonElement *inner = JsonObjectCreate(10);

        JsonObjectAppendString(inner, "third", "three");

        JsonObjectAppendObject(json, "second", inner);
    }
    {
        JsonElement *inner = JsonObjectCreate(10);

        JsonObjectAppendString(inner, "fifth", "five");

        JsonObjectAppendObject(json, "fourth", inner);
    }

    Writer *writer = StringWriter();

    JsonElementPrint(writer, json, 0);

    assert_string_equal(OBJECT_COMPOUND, StringWriterData(writer));

    JsonElementDestroy(json);
}
Beispiel #9
0
static JsonElement *ExportAttributesSyntaxAsJson(const ConstraintSyntax attributes[])
{
    JsonElement *json = JsonObjectCreate(10);
    int i = 0;

    if (attributes == NULL)
    {
        return json;
    }

    for (i = 0; attributes[i].lval != NULL; i++)
    {
        if (attributes[i].range.validation_string == CF_BUNDLE)
        {
            /* TODO: must handle edit_line somehow */
            continue;
        }
        else if (attributes[i].dtype == DATA_TYPE_BODY)
        {
            JsonElement *json_attributes = ExportAttributesSyntaxAsJson(attributes[i].range.body_type_syntax->constraints);

            JsonObjectAppendObject(json, attributes[i].lval, json_attributes);
        }
        else
        {
            JsonElement *attribute = JsonObjectCreate(10);

            JsonObjectAppendString(attribute, "datatype", CF_DATATYPES[attributes[i].dtype]);

            if (strlen(attributes[i].range.validation_string) == 0)
            {
                JsonObjectAppendString(attribute, "pcre-range", ".*");
            }
            else if (attributes[i].dtype == DATA_TYPE_OPTION || attributes[i].dtype == DATA_TYPE_OPTION_LIST)
            {
                JsonElement *options = JsonArrayCreate(10);
                char options_buffer[CF_BUFSIZE];
                char *option = NULL;

                strcpy(options_buffer, attributes[i].range.validation_string);
                for (option = strtok(options_buffer, ","); option != NULL; option = strtok(NULL, ","))
                {
                    JsonArrayAppendString(options, option);
                }

                JsonObjectAppendArray(attribute, "pcre-range", options);
            }
            else
            {
                char *pcre_range = PCREStringToJsonString(attributes[i].range.validation_string);

                JsonObjectAppendString(attribute, "pcre-range", pcre_range);
            }

            JsonObjectAppendObject(json, attributes[i].lval, attribute);
        }
    }

    return json;
}
Beispiel #10
0
JsonElement *FnCallToJson(FnCall *fp)
{
    assert(fp);

    JsonElement *object = JsonObjectCreate(3);

    JsonObjectAppendString(object, "name", fp->name);
    JsonObjectAppendString(object, "type", "function-call");

    JsonElement *argsArray = JsonArrayCreate(fp->argc);

    for (Rlist *rp = fp->args; rp != NULL; rp = rp->next)
    {
        switch (rp->type)
        {
        case CF_SCALAR:
            JsonArrayAppendString(argsArray, (const char *) rp->item);
            break;

        case CF_FNCALL:
            JsonArrayAppendObject(argsArray, FnCallToJson((FnCall *) rp->item));
            break;

        default:
            assert(false && "Unknown argument type");
            break;
        }
    }
    JsonObjectAppendArray(object, "arguments", argsArray);

    return object;
}
Beispiel #11
0
static JsonElement *ExportBundleClassesAsJson(Promise *promises)
{
    JsonElement *json_contexts = JsonArrayCreate(10);
    JsonElement *json_promises = JsonArrayCreate(10);
    char *current_context = "any";
    size_t context_offset_start = -1;
    size_t context_offset_end = -1;
    Promise *pp = NULL;

    for (pp = promises; pp != NULL; pp = pp->next)
    {
        JsonElement *json_promise = JsonObjectCreate(10);

        JsonObjectAppendInteger(json_promise, "offset", pp->offset.start);

        {
            JsonElement *json_promise_attributes = JsonArrayCreate(10);
            Constraint *cp = NULL;

            for (cp = pp->conlist; cp != NULL; cp = cp->next)
            {
                JsonElement *json_attribute = JsonObjectCreate(10);

                JsonObjectAppendInteger(json_attribute, "offset", cp->offset.start);
                JsonObjectAppendInteger(json_attribute, "offset-end", cp->offset.end);

                context_offset_end = cp->offset.end;

                JsonObjectAppendString(json_attribute, "lval", cp->lval);
                JsonObjectAppendObject(json_attribute, "rval", ExportAttributeValueAsJson(cp->rval));
                JsonArrayAppendObject(json_promise_attributes, json_attribute);
            }

            JsonObjectAppendInteger(json_promise, "offset-end", context_offset_end);

            JsonObjectAppendString(json_promise, "promiser", pp->promiser);
            /* FIXME: does not work for lists */
            if (pp->promisee.rtype == CF_SCALAR || pp->promisee.rtype == CF_NOPROMISEE)
            {
                JsonObjectAppendString(json_promise, "promisee", pp->promisee.item);
            }

            JsonObjectAppendArray(json_promise, "attributes", json_promise_attributes);
        }
        JsonArrayAppendObject(json_promises, json_promise);

        if (pp->next == NULL || strcmp(current_context, pp->next->classes) != 0)
        {
            JsonArrayAppendObject(json_contexts,
                                  CreateContextAsJson(current_context,
                                                      context_offset_start,
                                                      context_offset_end, "promises", json_promises));

            current_context = pp->classes;
        }
    }

    return json_contexts;
}
Beispiel #12
0
static void test_object_duplicate_key(void)
{
    JsonElement *a = JsonObjectCreate(1);

    JsonObjectAppendString(a, "a", "a");
    JsonObjectAppendString(a, "a", "a");

    assert_int_equal(1, JsonLength(a));

    JsonDestroy(a);
}
Beispiel #13
0
static void test_object_get_string(void)
{
    JsonElement *obj = JsonObjectCreate(10);

    JsonObjectAppendString(obj, "first", "one");
    JsonObjectAppendString(obj, "second", "two");

    assert_string_equal(JsonObjectGetAsString(obj, "second"), "two");
    assert_string_equal(JsonObjectGetAsString(obj, "first"), "one");

    JsonDestroy(obj);
}
Beispiel #14
0
static void test_show_object_simple(void **state)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "first", "one");
    JsonObjectAppendString(json, "second", "two");

    Writer *writer = StringWriter();

    JsonElementPrint(writer, json, 0);

    assert_string_equal(OBJECT_SIMPLE, StringWriterData(writer));

    JsonElementDestroy(json);
}
Beispiel #15
0
static JsonElement *ConstraintSyntaxToJson(const ConstraintSyntax *constraint_syntax)
{
 JsonElement *json_constraint = JsonObjectCreate(5);

 JsonObjectAppendString(json_constraint, "attribute", constraint_syntax->lval);
 JsonObjectAppendString(json_constraint, "status", SyntaxStatusToString(constraint_syntax->status));
 JsonObjectAppendString(json_constraint, "type", DataTypeToString(constraint_syntax->dtype));

 if (constraint_syntax->dtype != CF_DATA_TYPE_BODY && constraint_syntax->dtype != CF_DATA_TYPE_BUNDLE)
    {
    JsonObjectAppendString(json_constraint, "range", constraint_syntax->range.validation_string);
    }

 return json_constraint;
}
Beispiel #16
0
static void test_new_delete(void)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "first", "one");
    JsonDestroy(json);
}
Beispiel #17
0
/**
 * @brief Writes a file with a contained release ID based on git SHA,
 *        or file checksum if git SHA is not available.
 * @param filename the release_id file
 * @param dirname the directory to checksum or get the Git hash
 * @return True if successful
 */
static bool WriteReleaseIdFile(const char *filename, const char *dirname)
{
    char release_id[GENERIC_AGENT_CHECKSUM_SIZE];

    bool have_release_id =
        GeneratePolicyReleaseID(release_id, sizeof(release_id), dirname);

    if (!have_release_id)
    {
        return false;
    }

    int fd = creat(filename, 0600);
    if (fd == -1)
    {
        Log(LOG_LEVEL_ERR, "While writing policy release ID file '%s', could not create file (creat: %s)", filename, GetErrorStr());
        return false;
    }

    JsonElement *info = JsonObjectCreate(3);
    JsonObjectAppendString(info, "releaseId", release_id);

    Writer *w = FileWriter(fdopen(fd, "w"));
    JsonWrite(w, info, 0);

    WriterClose(w);
    JsonDestroy(info);

    Log(LOG_LEVEL_VERBOSE, "Saved policy release ID file '%s'", filename);
    return true;
}
Beispiel #18
0
void PolicyPrintAsJson(Writer *writer, const char *filename, Bundle *bundles, Body *bodies)
{
    JsonElement *json_policy = JsonObjectCreate(10);

    JsonObjectAppendString(json_policy, "name", filename);

    {
        JsonElement *json_bundles = JsonArrayCreate(10);
        Bundle *bp = NULL;

        for (bp = bundles; bp != NULL; bp = bp->next)
        {
            JsonArrayAppendObject(json_bundles, ExportBundleAsJson(bp));
        }

        JsonObjectAppendArray(json_policy, "bundles", json_bundles);
    }

    {
        JsonElement *json_bodies = JsonArrayCreate(10);
        Body *bdp = NULL;

        for (bdp = bodies; bdp != NULL; bdp = bdp->next)
        {
            JsonArrayAppendObject(json_bodies, ExportBodyAsJson(bdp));
        }

        JsonObjectAppendArray(json_policy, "bodies", json_bodies);
    }

    JsonElementPrint(writer, json_policy, 0);
    JsonElementDestroy(json_policy);
}
Beispiel #19
0
static void test_show_object_simple(void)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "first", "one");
    JsonObjectAppendString(json, "second", "two");

    Writer *writer = StringWriter();

    JsonWrite(writer, json, 0);
    char *output = StringWriterClose(writer);

    assert_string_equal(OBJECT_SIMPLE, output);

    JsonDestroy(json);
    free(output);
}
Beispiel #20
0
static JsonElement *JsonBundleTypeNew(void)
{
 JsonElement *json_bundle_type = JsonObjectCreate(2);

 JsonObjectAppendString(json_bundle_type, "status", SyntaxStatusToString(SYNTAX_STATUS_NORMAL));
 JsonObjectAppendArray(json_bundle_type, "promiseTypes", JsonArrayCreate(50));

 return json_bundle_type;
}
Beispiel #21
0
static JsonElement *JsonPromiseTypeNew(SyntaxStatus status)
{
 JsonElement *promise_type = JsonObjectCreate(2);

 JsonObjectAppendString(promise_type, "status", SyntaxStatusToString(status));
 JsonObjectAppendObject(promise_type, "attributes", JsonObjectCreate(50));

 return promise_type;
}
Beispiel #22
0
static JsonElement *ExportBundleAsJson(Bundle *bundle)
{
    JsonElement *json_bundle = JsonObjectCreate(10);

    JsonObjectAppendInteger(json_bundle, "offset", bundle->offset.start);
    JsonObjectAppendInteger(json_bundle, "offset-end", bundle->offset.end);

    JsonObjectAppendString(json_bundle, "name", bundle->name);
    JsonObjectAppendString(json_bundle, "bundle-type", bundle->type);

    {
        JsonElement *json_args = JsonArrayCreate(10);
        Rlist *argp = NULL;

        for (argp = bundle->args; argp != NULL; argp = argp->next)
        {
            JsonArrayAppendString(json_args, argp->item);
        }

        JsonObjectAppendArray(json_bundle, "arguments", json_args);
    }

    {
        JsonElement *json_promise_types = JsonArrayCreate(10);
        SubType *sp = NULL;

        for (sp = bundle->subtypes; sp != NULL; sp = sp->next)
        {
            JsonElement *json_promise_type = JsonObjectCreate(10);

            JsonObjectAppendInteger(json_promise_type, "offset", sp->offset.start);
            JsonObjectAppendInteger(json_promise_type, "offset-end", sp->offset.end);
            JsonObjectAppendString(json_promise_type, "name", sp->name);
            JsonObjectAppendArray(json_promise_type, "classes", ExportBundleClassesAsJson(sp->promiselist));

            JsonArrayAppendObject(json_promise_types, json_promise_type);
        }

        JsonObjectAppendArray(json_bundle, "promise-types", json_promise_types);
    }

    return json_bundle;
}
Beispiel #23
0
static JsonElement *CreateContextAsJson(const char *name, size_t offset,
                                        size_t offset_end, const char *children_name, JsonElement *children)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "name", name);
    JsonObjectAppendInteger(json, "offset", offset);
    JsonObjectAppendInteger(json, "offset-end", offset_end);
    JsonObjectAppendArray(json, children_name, children);

    return json;
}
Beispiel #24
0
static void test_show_object_escaped(void **state)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "escaped", "quote\"stuff \t \n\n");

    Writer *writer = StringWriter();

    JsonElementPrint(writer, json, 0);

    assert_string_equal(OBJECT_ESCAPED, StringWriterData(writer));

    JsonElementDestroy(json);
}
Beispiel #25
0
static JsonElement *BodySyntaxToJson(const BodySyntax *body_syntax)
{
 JsonElement *json_body = JsonObjectCreate(2);

 JsonObjectAppendString(json_body, "status", SyntaxStatusToString(body_syntax->status));
 {
 JsonElement *attributes = JsonObjectCreate(50);

 for (int i = 0; body_syntax->constraints[i].lval; i++)
    {
    const ConstraintSyntax *constraint_syntax = &body_syntax->constraints[i];
    if (constraint_syntax->status != SYNTAX_STATUS_REMOVED)
       {
       JsonElement *json_constraint = ConstraintSyntaxToJson(constraint_syntax);
       JsonObjectAppendString(json_constraint, "visibility", "body");
       JsonObjectAppendObject(attributes, constraint_syntax->lval, json_constraint);
       }
    }

 JsonObjectAppendObject(json_body, "attributes", attributes);
 }

 return json_body;
}
Beispiel #26
0
static void test_merge_object(void)
{
    JsonElement *a = JsonObjectCreate(2);
    JsonObjectAppendString(a, "a", "a");
    JsonObjectAppendString(a, "b", "b");

    JsonElement *b = JsonObjectCreate(2);
    JsonObjectAppendString(b, "b", "b");
    JsonObjectAppendString(b, "c", "c");

    JsonElement *c = JsonMerge(a, b);

    assert_int_equal(2, JsonLength(a));
    assert_int_equal(2, JsonLength(b));
    assert_int_equal(3, JsonLength(c));

    assert_string_equal("a", JsonObjectGetAsString(c, "a"));
    assert_string_equal("b", JsonObjectGetAsString(c, "b"));
    assert_string_equal("c", JsonObjectGetAsString(c, "c"));

    JsonDestroy(a);
    JsonDestroy(b);
    JsonDestroy(c);
}
Beispiel #27
0
static void test_show_object_escaped(void)
{
    JsonElement *json = JsonObjectCreate(10);

    JsonObjectAppendString(json, "escaped", "quote\"stuff \t \n\n");

    Writer *writer = StringWriter();

    JsonWrite(writer, json, 0);
    char *output = StringWriterClose(writer);

    assert_string_equal(OBJECT_ESCAPED, output);

    JsonDestroy(json);
    free(output);
}
Beispiel #28
0
static void test_show_array_object(void **state)
{
    JsonElement *array = JsonArrayCreate(10);
    JsonElement *object = JsonObjectCreate(10);

    JsonObjectAppendString(object, "first", "one");

    JsonArrayAppendObject(array, object);

    Writer *writer = StringWriter();

    JsonElementPrint(writer, array, 0);

    assert_string_equal(ARRAY_OBJECT, StringWriterData(writer));

    JsonElementDestroy(array);
}
Beispiel #29
0
static void test_show_array_object(void)
{
    JsonElement *array = JsonArrayCreate(10);
    JsonElement *object = JsonObjectCreate(10);

    JsonObjectAppendString(object, "first", "one");

    JsonArrayAppendObject(array, object);

    Writer *writer = StringWriter();

    JsonWrite(writer, array, 0);
    char *output = StringWriterClose(writer);

    assert_string_equal(ARRAY_OBJECT, output);

    JsonDestroy(array);
    free(output);
}
Beispiel #30
0
static JsonElement *ExportBodyClassesAsJson(Constraint *constraints)
{
    JsonElement *json_contexts = JsonArrayCreate(10);
    JsonElement *json_attributes = JsonArrayCreate(10);
    char *current_context = "any";
    size_t context_offset_start = -1;
    size_t context_offset_end = -1;
    Constraint *cp = NULL;

    for (cp = constraints; cp != NULL; cp = cp->next)
    {
        JsonElement *json_attribute = JsonObjectCreate(10);

        JsonObjectAppendInteger(json_attribute, "offset", cp->offset.start);
        JsonObjectAppendInteger(json_attribute, "offset-end", cp->offset.end);

        context_offset_start = cp->offset.context;
        context_offset_end = cp->offset.end;

        JsonObjectAppendString(json_attribute, "lval", cp->lval);
        JsonObjectAppendObject(json_attribute, "rval", ExportAttributeValueAsJson(cp->rval));
        JsonArrayAppendObject(json_attributes, json_attribute);

        if (cp->next == NULL || strcmp(current_context, cp->next->classes) != 0)
        {
            JsonArrayAppendObject(json_contexts,
                                  CreateContextAsJson(current_context,
                                                      context_offset_start,
                                                      context_offset_end, "attributes", json_attributes));

            current_context = cp->classes;
        }
    }

    return json_contexts;
}