static int append_name_to_string_array(MXFMetadataSet* set, const mxfKey* itemKey, const mxfUTF16Char* name)
{
    uint8_t* nameArray = NULL;
    uint16_t existingNameArraySize = 0;
    uint16_t nameArraySize = 0;
    MXFMetadataItem* namesItem = NULL;
    
    if (mxf_have_item(set, itemKey))
    {
        CHK_ORET(mxf_get_item(set, itemKey, &namesItem));
        existingNameArraySize = namesItem->length;
    }
    nameArraySize = existingNameArraySize + (uint16_t)(mxfUTF16Char_extlen * (wcslen(name) + 1));
    
    CHK_MALLOC_ARRAY_ORET(nameArray, uint8_t, nameArraySize);
    if (existingNameArraySize > 0)
    {
        memcpy(nameArray, namesItem->value, existingNameArraySize);
    }
    mxf_set_utf16string(name, &nameArray[existingNameArraySize]);
    
    CHK_OFAIL(mxf_set_item(set, itemKey, nameArray, nameArraySize));

    SAFE_FREE(&nameArray);
    return 1;
    
fail:
    SAFE_FREE(&nameArray);
    return 0;
}
static Page* open_page(MXFFileSysData *sysData, int64_t position)
{
    int i;
    int page;

    page = (int)(position / sysData->pageSize);
    if (page > sysData->numPages)
    {
        /* only allowed to open pages 0 .. last + 1 */
        return 0;
    }

    if (page == sysData->numPages)
    {
        if (sysData->mode == READ_MODE)
        {
            /* no more pages to open */
            return 0;
        }

        if (sysData->numPages == sysData->numPagesAllocated)
        {
            /* reallocate the pages */

            Page *newPages;
            CHK_MALLOC_ARRAY_ORET(newPages, Page, sysData->numPagesAllocated + PAGE_ALLOC_INCR);
            memcpy(newPages, sysData->pages, sizeof(Page) * sysData->numPagesAllocated);
            SAFE_FREE(sysData->pages);
            sysData->pages = newPages;
            sysData->numPagesAllocated += PAGE_ALLOC_INCR;

            /* reset the link back from file descriptors to the new pages */
            for (i = 0; i < sysData->numPages; i++)
            {
                if (sysData->pages[i].fileDescriptor != NULL)
                {
                    sysData->pages[i].fileDescriptor->page = &sysData->pages[i];
                }
            }
        }

        /* set new page data */
        memset(&sysData->pages[sysData->numPages], 0, sizeof(Page));
        sysData->pages[sysData->numPages].index = sysData->numPages;

        sysData->numPages++;
    }

    /* open the file */
    if (!open_file(sysData, &sysData->pages[page]))
    {
        return 0;
    }

    return &sysData->pages[page];
}
int mxf_read_item(MXFFile* mxfFile, MXFMetadataItem* item, uint16_t len)
{
    uint8_t buffer[65536];

    CHK_ORET(mxf_file_read(mxfFile, buffer, len) == len);

    CHK_MALLOC_ARRAY_ORET(item->value, uint8_t, len);
    memcpy(item->value, buffer, len);
    item->length = len;
    
    return 1;
}
int mxf_page_file_open_modify(const char *filenameTemplate, int64_t pageSize, MXFPageFile **mxfPageFile)
{
    MXFFile *newMXFFile = NULL;
    int pageCount;
    int allocatedPages;
    char filename[4096];
    FILE *file;
    int64_t fileSize;


    if (strstr(filenameTemplate, "%d") == NULL)
    {
        mxf_log_error("Filename template '%s' doesn't contain %%d\n", filenameTemplate);
        return 0;
    }

    /* count number of page files */
    pageCount = 0;
    for(;;)
    {
        mxf_snprintf(filename, sizeof(filename), filenameTemplate, pageCount);
        if ((file = fopen(filename, "rb")) == NULL)
        {
            break;
        }
        fclose(file);
        pageCount++;
    }

    if (pageCount == 0)
    {
        /* file not found */
        return 0;
    }

    /* check the size of the first file equals the pageSize */
    if (pageCount > 1)
    {
        mxf_snprintf(filename, sizeof(filename), filenameTemplate, 0);
        fileSize = disk_file_size(filename);
        if (fileSize < 0)
        {
            mxf_log_error("Failed to stat file '%s': %s\n", filename, strerror(errno));
            return 0;
        }
        if (pageSize != fileSize)
        {
            mxf_log_error("Size of first file '%s' (%"PRId64" does not equal page size %"PRId64"\n", filename, fileSize, pageSize);
            return 0;
        }
    }


    CHK_MALLOC_ORET(newMXFFile, MXFFile);
    memset(newMXFFile, 0, sizeof(*newMXFFile));

    newMXFFile->close           = page_file_close;
    newMXFFile->read            = page_file_read;
    newMXFFile->write           = page_file_write;
    newMXFFile->get_char        = page_file_getchar;
    newMXFFile->put_char        = page_file_putchar;
    newMXFFile->eof             = page_file_eof;
    newMXFFile->seek            = page_file_seek;
    newMXFFile->tell            = page_file_tell;
    newMXFFile->is_seekable     = page_file_is_seekable;
    newMXFFile->size            = page_file_size;
    newMXFFile->free_sys_data   = free_page_file;


    CHK_MALLOC_OFAIL(newMXFFile->sysData, MXFFileSysData);
    memset(newMXFFile->sysData, 0, sizeof(*newMXFFile->sysData));

    CHK_OFAIL((newMXFFile->sysData->filenameTemplate = strdup(filenameTemplate)) != NULL);
    newMXFFile->sysData->pageSize = pageSize;
    newMXFFile->sysData->mode = MODIFY_MODE;
    newMXFFile->sysData->mxfPageFile.mxfFile = newMXFFile;


    /* allocate pages */
    allocatedPages = (pageCount < PAGE_ALLOC_INCR) ? PAGE_ALLOC_INCR : pageCount;
    CHK_MALLOC_ARRAY_ORET(newMXFFile->sysData->pages, Page, allocatedPages);
    memset(newMXFFile->sysData->pages, 0, allocatedPages * sizeof(Page));
    newMXFFile->sysData->numPages = pageCount;
    newMXFFile->sysData->numPagesAllocated = allocatedPages;
    for (pageCount = 0; pageCount < newMXFFile->sysData->numPages; pageCount++)
    {
        newMXFFile->sysData->pages[pageCount].index = pageCount;
        newMXFFile->sysData->pages[pageCount].size = pageSize;
    }

    /* set the files size of the last file, which could have size < pageSize */
    mxf_snprintf(filename, sizeof(filename), filenameTemplate, newMXFFile->sysData->numPages - 1);
    fileSize = disk_file_size(filename);
    if (fileSize < 0)
    {
        mxf_log_error("Failed to stat file '%s': %s\n", filename, strerror(errno));
        goto fail;
    }
    newMXFFile->sysData->pages[newMXFFile->sysData->numPages - 1].size = fileSize;


    *mxfPageFile = &newMXFFile->sysData->mxfPageFile;
    return 1;

fail:
    if (newMXFFile != NULL)
    {
        mxf_file_close(&newMXFFile);
    }
    return 0;
}