MOBI_RET mobi_build_opf_guide(OPF *opf, const MOBIRawml *rawml) {
    /* parse guide data */
    if (rawml == NULL || rawml->guide == NULL) {
        debug_print("%s\n", "Initialization failed");
        return MOBI_INIT_FAILED;
    }
    size_t i = 0;
    size_t j = 0;
    MOBI_RET ret;
    size_t count = rawml->guide->entries_count;
    if (count == 0) {
        return MOBI_SUCCESS;
    }
    opf->guide = malloc(sizeof(OPFguide));
    if (opf->guide == NULL) {
        debug_print("%s\n", "Memory allocation failed");
        return MOBI_MALLOC_FAILED;
    }
    OPFreference **reference = malloc((count + 1) * sizeof(OPFreference*));
    if (reference == NULL) {
        free(opf->guide);
        opf->guide = NULL;
        debug_print("%s\n", "Memory allocation failed");
        return MOBI_MALLOC_FAILED;
    }
    if (rawml->guide->cncx_record == NULL) {
        free(reference);
        free(opf->guide);
        opf->guide = NULL;
        debug_print("%s\n", "Missing cncx record");
        return MOBI_DATA_CORRUPT;
    }
    while (i < count) {
        const MOBIIndexEntry *guide_entry = &rawml->guide->entries[i];
        const char *type = guide_entry->label;
        uint32_t cncx_offset;
        ret = mobi_get_indxentry_tagvalue(&cncx_offset, guide_entry, INDX_TAG_GUIDE_TITLE_CNCX);
        if (ret != MOBI_SUCCESS) {
            free(reference);
            free(opf->guide);
            opf->guide = NULL;
            return ret;
        }
        const MOBIPdbRecord *cncx_record = rawml->guide->cncx_record;
        char *ref_title = mobi_get_cncx_string_utf8(cncx_record, cncx_offset, rawml->guide->encoding);
        if (ref_title == NULL) {
            free(reference);
            free(opf->guide);
            opf->guide = NULL;
            debug_print("%s\n", "Memory allocation failed");
            return MOBI_MALLOC_FAILED;
        }
        uint32_t frag_number = MOBI_NOTSET;
        ret = mobi_get_indxentry_tagvalue(&frag_number, guide_entry, INDX_TAG_FRAG_POSITION);
        if (ret != MOBI_SUCCESS) {
            debug_print("INDX_TAG_FRAG_POSITION not found (%i)\n", ret);
            free(ref_title);
            i++;
            continue;
            /* FIXME: I need some examples which use other tags */
            //mobi_get_indxentry_tagvalue(&frag_number, guide_entry, INDX_TAG_FRAG_FILE_NR);
        }
        if (frag_number >= rawml->frag->entries_count) {
            debug_print("Wrong frag entry index (%i)\n", frag_number);
            free(ref_title);
            i++;
            continue;
        }
        const MOBIIndexEntry *frag_entry = &rawml->frag->entries[frag_number];
        uint32_t file_number;
        ret = mobi_get_indxentry_tagvalue(&file_number, frag_entry, INDX_TAG_FRAG_FILE_NR);
        if (ret != MOBI_SUCCESS) {
            free(reference);
            free(opf->guide);
            free(ref_title);
            opf->guide = NULL;
            return ret;
        }
        /* check if valid guide type */
        char *ref_type;
        size_t type_size = strlen(type);
        if (!mobi_is_guide_type(type)) {
            /* prepend "other." prefix */
            type_size += 6;
            ref_type = malloc(type_size + 1);
            if (ref_type == NULL) {
                free(reference);
                free(opf->guide);
                opf->guide = NULL;
                free(ref_title);
                debug_print("%s\n", "Memory allocation failed");
                return MOBI_MALLOC_FAILED;
            }
            snprintf(ref_type, type_size + 1, "other.%s", type);
        } else {
            ref_type = malloc(type_size + 1);
            if (ref_type == NULL) {
                free(reference);
                free(opf->guide);
                opf->guide = NULL;
                free(ref_title);
                debug_print("%s\n", "Memory allocation failed");
                return MOBI_MALLOC_FAILED;
            }
            memcpy(ref_type, type, type_size);
            ref_type[type_size] = '\0';
        }
        debug_print("<reference type=\"%s\" title=\"%s\" href=\"part%05u.html\" />", ref_type, ref_title, file_number);
        char href[FILENAME_MAX + 1];
        snprintf(href, sizeof(href), "part%05u.html", file_number);
        char *ref_href = strdup(href);
        reference[j] = calloc(1, sizeof(OPFreference));
        *reference[j] = (OPFreference) { ref_type, ref_title, ref_href };
        i++;
        j++;
    }
    /* terminate array with NULL */
    reference[j] = NULL;
    opf->guide->reference = reference;
    return MOBI_SUCCESS;
}