static cl_error_t egg_parse_file_extra_field(egg_handle* handle, egg_file* eggFile)
{
    cl_error_t status = CL_EPARSE;

    const uint8_t* index    = NULL;
    extra_field* extraField = NULL;
    uint32_t magic          = 0;
    uint32_t size           = 0;

    if (!handle || !eggFile) {
        cli_errmsg("egg_parse_file_extra_field: Invalid args!\n");
        return CL_EARG;
    }

    if (CL_SUCCESS != EGG_VALIDATE_HANDLE(handle)) {
        cli_errmsg("egg_parse_file_extra_field: Invalid handle values!\n");
        status = CL_EARG;
        goto done;
    }

    index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, sizeof(extra_field));
    if (!index) {
        cli_dbgmsg("egg_parse_file_extra_field: File buffer too small to contain extra_field header.\n");
        goto done;
    }

    extraField = (extra_field*)index;

    cli_dbgmsg("egg_parse_file_extra_field: extra_field->magic:    %08x (%s)\n", le32_to_host(extraField->magic), getMagicHeaderName(le32_to_host(extraField->magic)));
    cli_dbgmsg("egg_parse_file_extra_field: extra_field->bit_flag: %02x\n", extraField->bit_flag);

    handle->offset += sizeof(extra_field);

    if (extraField->bit_flag & EXTRA_FIELD_FLAGS_SIZE_IS_4BYTES) {
        /* size is uint32_t */
        index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, sizeof(uint32_t));
        if (!index) {
            cli_dbgmsg("egg_parse_file_extra_field: File buffer too small to contain extra_field header.\n");
            goto done;
        }

        size = le32_to_host(*(uint32_t*)index);

        handle->offset += sizeof(uint32_t);
    } else {
        /* size is uint16_t */
        index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, sizeof(uint16_t));
        if (!index) {
            cli_dbgmsg("egg_parse_file_extra_field: File buffer too small to contain extra_field header.\n");
            goto done;
        }

        size = le16_to_host(*(uint16_t*)index);

        handle->offset += sizeof(uint16_t);
    }

    cli_dbgmsg("egg_parse_file_extra_field: extra_field->size:     %u\n", size);

    magic = le32_to_host(extraField->magic);

    switch (magic) {
        case FILENAME_HEADER_MAGIC: {
            /*
             * File Filename Header
             */
            uint16_t codepage       = 0; /* Windows code page https://docs.microsoft.com/en-us/windows/desktop/Intl/code-page-identifiers) */
            uint32_t name_size      = 0;
            uint32_t remaining_size = size;

            char* name_utf8       = NULL;
            size_t name_utf8_size = 0;

            if (NULL != eggFile->filename.name_utf8) {
                cli_warnmsg("egg_parse_file_extra_field: Encountered more than 1 filename_header!\n");
                goto done;
            }

            index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, size);
            if (!index) {
                cli_dbgmsg("egg_parse_file_extra_field: File buffer too small to contain name fields.\n");
                goto done;
            }

            if (extraField->bit_flag & FILENAME_HEADER_FLAGS_ENCRYPT)
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->bit_flag: encrypted\n");
            else
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->bit_flag: not encrypted\n");

            if (extraField->bit_flag & FILENAME_HEADER_FLAGS_RELATIVE_PATH_INSTEAD_OF_ABSOLUTE)
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->bit_flag: relative-path\n");
            else
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->bit_flag: absolute-path\n");

            if (extraField->bit_flag & FILENAME_HEADER_FLAGS_MULTIBYTE_CODEPAGE_INSTEAD_OF_UTF8)
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->bit_flag: Windows Multibyte + codepage\n");
            else
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->bit_flag: UTF-8\n");

            if (extraField->bit_flag & FILENAME_HEADER_FLAGS_MULTIBYTE_CODEPAGE_INSTEAD_OF_UTF8) {
                /* Utf-8 - header will include locale */
                /* Check that the size is big enough */
                if (remaining_size < sizeof(uint16_t)) {
                    cli_dbgmsg("egg_parse_file_extra_field: size too small for locale information.\n");
                    goto done;
                }
                codepage = *(uint16_t*)index;
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->codepage:       %u\n", codepage);
                index += sizeof(uint16_t);
                handle->offset += sizeof(uint16_t);
                remaining_size -= sizeof(uint16_t);
            }

            if (extraField->bit_flag & FILENAME_HEADER_FLAGS_RELATIVE_PATH_INSTEAD_OF_ABSOLUTE) {
                /* header will include parent_path_id */
                /* Check that the size is big enough */
                if (remaining_size < sizeof(uint32_t)) {
                    cli_dbgmsg("egg_parse_file_extra_field: size too small for parent_path_id.\n");
                    goto done;
                }
                eggFile->filename.parent_path_id = *(uint16_t*)index;
                cli_dbgmsg("egg_parse_file_extra_field: filename_header->parent_path_id: %u\n", eggFile->filename.parent_path_id);
                index += sizeof(uint32_t);
                handle->offset += sizeof(uint32_t);
                remaining_size -= sizeof(uint32_t);
            }

            if (remaining_size == 0) {
                cli_dbgmsg("egg_parse_file_extra_field: size too small for name string.\n");
                goto done;
            }
            name_size = remaining_size;

            /*
             * Store name as UTF-8 string.
             */
            if (extraField->bit_flag & FILENAME_HEADER_FLAGS_MULTIBYTE_CODEPAGE_INSTEAD_OF_UTF8) {
                /* Convert ANSI codepage to UTF-8. EGG format explicitly supports:
                 * - 949 (Korean Unified Code)
                 * - 932 (Japanese Shift-JIS) */
                if (0 == codepage) {
                    if (CL_SUCCESS != cli_codepage_to_utf8((char*)index, name_size, 65001, &name_utf8, &name_utf8_size)) {
                        cli_dbgmsg("egg_parse_file_extra_field: failed to convert codepage \"0\" to UTF-8\n");
                        name_utf8 = cli_genfname(NULL);
                    }
                } else {
                    if (CL_SUCCESS != cli_codepage_to_utf8((char*)index, name_size, codepage, &name_utf8, &name_utf8_size)) {
                        cli_dbgmsg("egg_parse_file_extra_field: failed to convert codepage %u to UTF-8\n", codepage);
                        name_utf8 = cli_genfname(NULL);
                    }
                }
            } else {
                /* Should already be UTF-8. Use as-is.. */
                name_utf8 = CLI_STRNDUP((char*)index, name_size);
                if (NULL == name_utf8) {
                    cli_dbgmsg("egg_parse_file_extra_field: failed to allocate name buffer.\n");
                    status = CL_EMEM;
                    goto done;
                }
            }
            eggFile->filename.name_utf8 = name_utf8;

            cli_dbgmsg("egg_parse_file_extra_field: filename_header->name: %s\n", eggFile->filename.name_utf8);

            break;
        }
        case COMMENT_HEADER_MAGIC: {
            /*
             * File Comment Header
             */
            cl_error_t retval = CL_EPARSE;
            char* comment     = NULL;

            index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, size);
            if (!index) {
                cli_dbgmsg("egg_parse_file_extra_field: File buffer too small to contain comment fields.\n");
                goto done;
            }

            if (CL_SUCCESS != (retval = egg_parse_comment_header(index, size, extraField, &comment))) {
                cli_dbgmsg("egg_parse_file_extra_field: Issue parsing comment header. Error code: %u\n", retval);
                break;
            } else {
                /*
                 * Success?
                 */
                if (comment == NULL) {
                    /* Uh... no. */
                    cli_errmsg("egg_parse_file_extra_field: Logic error! Succesfully parsed comment header,"
                               " but did not return egg_comment information!\n");
                    goto done;
                } else {
                    /*
                     * Comment found. Add comment to our list.
                     */
                    char** comments_tmp;

                    comments_tmp = (char**)cli_realloc(
                        (void*)eggFile->comments,
                        sizeof(char**) * (eggFile->nComments + 1));
                    if (NULL == comments_tmp) {
                        status = CL_EMEM;
                        goto done;
                    }
                    eggFile->comments                     = comments_tmp;
                    eggFile->comments[eggFile->nComments] = comment;
                    eggFile->nComments++;
                }
            }
            break;
        }
        case ENCRYPT_HEADER_MAGIC: {
            /*
             * File Encryption Header.
             */
            if (NULL != eggFile->encrypt) {
                cli_warnmsg("egg_parse_file_extra_field: Encountered more than 1 encrypt_header!\n");
                goto done;
            }

            /*
             * Fudge factor.
             * The documentation is hazy about how the encrypt header works.
             * From testing, it seems that for encrypted files, the size in the extra_field includes the size OF the extra field.
             */
            size -= sizeof(extra_field) + sizeof(uint16_t);

            index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, size);
            if (!index) {
                cli_errmsg("egg_parse_file_extra_field: File buffer too small to contain encryption fields.\n");
                goto done;
            }

            if (CL_SUCCESS != egg_parse_encrypt_header(index, size, &eggFile->encrypt)) {
                cli_errmsg("egg_parse_file_extra_field: Failed to parse encrypt_header.\n");
                goto done;
            }
            break;
        }
        case WINDOWS_INFO_MAGIC: {
            windows_file_information* windowsFileInformation = NULL;

            if (NULL != eggFile->windowsFileInformation) {
                cli_warnmsg("egg_parse_file_extra_field: Encountered more than 1 windows_file_information!\n");
                goto done;
            }

            if (sizeof(windows_file_information) != size) {
                cli_warnmsg("egg_parse_file_extra_field: Invalid size of windows_file_information!\n");
            }

            index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, sizeof(windows_file_information));
            if (!index) {
                cli_dbgmsg("egg_parse_file_extra_field: File buffer too small to contain windows info.\n");
                goto done;
            }

            windowsFileInformation          = (windows_file_information*)index;
            eggFile->windowsFileInformation = windowsFileInformation;

            cli_dbgmsg("egg_parse_file_extra_field: windows_file_information->last_modified_time:   %016" PRIx64 "\n", le64_to_host(windowsFileInformation->last_modified_time));
            cli_dbgmsg("egg_parse_file_extra_field: windows_file_information->attribute:            %08x\n", windowsFileInformation->attribute);
            break;
        }
        case POSIX_INFO_MAGIC: {
            posix_file_information* posixFileInformation = NULL;

            if (NULL != eggFile->posixFileInformation) {
                cli_warnmsg("egg_parse_file_extra_field: Encountered more than 1 posix_file_information!\n");
                goto done;
            }

            if (sizeof(posix_file_information) != size) {
                cli_warnmsg("egg_parse_file_extra_field: Invalid size of posix_file_information!\n");
            }

            index = (const uint8_t*)fmap_need_off_once(handle->map, handle->offset, sizeof(posix_file_information));
            if (!index) {
                cli_dbgmsg("egg_parse_file_extra_field: File buffer too small to contain posix info.\n");
                goto done;
            }

            posixFileInformation          = (posix_file_information*)index;
            eggFile->posixFileInformation = posixFileInformation;

            cli_dbgmsg("egg_parse_file_extra_field: posix_file_information->mode:                 %08x ", le32_to_host(posixFileInformation->mode));
            if (UNLIKELY(cli_debug_flag)) {
                print_posix_info_mode(posixFileInformation->mode);
            }

            cli_dbgmsg("egg_parse_file_extra_field: posix_file_information->uid:                  %08x\n", le32_to_host(posixFileInformation->uid));
            cli_dbgmsg("egg_parse_file_extra_field: posix_file_information->gid:                  %08x\n", le32_to_host(posixFileInformation->gid));
            cli_dbgmsg("egg_parse_file_extra_field: posix_file_information->last_modified_time:   %016" PRIx64 "\n", le64_to_host(posixFileInformation->last_modified_time));
            break;
        }
        case FILE_HEADER_MAGIC: {
            if (handle->bSolid) {
                cli_dbgmsg("egg_parse_file_extra_field: Solid archive - on to next file header.\n");
            } else {
                cli_warnmsg("egg_parse_file_extra_field: Missing EOFARC in non-solid/standard archive.\n");
            }
            break;
        }
        default: {
            cli_dbgmsg("egg_parse_file_extra_field: unexpected header magic:    %08x (%s)\n", magic, getMagicHeaderName(magic));
        }
    }

    handle->offset += size;

    status = CL_SUCCESS;

done:

    return status;
}