MOBI_RET mobi_reconstruct_orth(const MOBIRawml *rawml, MOBIFragment *first, size_t *new_size) {
    MOBITrie *infl_trie = NULL;
    bool is_infl_v2 = mobi_indx_has_tag(rawml->orth, INDX_TAGARR_ORTH_INFL);
    bool is_infl_v1 = false;
    if (is_infl_v2 == false) {
        is_infl_v1 = mobi_indx_has_tag(rawml->infl, INDX_TAGARR_INFL_PARTS_V1);
    }
    debug_print("Reconstructing orth index %s\n", (is_infl_v1)?"(infl v1)":(is_infl_v2)?"(infl v2)":"");
    if (is_infl_v1) {
        size_t total = rawml->infl->entries_count;
        size_t j = 0;
        while (j < total) {
            MOBI_RET ret = mobi_trie_insert_infl(&infl_trie, rawml->infl, j++);
            if (ret != MOBI_SUCCESS || infl_trie == NULL) {
                debug_print("Building trie for inflections failed%s", "\n");
                mobi_trie_free(infl_trie);
                is_infl_v1 = false;
            }
        }
    }
    
    MOBIFragment *curr = first;
    size_t i = 0;
    const size_t count = rawml->orth->entries_count;
    const char *start_tag1 = "<idx:entry><idx:orth value=\"%s\">%s</idx:orth></idx:entry>";
    const char *start_tag2 = "<idx:entry scriptable=\"yes\"><idx:orth value=\"%s\">%s</idx:orth>";
    const char *end_tag = "</idx:entry>";
    const size_t start_tag1_len = strlen(start_tag1) - 4;
    const size_t start_tag2_len = strlen(start_tag2) - 4;
    const size_t end_tag_len = strlen(end_tag);
    uint32_t prev_startpos = 0;
    while (i < count) {
        const MOBIIndexEntry *orth_entry = &rawml->orth->entries[i];
        const char *label = orth_entry->label;
        uint32_t entry_startpos;
        MOBI_RET ret = mobi_get_indxentry_tagvalue(&entry_startpos, orth_entry, INDX_TAG_ORTH_POSITION);
        if (ret != MOBI_SUCCESS) {
            i++;
            continue;
        }
        size_t entry_length = 0;
        uint32_t entry_textlen = 0;
        mobi_get_indxentry_tagvalue(&entry_textlen, orth_entry, INDX_TAG_ORTH_LENGTH);
        char *start_tag;
        if (entry_textlen == 0) {
            entry_length += start_tag1_len + strlen(label);
            start_tag = (char *) start_tag1;
        } else {
            entry_length += start_tag2_len + strlen(label);
            start_tag = (char *) start_tag2;
        }

        char *entry_text;
        if (rawml->infl) {
            char *infl_tag = malloc(INDX_INFLTAG_SIZEMAX + 1);
            if (infl_tag == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                return MOBI_MALLOC_FAILED;
            }
            infl_tag[0] = '\0';
            if (is_infl_v2) {
                ret = mobi_reconstruct_infl(infl_tag, rawml->infl, orth_entry);
            } else if (is_infl_v1) {
                ret = mobi_reconstruct_infl_v1(infl_tag, infl_trie, orth_entry);
            } else {
                debug_print("Unknown inflection scheme?%s", "\n");
            }
            if (ret != MOBI_SUCCESS) {
                free(infl_tag);
                return ret;
            }
            entry_length += strlen(infl_tag);
            
            entry_text = malloc(entry_length + 1);
            if (entry_text == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                free(infl_tag);
                return MOBI_MALLOC_FAILED;
            }
            snprintf(entry_text, entry_length + 1, start_tag, label, infl_tag);
            free(infl_tag);
        } else {
            entry_text = malloc(entry_length + 1);
            if (entry_text == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                return MOBI_MALLOC_FAILED;
            }
            snprintf(entry_text, entry_length + 1, start_tag, label, "");
        }
        
        if (entry_startpos < prev_startpos) {
            curr = first;
        }
        curr = mobi_list_insert(curr, SIZE_MAX,
                                (unsigned char *) entry_text,
                                entry_length, true, entry_startpos);
        prev_startpos = entry_startpos;
        if (curr == NULL) {
            debug_print("%s\n", "Memory allocation failed");
            mobi_trie_free(infl_trie);
            return MOBI_MALLOC_FAILED;
        }
        *new_size += curr->size;
        if (entry_textlen > 0) {
            /* FIXME: avoid end_tag duplication */
            curr = mobi_list_insert(curr, SIZE_MAX,
                                    (unsigned char *) strdup(end_tag),
                                    end_tag_len, true, entry_startpos + entry_textlen);
            if (curr == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                return MOBI_MALLOC_FAILED;
            }
            *new_size += curr->size;
        }
        i++;
    }
    mobi_trie_free(infl_trie);
    return MOBI_SUCCESS;
}
MOBI_RET mobi_reconstruct_orth(const MOBIRawml *rawml, MOBIFragment *first, size_t *new_size) {
    MOBITrie *infl_trie = NULL;
    bool is_infl_v2 = mobi_indx_has_tag(rawml->orth, INDX_TAGARR_ORTH_INFL);
    bool is_infl_v1 = false;
    if (is_infl_v2 == false) {
        is_infl_v1 = mobi_indx_has_tag(rawml->infl, INDX_TAGARR_INFL_PARTS_V1);
    }
    debug_print("Reconstructing orth index %s\n", (is_infl_v1)?"(infl v1)":(is_infl_v2)?"(infl v2)":"");
    if (is_infl_v1) {
        size_t total = rawml->infl->entries_count;
        size_t j = 0;
        while (j < total) {
            MOBI_RET ret = mobi_trie_insert_infl(&infl_trie, rawml->infl, j++);
            if (ret != MOBI_SUCCESS || infl_trie == NULL) {
                debug_print("Building trie for inflections failed%s", "\n");
                mobi_trie_free(infl_trie);
                is_infl_v1 = false;
            }
        }
    }
    
    MOBIFragment *curr = first;
    size_t i = 0;
    const size_t count = rawml->orth->entries_count;
    const char *start_tag1 = "<idx:entry><idx:orth value=\"%s\">%s</idx:orth></idx:entry>";
    const char *start_tag2 = "<idx:entry scriptable=\"yes\"><idx:orth value=\"%s\">%s</idx:orth>";
    const char *end_tag = "</idx:entry>";
    const size_t start_tag1_len = strlen(start_tag1) - 4;
    const size_t start_tag2_len = strlen(start_tag2) - 4;
    const size_t end_tag_len = strlen(end_tag);
    uint32_t prev_startpos = 0;
    while (i < count) {
        const MOBIIndexEntry *orth_entry = &rawml->orth->entries[i];
        const char *label = orth_entry->label;
        uint32_t entry_startpos;
        MOBI_RET ret = mobi_get_indxentry_tagvalue(&entry_startpos, orth_entry, INDX_TAG_ORTH_POSITION);
        if (ret != MOBI_SUCCESS) {
            i++;
            continue;
        }
        size_t entry_length = 0;
        uint32_t entry_textlen = 0;
        mobi_get_indxentry_tagvalue(&entry_textlen, orth_entry, INDX_TAG_ORTH_LENGTH);
        char *start_tag;
        if (entry_textlen == 0) {
            entry_length += start_tag1_len + strlen(label);
            start_tag = (char *) start_tag1;
        } else {
            entry_length += start_tag2_len + strlen(label);
            start_tag = (char *) start_tag2;
        }

        char *entry_text;
        if (rawml->infl) {
            char *infl_tag = malloc(INDX_INFLTAG_SIZEMAX + 1);
            if (infl_tag == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                return MOBI_MALLOC_FAILED;
            }
            infl_tag[0] = '\0';
            if (is_infl_v2) {
                ret = mobi_reconstruct_infl(infl_tag, rawml->infl, orth_entry);
            } else if (is_infl_v1) {
                ret = mobi_reconstruct_infl_v1(infl_tag, infl_trie, orth_entry);
            } else {
                debug_print("Unknown inflection scheme?%s", "\n");
            }
            if (ret != MOBI_SUCCESS) {
                free(infl_tag);
                return ret;
            }
            entry_length += strlen(infl_tag);
            
            entry_text = malloc(entry_length + 1);
            if (entry_text == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                free(infl_tag);
                return MOBI_MALLOC_FAILED;
            }
            snprintf(entry_text, entry_length + 1, start_tag, label, infl_tag);
            free(infl_tag);
        } else {
            entry_text = malloc(entry_length + 1);
            if (entry_text == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                return MOBI_MALLOC_FAILED;
            }
            snprintf(entry_text, entry_length + 1, start_tag, label, "");
        }
        
        if (entry_startpos < prev_startpos) {
            curr = first;
        }
        curr = mobi_list_insert(curr, SIZE_MAX,
                                (unsigned char *) entry_text,
                                entry_length, true, entry_startpos);
        prev_startpos = entry_startpos;
        if (curr == NULL) {
            debug_print("%s\n", "Memory allocation failed");
            mobi_trie_free(infl_trie);
            return MOBI_MALLOC_FAILED;
        }
        *new_size += curr->size;
        if (entry_textlen > 0) {
             
            curr = mobi_list_insert(curr, SIZE_MAX,
                                    (unsigned char *) strdup(end_tag),
                                    end_tag_len, true, entry_startpos + entry_textlen);
            if (curr == NULL) {
                debug_print("%s\n", "Memory allocation failed");
                mobi_trie_free(infl_trie);
                return MOBI_MALLOC_FAILED;
            }
            *new_size += curr->size;
        }
        i++;
    }
    mobi_trie_free(infl_trie);
    return MOBI_SUCCESS;
}