/* autogenerated file */
# ifndef _GNU_SOURCE
#  define _GNU_SOURCE
# endif
#include <string.h>
#include <read-file.h>
#include "oci_image_spec.h"

void free_oci_image_config_labels (oci_image_config_labels *ptr) {
    if (!ptr)
        return;
    free_cells (ptr);
    ptr = NULL;
    free (ptr);
}

oci_image_config *make_oci_image_config (yajl_val tree, struct parser_context *ctx, parser_error *err) {
    oci_image_config *ret = NULL;
    *err = 0;
    (void) ctx;  /* Silence compiler warning.  */
    if (tree == NULL)
        return ret;
    ret = safe_malloc (sizeof (*ret));
    {
        yajl_val val = get_val (tree, "User", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->user = strdup (str ? str : "");
            if (ret->user == NULL)
                abort ();
        }
    }
    {
        yajl_val tmp = get_val (tree, "ExposedPorts", yajl_t_object);
        if (tmp && YAJL_GET_OBJECT (tmp)) {
            size_t i;
            const char **keys = YAJL_GET_OBJECT (tmp)->keys;
            size_t len = YAJL_GET_OBJECT (tmp)->len;
            ret->exposed_ports_len = len;
            ret->exposed_ports = safe_malloc ((len + 1) * sizeof (*ret->exposed_ports));
            for (i = 0; i < len; i++) {
                const char *key = keys[i];
                if (key) {
                     ret->exposed_ports[i] = strdup (key) ? : "";
                     if (ret->exposed_ports[i] == NULL)
                         abort ();                }
            }
        }
        else
        {
            ret->exposed_ports_len = 0;
        }
    }
    {
        yajl_val tmp = get_val (tree, "Env", yajl_t_array);
        if (tmp && YAJL_GET_ARRAY (tmp)) {
            size_t i;
            yajl_val *values = YAJL_GET_ARRAY (tmp)->values;
            size_t len = YAJL_GET_ARRAY (tmp)->len;
            ret->env_len = len;
            ret->env = safe_malloc ((len + 1) * sizeof (*ret->env));
            for (i = 0; i < len; i++) {
                yajl_val val = values[i];
                if (val) {
                    char *str = YAJL_GET_STRING (val);
                    ret->env[i] = strdup (str ? str : "");
                    if (ret->env[i] == NULL)
                        abort ();
                }
            }
        }
    }
    {
        yajl_val tmp = get_val (tree, "Entrypoint", yajl_t_array);
        if (tmp && YAJL_GET_ARRAY (tmp)) {
            size_t i;
            yajl_val *values = YAJL_GET_ARRAY (tmp)->values;
            size_t len = YAJL_GET_ARRAY (tmp)->len;
            ret->entrypoint_len = len;
            ret->entrypoint = safe_malloc ((len + 1) * sizeof (*ret->entrypoint));
            for (i = 0; i < len; i++) {
                yajl_val val = values[i];
                if (val) {
                    char *str = YAJL_GET_STRING (val);
                    ret->entrypoint[i] = strdup (str ? str : "");
                    if (ret->entrypoint[i] == NULL)
                        abort ();
                }
            }
        }
    }
    {
        yajl_val tmp = get_val (tree, "Cmd", yajl_t_array);
        if (tmp && YAJL_GET_ARRAY (tmp)) {
            size_t i;
            yajl_val *values = YAJL_GET_ARRAY (tmp)->values;
            size_t len = YAJL_GET_ARRAY (tmp)->len;
            ret->cmd_len = len;
            ret->cmd = safe_malloc ((len + 1) * sizeof (*ret->cmd));
            for (i = 0; i < len; i++) {
                yajl_val val = values[i];
                if (val) {
                    char *str = YAJL_GET_STRING (val);
                    ret->cmd[i] = strdup (str ? str : "");
                    if (ret->cmd[i] == NULL)
                        abort ();
                }
            }
        }
    }
    {
        yajl_val tmp = get_val (tree, "Volumes", yajl_t_object);
        if (tmp && YAJL_GET_OBJECT (tmp)) {
            size_t i;
            const char **keys = YAJL_GET_OBJECT (tmp)->keys;
            size_t len = YAJL_GET_OBJECT (tmp)->len;
            ret->volumes_len = len;
            ret->volumes = safe_malloc ((len + 1) * sizeof (*ret->volumes));
            for (i = 0; i < len; i++) {
                const char *key = keys[i];
                if (key) {
                     ret->volumes[i] = strdup (key) ? : "";
                     if (ret->volumes[i] == NULL)
                         abort ();                }
            }
        }
        else
        {
            ret->volumes_len = 0;
        }
    }
    {
        yajl_val val = get_val (tree, "WorkingDir", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->working_dir = strdup (str ? str : "");
            if (ret->working_dir == NULL)
                abort ();
        }
    }
    {
        yajl_val tmp = get_val (tree, "Labels", yajl_t_object);
        if (tmp != NULL) {
            ret->labels = read_map_string_string (tmp);
        }
    }
    {
        yajl_val val = get_val (tree, "StopSignal", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->stop_signal = strdup (str ? str : "");
            if (ret->stop_signal == NULL)
                abort ();
        }
    }

    if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) {
        size_t i;
        for (i = 0; i < tree->u.object.len; i++)
            if (strcmp (tree->u.object.keys[i], "User") &&
                strcmp (tree->u.object.keys[i], "ExposedPorts") &&
                strcmp (tree->u.object.keys[i], "Env") &&
                strcmp (tree->u.object.keys[i], "Entrypoint") &&
                strcmp (tree->u.object.keys[i], "Cmd") &&
                strcmp (tree->u.object.keys[i], "Volumes") &&
                strcmp (tree->u.object.keys[i], "WorkingDir") &&
                strcmp (tree->u.object.keys[i], "Labels") &&
                strcmp (tree->u.object.keys[i], "StopSignal")) {
                fprintf (ctx->errfile, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]);
            }
        }
    return ret;
}

void free_oci_image_config (oci_image_config *ptr) {
    if (!ptr)
        return;
    free (ptr->user);
    ptr->user = NULL;
    if (ptr->exposed_ports) {
        size_t i;
        for (i = 0; i < ptr->exposed_ports_len; i++) {
            if (ptr->exposed_ports[i]) {
                free (ptr->exposed_ports[i]);
                ptr->exposed_ports[i] = NULL;
            }
        }
        free (ptr->exposed_ports);
        ptr->exposed_ports = NULL;
    }
    if (ptr->env) {
        size_t i;
        for (i = 0; i < ptr->env_len; i++) {
            if (ptr->env[i]) {
                free (ptr->env[i]);
                ptr->env[i] = NULL;
            }
        }
        free (ptr->env);
        ptr->env = NULL;
    }
    if (ptr->entrypoint) {
        size_t i;
        for (i = 0; i < ptr->entrypoint_len; i++) {
            if (ptr->entrypoint[i]) {
                free (ptr->entrypoint[i]);
                ptr->entrypoint[i] = NULL;
            }
        }
        free (ptr->entrypoint);
        ptr->entrypoint = NULL;
    }
    if (ptr->cmd) {
        size_t i;
        for (i = 0; i < ptr->cmd_len; i++) {
            if (ptr->cmd[i]) {
                free (ptr->cmd[i]);
                ptr->cmd[i] = NULL;
            }
        }
        free (ptr->cmd);
        ptr->cmd = NULL;
    }
    if (ptr->volumes) {
        size_t i;
        for (i = 0; i < ptr->volumes_len; i++) {
            if (ptr->volumes[i]) {
                free (ptr->volumes[i]);
                ptr->volumes[i] = NULL;
            }
        }
        free (ptr->volumes);
        ptr->volumes = NULL;
    }
    free (ptr->working_dir);
    ptr->working_dir = NULL;
    free_oci_image_config_labels (ptr->labels);
    ptr->labels = NULL;
    free (ptr->stop_signal);
    ptr->stop_signal = NULL;
    free (ptr);
}

bool gen_oci_image_config (yajl_gen g, oci_image_config *ptr, struct parser_context *ctx, parser_error *err) {
    bool stat = true;
    *err = 0;
    (void) ptr;  /* Silence compiler warning.  */
    (void) ctx;  /* Silence compiler warning.  */
    stat = reformat_start_map (g);
    if (!stat)
        return false;
    if (ptr->user) {
        stat = reformat_map_key (g, (unsigned char *) "User", 4 /* strlen ("User") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->user, strlen (ptr->user));
        if (!stat)
            return false;
    }
    if (ptr->exposed_ports) {
        stat = reformat_map_key (g, (unsigned char *) "ExposedPorts", 12 /* strlen ("ExposedPorts") */);
        if (!stat)
            return false;
        stat = reformat_start_map (g);
        if (!stat)
            return false;
        size_t i;
        for (i = 0; i < ptr->exposed_ports_len; i++) {
            stat = reformat_map_key (g, (unsigned char *) ptr->exposed_ports[i], strlen (ptr->exposed_ports[i]));
            if (!stat)
                return false;
            yajl_gen_config (g, yajl_gen_beautify, 0);
            stat = reformat_start_map (g);
            if (!stat)
                return false;
            stat = reformat_end_map (g);
            if (!stat)
                return false;
            yajl_gen_config (g, yajl_gen_beautify, 1);
        }
        stat = reformat_end_map (g);
        if (!stat)
            return false;
    }
    if (ptr->env) {
        stat = reformat_map_key (g, (unsigned char *) "Env", 3 /* strlen ("Env") */);
        if (!stat)
            return false;
        size_t i;
        stat = reformat_start_array (g);
        if (!stat)
            return false;
        for (i = 0; i < ptr->env_len; i++) {
            stat = reformat_string (g, (unsigned char *) ptr->env[i], strlen (ptr->env[i]));
            if (!stat)
                return false;
        }
        stat = reformat_end_array (g);
        if (!stat)
            return false;
    }
    if (ptr->entrypoint) {
        stat = reformat_map_key (g, (unsigned char *) "Entrypoint", 10 /* strlen ("Entrypoint") */);
        if (!stat)
            return false;
        size_t i;
        stat = reformat_start_array (g);
        if (!stat)
            return false;
        for (i = 0; i < ptr->entrypoint_len; i++) {
            stat = reformat_string (g, (unsigned char *) ptr->entrypoint[i], strlen (ptr->entrypoint[i]));
            if (!stat)
                return false;
        }
        stat = reformat_end_array (g);
        if (!stat)
            return false;
    }
    if (ptr->cmd) {
        stat = reformat_map_key (g, (unsigned char *) "Cmd", 3 /* strlen ("Cmd") */);
        if (!stat)
            return false;
        size_t i;
        stat = reformat_start_array (g);
        if (!stat)
            return false;
        for (i = 0; i < ptr->cmd_len; i++) {
            stat = reformat_string (g, (unsigned char *) ptr->cmd[i], strlen (ptr->cmd[i]));
            if (!stat)
                return false;
        }
        stat = reformat_end_array (g);
        if (!stat)
            return false;
    }
    if (ptr->volumes) {
        stat = reformat_map_key (g, (unsigned char *) "Volumes", 7 /* strlen ("Volumes") */);
        if (!stat)
            return false;
        stat = reformat_start_map (g);
        if (!stat)
            return false;
        size_t i;
        for (i = 0; i < ptr->volumes_len; i++) {
            stat = reformat_map_key (g, (unsigned char *) ptr->volumes[i], strlen (ptr->volumes[i]));
            if (!stat)
                return false;
            yajl_gen_config (g, yajl_gen_beautify, 0);
            stat = reformat_start_map (g);
            if (!stat)
                return false;
            stat = reformat_end_map (g);
            if (!stat)
                return false;
            yajl_gen_config (g, yajl_gen_beautify, 1);
        }
        stat = reformat_end_map (g);
        if (!stat)
            return false;
    }
    if (ptr->working_dir) {
        stat = reformat_map_key (g, (unsigned char *) "WorkingDir", 10 /* strlen ("WorkingDir") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->working_dir, strlen (ptr->working_dir));
        if (!stat)
            return false;
    }
    if (ptr->labels) {
        stat = reformat_map_key (g, (unsigned char *) "Labels", 6 /* strlen ("Labels") */);
        if (!stat)
            return false;
        stat = gen_map_string_string (g, ptr->labels);
        if (!stat)
            return false;
    }
    if (ptr->stop_signal) {
        stat = reformat_map_key (g, (unsigned char *) "StopSignal", 10 /* strlen ("StopSignal") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->stop_signal, strlen (ptr->stop_signal));
        if (!stat)
            return false;
    }
    stat = reformat_end_map (g);
    if (!stat)
        return false;
    return true;
}

oci_image_rootfs *make_oci_image_rootfs (yajl_val tree, struct parser_context *ctx, parser_error *err) {
    oci_image_rootfs *ret = NULL;
    *err = 0;
    (void) ctx;  /* Silence compiler warning.  */
    if (tree == NULL)
        return ret;
    ret = safe_malloc (sizeof (*ret));
    {
        yajl_val tmp = get_val (tree, "diff_ids", yajl_t_array);
        if (tmp && YAJL_GET_ARRAY (tmp)) {
            size_t i;
            yajl_val *values = YAJL_GET_ARRAY (tmp)->values;
            size_t len = YAJL_GET_ARRAY (tmp)->len;
            ret->diff_ids_len = len;
            ret->diff_ids = safe_malloc ((len + 1) * sizeof (*ret->diff_ids));
            for (i = 0; i < len; i++) {
                yajl_val val = values[i];
                if (val) {
                    char *str = YAJL_GET_STRING (val);
                    ret->diff_ids[i] = strdup (str ? str : "");
                    if (ret->diff_ids[i] == NULL)
                        abort ();
                }
            }
        }
    }
    {
        yajl_val val = get_val (tree, "type", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->type = strdup (str ? str : "");
            if (ret->type == NULL)
                abort ();
        }
    }
    if (ret->diff_ids == NULL) {
        if (asprintf (err, "Required field '%s' not present", "diff_ids") < 0)
            abort();
        free_oci_image_rootfs (ret);
        return NULL;
    }
    if (ret->type == NULL) {
        if (asprintf (err, "Required field '%s' not present", "type") < 0)
            abort();
        free_oci_image_rootfs (ret);
        return NULL;
    }

    if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) {
        size_t i;
        for (i = 0; i < tree->u.object.len; i++)
            if (strcmp (tree->u.object.keys[i], "diff_ids") &&
                strcmp (tree->u.object.keys[i], "type")) {
                fprintf (ctx->errfile, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]);
            }
        }
    return ret;
}

void free_oci_image_rootfs (oci_image_rootfs *ptr) {
    if (!ptr)
        return;
    if (ptr->diff_ids) {
        size_t i;
        for (i = 0; i < ptr->diff_ids_len; i++) {
            if (ptr->diff_ids[i]) {
                free (ptr->diff_ids[i]);
                ptr->diff_ids[i] = NULL;
            }
        }
        free (ptr->diff_ids);
        ptr->diff_ids = NULL;
    }
    free (ptr->type);
    ptr->type = NULL;
    free (ptr);
}

bool gen_oci_image_rootfs (yajl_gen g, oci_image_rootfs *ptr, struct parser_context *ctx, parser_error *err) {
    bool stat = true;
    *err = 0;
    (void) ptr;  /* Silence compiler warning.  */
    (void) ctx;  /* Silence compiler warning.  */
    stat = reformat_start_map (g);
    if (!stat)
        return false;
    if (ptr->diff_ids) {
        stat = reformat_map_key (g, (unsigned char *) "diff_ids", 8 /* strlen ("diff_ids") */);
        if (!stat)
            return false;
        size_t i;
        stat = reformat_start_array (g);
        if (!stat)
            return false;
        for (i = 0; i < ptr->diff_ids_len; i++) {
            stat = reformat_string (g, (unsigned char *) ptr->diff_ids[i], strlen (ptr->diff_ids[i]));
            if (!stat)
                return false;
        }
        stat = reformat_end_array (g);
        if (!stat)
            return false;
    }
    if (ptr->type) {
        stat = reformat_map_key (g, (unsigned char *) "type", 4 /* strlen ("type") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->type, strlen (ptr->type));
        if (!stat)
            return false;
    }
    stat = reformat_end_map (g);
    if (!stat)
        return false;
    return true;
}

oci_image_history_element *make_oci_image_history_element (yajl_val tree, struct parser_context *ctx, parser_error *err) {
    oci_image_history_element *ret = NULL;
    *err = 0;
    (void) ctx;  /* Silence compiler warning.  */
    if (tree == NULL)
        return ret;
    ret = safe_malloc (sizeof (*ret));
    {
        yajl_val val = get_val (tree, "created", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->created = strdup (str ? str : "");
            if (ret->created == NULL)
                abort ();
        }
    }
    {
        yajl_val val = get_val (tree, "author", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->author = strdup (str ? str : "");
            if (ret->author == NULL)
                abort ();
        }
    }
    {
        yajl_val val = get_val (tree, "created_by", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->created_by = strdup (str ? str : "");
            if (ret->created_by == NULL)
                abort ();
        }
    }
    {
        yajl_val val = get_val (tree, "comment", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->comment = strdup (str ? str : "");
            if (ret->comment == NULL)
                abort ();
        }
    }
    {
        yajl_val val = get_val (tree, "empty_layer", yajl_t_true);
        if (val) {
            ret->empty_layer = YAJL_IS_TRUE (val);
            ret->empty_layer_present = 1;
        }
    }
    return ret;
}

void free_oci_image_history_element (oci_image_history_element *ptr) {
    if (!ptr)
        return;
    free (ptr->created);
    ptr->created = NULL;
    free (ptr->author);
    ptr->author = NULL;
    free (ptr->created_by);
    ptr->created_by = NULL;
    free (ptr->comment);
    ptr->comment = NULL;
    free (ptr);
}

bool gen_oci_image_history_element (yajl_gen g, oci_image_history_element *ptr, struct parser_context *ctx, parser_error *err) {
    bool stat = true;
    *err = 0;
    (void) ptr;  /* Silence compiler warning.  */
    (void) ctx;  /* Silence compiler warning.  */
    stat = reformat_start_map (g);
    if (!stat)
        return false;
    if (ptr->created) {
        stat = reformat_map_key (g, (unsigned char *) "created", 7 /* strlen ("created") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->created, strlen (ptr->created));
        if (!stat)
            return false;
    }
    if (ptr->author) {
        stat = reformat_map_key (g, (unsigned char *) "author", 6 /* strlen ("author") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->author, strlen (ptr->author));
        if (!stat)
            return false;
    }
    if (ptr->created_by) {
        stat = reformat_map_key (g, (unsigned char *) "created_by", 10 /* strlen ("created_by") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->created_by, strlen (ptr->created_by));
        if (!stat)
            return false;
    }
    if (ptr->comment) {
        stat = reformat_map_key (g, (unsigned char *) "comment", 7 /* strlen ("comment") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->comment, strlen (ptr->comment));
        if (!stat)
            return false;
    }
    if (ptr->empty_layer_present) {
        stat = reformat_map_key (g, (unsigned char *)"empty_layer", 11 /* strlen ("empty_layer") */);
        if (!stat)
            return false;
        stat = reformat_boolean (g, 1);
        if (!stat)
            return false;
    }
    stat = reformat_end_map (g);
    if (!stat)
        return false;
    return true;
}

oci_image *make_oci_image (yajl_val tree, struct parser_context *ctx, parser_error *err) {
    oci_image *ret = NULL;
    *err = 0;
    (void) ctx;  /* Silence compiler warning.  */
    if (tree == NULL)
        return ret;
    ret = safe_malloc (sizeof (*ret));
    {
        yajl_val val = get_val (tree, "created", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->created = strdup (str ? str : "");
            if (ret->created == NULL)
                abort ();
        }
    }
    {
        yajl_val val = get_val (tree, "author", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->author = strdup (str ? str : "");
            if (ret->author == NULL)
                abort ();
        }
    }
    {
        yajl_val val = get_val (tree, "architecture", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->architecture = strdup (str ? str : "");
            if (ret->architecture == NULL)
                abort ();
        }
    }
    {
        yajl_val val = get_val (tree, "os", yajl_t_string);
        if (val) {
            char *str = YAJL_GET_STRING (val);
            ret->os = strdup (str ? str : "");
            if (ret->os == NULL)
                abort ();
        }
    }
    ret->config = make_oci_image_config (get_val (tree, "config", yajl_t_object), ctx, err);
    if (ret->config == NULL && *err != 0) {
        free_oci_image (ret);
        return NULL;
    }
    ret->rootfs = make_oci_image_rootfs (get_val (tree, "rootfs", yajl_t_object), ctx, err);
    if (ret->rootfs == NULL && *err != 0) {
        free_oci_image (ret);
        return NULL;
    }
    {
        yajl_val tmp = get_val (tree, "history", yajl_t_array);
        if (tmp && YAJL_GET_ARRAY (tmp)) {
            size_t i;
            yajl_val *values = YAJL_GET_ARRAY (tmp)->values;
            size_t len = YAJL_GET_ARRAY (tmp)->len;
            ret->history_len = len;
            ret->history = safe_malloc ((len + 1) * sizeof (*ret->history));
            for (i = 0; i < len; i++) {
                ret->history[i] = make_oci_image_history_element (values[i], ctx, err);
                if (ret->history[i] == NULL) {
                    free_oci_image (ret);
                    return NULL;
                }
            }
        }
    }
    if (ret->architecture == NULL) {
        if (asprintf (err, "Required field '%s' not present", "architecture") < 0)
            abort();
        free_oci_image (ret);
        return NULL;
    }
    if (ret->os == NULL) {
        if (asprintf (err, "Required field '%s' not present", "os") < 0)
            abort();
        free_oci_image (ret);
        return NULL;
    }
    if (ret->rootfs == NULL) {
        if (asprintf (err, "Required field '%s' not present", "rootfs") < 0)
            abort();
        free_oci_image (ret);
        return NULL;
    }

    if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) {
        size_t i;
        for (i = 0; i < tree->u.object.len; i++)
            if (strcmp (tree->u.object.keys[i], "created") &&
                strcmp (tree->u.object.keys[i], "author") &&
                strcmp (tree->u.object.keys[i], "architecture") &&
                strcmp (tree->u.object.keys[i], "os") &&
                strcmp (tree->u.object.keys[i], "config") &&
                strcmp (tree->u.object.keys[i], "rootfs") &&
                strcmp (tree->u.object.keys[i], "history")) {
                fprintf (ctx->errfile, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]);
            }
        }
    return ret;
}

void free_oci_image (oci_image *ptr) {
    if (!ptr)
        return;
    free (ptr->created);
    ptr->created = NULL;
    free (ptr->author);
    ptr->author = NULL;
    free (ptr->architecture);
    ptr->architecture = NULL;
    free (ptr->os);
    ptr->os = NULL;
    if (ptr->config) {
        free_oci_image_config (ptr->config);
        ptr->config = NULL;
    }
    if (ptr->rootfs) {
        free_oci_image_rootfs (ptr->rootfs);
        ptr->rootfs = NULL;
    }
    if (ptr->history) {
        size_t i;
        for (i = 0; i < ptr->history_len; i++)
            if (ptr->history[i]) {
                free_oci_image_history_element (ptr->history[i]);
                ptr->history[i] = NULL;
            }
        free (ptr->history);
        ptr->history = NULL;
    }
    free (ptr);
}

bool gen_oci_image (yajl_gen g, oci_image *ptr, struct parser_context *ctx, parser_error *err) {
    bool stat = true;
    *err = 0;
    (void) ptr;  /* Silence compiler warning.  */
    (void) ctx;  /* Silence compiler warning.  */
    stat = reformat_start_map (g);
    if (!stat)
        return false;
    if (ptr->created) {
        stat = reformat_map_key (g, (unsigned char *) "created", 7 /* strlen ("created") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->created, strlen (ptr->created));
        if (!stat)
            return false;
    }
    if (ptr->author) {
        stat = reformat_map_key (g, (unsigned char *) "author", 6 /* strlen ("author") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->author, strlen (ptr->author));
        if (!stat)
            return false;
    }
    if (ptr->architecture) {
        stat = reformat_map_key (g, (unsigned char *) "architecture", 12 /* strlen ("architecture") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->architecture, strlen (ptr->architecture));
        if (!stat)
            return false;
    }
    if (ptr->os) {
        stat = reformat_map_key (g, (unsigned char *) "os", 2 /* strlen ("os") */);
        if (!stat)
            return false;
        stat = reformat_string (g, (unsigned char *) ptr->os, strlen (ptr->os));
        if (!stat)
            return false;
    }
    if (ptr->config) {
        stat = reformat_map_key (g, (unsigned char *) "config", 6 /* strlen ("config") */);
        if (!stat)
            return false;
        stat = gen_oci_image_config (g, ptr->config, ctx, err);
        if (!stat)
            return false;
    }
    if (ptr->rootfs) {
        stat = reformat_map_key (g, (unsigned char *) "rootfs", 6 /* strlen ("rootfs") */);
        if (!stat)
            return false;
        stat = gen_oci_image_rootfs (g, ptr->rootfs, ctx, err);
        if (!stat)
            return false;
    }
    if (ptr->history) {
        stat = reformat_map_key (g, (unsigned char *) "history", 7 /* strlen ("history") */);
        if (!stat)
            return false;
        size_t i;
        stat = reformat_start_array (g);
        if (!stat)
            return false;
        for (i = 0; i < ptr->history_len; i++) {
            stat = gen_oci_image_history_element(g, ptr->history[i], ctx, err);
            if (!stat)
                return false;
        }
        stat = reformat_end_array (g);
        if (!stat)
            return false;
    }
    stat = reformat_end_map (g);
    if (!stat)
        return false;
    return true;
}


oci_image *oci_image_parse_file (const char *filename, struct parser_context *ctx, parser_error *err) {
    yajl_val tree;
    size_t filesize;

    if (!filename || !err)
        return NULL;
    *err = NULL;
    struct parser_context tmp_ctx;
    if (!ctx) {
       ctx = &tmp_ctx;
       memset (&tmp_ctx, 0, sizeof (tmp_ctx));
    }
    char *content = read_file (filename, &filesize);
    char errbuf[1024];
    if (content == NULL) {
        if (asprintf (err, "cannot read the file: %s", filename) < 0)
            abort ();
        return NULL;
    }
    tree = yajl_tree_parse (content, errbuf, sizeof (errbuf));
    free (content);
    if (tree == NULL) {
        if (asprintf (err, "cannot parse the file: %s", errbuf) < 0)
            abort ();
        return NULL;
    }

    oci_image *ptr = make_oci_image (tree, ctx, err);
    yajl_tree_free (tree);
    return ptr;
}

oci_image *oci_image_parse_file_stream (FILE *stream, struct parser_context *ctx, parser_error *err) {
    yajl_val tree;
    size_t filesize;

    if (!stream || !err)
        return NULL;
    *err = NULL;
    struct parser_context tmp_ctx;
    if (!ctx) {
       ctx = &tmp_ctx;
       memset (&tmp_ctx, 0, sizeof (tmp_ctx));
    }
    char *content = fread_file (stream, &filesize);
    char errbuf[1024];
    if (content == NULL) {
        *err = strdup ("cannot read the file");
        return NULL;
    }
    tree = yajl_tree_parse (content, errbuf, sizeof (errbuf));
    free (content);
    if (tree == NULL) {
        if (asprintf (err, "cannot parse the stream: %s", errbuf) < 0)
            abort ();
        return NULL;
    }

    oci_image *ptr = make_oci_image (tree, ctx, err);
    yajl_tree_free (tree);
    return ptr;
}

oci_image *oci_image_parse_data (const char *jsondata, struct parser_context *ctx, parser_error *err) {
    yajl_val tree;
    struct parser_context tmp_ctx;

    if (!jsondata || !err)
        return NULL;
    *err = NULL;
    if (!ctx) {
       ctx = &tmp_ctx;
       memset (&tmp_ctx, 0, sizeof (tmp_ctx));
    }
    char errbuf[1024];
    tree = yajl_tree_parse (jsondata, errbuf, sizeof (errbuf));
    if (tree == NULL) {
        if (asprintf (err, "cannot parse the data: %s", errbuf) < 0)
            abort ();
        return NULL;
    }
    oci_image *ptr = make_oci_image (tree, ctx, err);
    yajl_tree_free (tree);
    return ptr;
}
char *oci_image_generate_json (oci_image *ptr, struct parser_context *ctx, parser_error *err) {
    yajl_gen g = NULL;
    struct parser_context tmp_ctx;
    const unsigned char *gen_buf = NULL;
    char *json_buf = NULL;
    size_t gen_len = 0;

    if (!ptr || !err)
        return NULL;
    *err = NULL;
    if (!ctx) {
        ctx = &tmp_ctx;
        memset (&tmp_ctx, 0, sizeof (tmp_ctx));
    }

    if (!json_gen_init (&g)) {
        *err = strdup ("Json_gen init failed");
        goto out;
    }
    if (!gen_oci_image (g, ptr, ctx, err)) {
        *err = strdup ("Failed to generate json");
        goto free_out;
    }

    yajl_gen_get_buf (g, &gen_buf, &gen_len);
    if (!gen_buf) {
        *err = strdup ("Error to get generated json");
        goto free_out;
    }

    json_buf = safe_malloc (gen_len + 1);
    memcpy (json_buf, gen_buf, gen_len);
    json_buf[gen_len] = '\0';

free_out:
    yajl_gen_clear (g);
    yajl_gen_free (g);
out:
    return json_buf;
}
