311 lines
7.7 KiB
C
311 lines
7.7 KiB
C
/*
|
|
* UPIWIN - Micro Pi Windowing Framework Kernel
|
|
* Copyright (C) 2019 Amy Bowersox/Erbosoft Metaverse Design Solutions
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <zip.h>
|
|
#include "wintype.h"
|
|
#include "scode.h"
|
|
#include "config.h"
|
|
#include "log.h"
|
|
#include "resources.h"
|
|
|
|
typedef struct tagRESFILE {
|
|
struct tagRESFILE *next;
|
|
struct tagRESFILE *prev;
|
|
zip_t *resource;
|
|
} RESFILE, *PRESFILE;
|
|
|
|
typedef struct tagRESOURCEINFO {
|
|
zip_t *resource_file;
|
|
zip_stat_t entryinfo;
|
|
} RESOURCEINFO, *PRESOURCEINFO;
|
|
|
|
/* conversion table from zip error codes to our HRESULT values */
|
|
static const struct tagCONVERSIONTABLE {
|
|
int zip_err_code;
|
|
HRESULT sys_err_code;
|
|
} conversion_table[] = {
|
|
{ ZIP_ER_OK, S_OK },
|
|
{ ZIP_ER_SEEK, STG_E_SEEKERROR },
|
|
{ ZIP_ER_READ, STG_E_READFAULT },
|
|
{ ZIP_ER_WRITE, STG_E_WRITEFAULT },
|
|
{ ZIP_ER_NOENT, STG_E_FILENOTFOUND },
|
|
{ ZIP_ER_MEMORY, E_OUTOFMEMORY },
|
|
{ ZIP_ER_INVAL, E_INVALIDARG },
|
|
{ ZIP_ER_INTERNAL, E_UNEXPECTED },
|
|
{ -1, 0 }
|
|
};
|
|
|
|
/* references to system resource data in zip format */
|
|
extern uint8_t _binary_sysresources_zip_start[];
|
|
extern uint8_t _binary_sysresources_zip_end;
|
|
extern uint8_t _binary_sysresources_zip_size;
|
|
|
|
static zip_t *sysresource = NULL; /* system resource file */
|
|
static PRESFILE resfiles = NULL; /* all open resource files */
|
|
|
|
static HRESULT ziperror_to_hresult(zip_error_t *errinfo)
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; conversion_table[i].zip_err_code >= 0; i++)
|
|
if (conversion_table[i].zip_err_code == errinfo->zip_err)
|
|
return conversion_table[i].sys_err_code;
|
|
return MAKE_SCODE(SEVERITY_ERROR, FACILITY_ZIP, errinfo->zip_err);
|
|
}
|
|
|
|
static BOOL check_in_list(PRESFILE presfile)
|
|
{
|
|
register PRESFILE p = resfiles;
|
|
do
|
|
{
|
|
if (p == presfile)
|
|
return TRUE;
|
|
p = p->next;
|
|
} while (p != resfiles);
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT Rsrc_load_file(PCSTR filename, PHRESFILE newhandle)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PRESFILE pfile = NULL;
|
|
zip_source_t *source;
|
|
zip_error_t errinfo;
|
|
|
|
if (!newhandle)
|
|
return E_POINTER;
|
|
*newhandle = (HRESFILE)NULL;
|
|
|
|
pfile = (PRESFILE)malloc(sizeof(RESFILE));
|
|
if (!pfile)
|
|
return E_OUTOFMEMORY;
|
|
memset(pfile, 0, sizeof(RESFILE));
|
|
|
|
zip_error_init(&errinfo);
|
|
source = zip_source_file_create(filename, 0, 0, &errinfo);
|
|
if (source)
|
|
{
|
|
pfile->resource = zip_open_from_source(source, ZIP_RDONLY, &errinfo);
|
|
if (!(pfile->resource))
|
|
zip_source_free(source);
|
|
}
|
|
if (!(pfile->resource))
|
|
hr = ziperror_to_hresult(&errinfo);
|
|
zip_error_fini(&errinfo);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (resfiles)
|
|
{
|
|
pfile->next = resfiles;
|
|
pfile->prev = resfiles->prev;
|
|
resfiles->prev->next = pfile;
|
|
resfiles->prev = pfile;
|
|
}
|
|
else
|
|
pfile->next = pfile->prev = pfile;
|
|
resfiles = pfile;
|
|
*newhandle = (HRESFILE)pfile;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT internal_close(PRESFILE presfile)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (zip_close(presfile->resource))
|
|
hr = ziperror_to_hresult(zip_get_error(presfile->resource));
|
|
if (resfiles == presfile)
|
|
{
|
|
resfiles = presfile->next;
|
|
if (resfiles == presfile)
|
|
resfiles = NULL;
|
|
}
|
|
presfile->prev->next = presfile->next;
|
|
presfile->next->prev = presfile->prev;
|
|
free(presfile);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT Rsrc_close_file(HRESFILE handle)
|
|
{
|
|
if (check_in_list((PRESFILE)handle))
|
|
return internal_close((PRESFILE)handle);
|
|
return E_HANDLE;
|
|
}
|
|
|
|
HRESULT Rsrc_find_resource(HRESFILE hfile, PCSTR name, PCSTR type, PHRSRC presource)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PRESFILE pfile = (PRESFILE)hfile;
|
|
PRESOURCEINFO info = NULL;
|
|
zip_t *theresource;
|
|
zip_int64_t index;
|
|
|
|
if (pfile)
|
|
{
|
|
if (check_in_list(pfile))
|
|
theresource = pfile->resource;
|
|
else
|
|
return E_HANDLE;
|
|
}
|
|
else
|
|
theresource = sysresource;
|
|
ASSERT(theresource);
|
|
if (!name)
|
|
return E_INVALIDARG;
|
|
if (!presource)
|
|
return E_POINTER;
|
|
*presource = (HRSRC)NULL;
|
|
|
|
index = zip_name_locate(theresource, name, ZIP_FL_NOCASE);
|
|
if (index < 0)
|
|
hr = ziperror_to_hresult(zip_get_error(theresource));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
info = (PRESOURCEINFO)malloc(sizeof(RESOURCEINFO));
|
|
if (info)
|
|
{
|
|
if (zip_stat_index(theresource, index, ZIP_FL_NOCASE, &(info->entryinfo)))
|
|
hr = ziperror_to_hresult(zip_get_error(theresource));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
info->entryinfo.index = index;
|
|
info->entryinfo.valid |= ZIP_STAT_INDEX;
|
|
info->resource_file = theresource;
|
|
*presource = (HRSRC)info;
|
|
}
|
|
if (FAILED(hr))
|
|
free(info);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT Rsrc_free_resource(HRSRC resource)
|
|
{
|
|
if (!resource)
|
|
return E_HANDLE;
|
|
free((PRESOURCEINFO)resource);
|
|
return S_OK;
|
|
}
|
|
|
|
UINT32 Rsrc_sizeof_resource(HRSRC resource)
|
|
{
|
|
PRESOURCEINFO p = (PRESOURCEINFO)resource;
|
|
if (!p)
|
|
return 0;
|
|
if (p->entryinfo.valid & ZIP_STAT_SIZE)
|
|
return (UINT32)(p->entryinfo.size);
|
|
return 0;
|
|
}
|
|
|
|
HRESULT Rsrc_read_resource_here(HRSRC resource, PVOID buffer, UINT32 size, PUINT32 actual_read)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PRESOURCEINFO p = (PRESOURCEINFO)resource;
|
|
UINT32 max_size = size;
|
|
UINT32 already_read = 0;
|
|
PBYTE pbuffer = (PBYTE)buffer;
|
|
zip_int64_t nread;
|
|
zip_file_t *fp;
|
|
|
|
if (!p)
|
|
return E_HANDLE;
|
|
if (!buffer)
|
|
return E_POINTER;
|
|
if (p->entryinfo.valid & ZIP_STAT_SIZE)
|
|
{
|
|
if ((UINT32)(p->entryinfo.size) < max_size)
|
|
max_size = (UINT32)(p->entryinfo.size);
|
|
else if ((UINT32)(p->entryinfo.size) > max_size)
|
|
hr = UPIWIN_S_PARTIALRSRC;
|
|
}
|
|
|
|
fp = zip_fopen_index(p->resource_file, p->entryinfo.index, ZIP_FL_NOCASE);
|
|
if (fp)
|
|
{
|
|
while (SUCCEEDED(hr) && (max_size > 0))
|
|
{
|
|
nread = zip_fread(fp, pbuffer, max_size);
|
|
if (nread < 0)
|
|
{
|
|
hr = ziperror_to_hresult(zip_get_error(p->resource_file));
|
|
break;
|
|
}
|
|
pbuffer += (UINT_PTR)nread;
|
|
max_size -= (UINT32)nread;
|
|
already_read += (UINT32)nread;
|
|
}
|
|
zip_fclose(fp);
|
|
}
|
|
else
|
|
hr = ziperror_to_hresult(zip_get_error(p->resource_file));
|
|
if (actual_read)
|
|
*actual_read = already_read;
|
|
return hr;
|
|
}
|
|
|
|
static void rsrc_cleanup(void)
|
|
{
|
|
while (resfiles)
|
|
internal_close(resfiles);
|
|
zip_close(sysresource);
|
|
sysresource = NULL;
|
|
}
|
|
|
|
HRESULT Rsrc_setup(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
zip_source_t *syssource;
|
|
zip_error_t errinfo;
|
|
|
|
Log(LDEBUG, "system resource length = %u", (UINT_PTR)(&_binary_sysresources_zip_size));
|
|
zip_error_init(&errinfo);
|
|
syssource = zip_source_buffer_create(_binary_sysresources_zip_start, (UINT_PTR)(&_binary_sysresources_zip_size),
|
|
0, &errinfo);
|
|
if (!syssource)
|
|
{
|
|
hr = ziperror_to_hresult(&errinfo);
|
|
goto error_0;
|
|
}
|
|
|
|
sysresource = zip_open_from_source(syssource, ZIP_RDONLY, &errinfo);
|
|
if (!sysresource)
|
|
{
|
|
hr = ziperror_to_hresult(&errinfo);
|
|
goto error_1;
|
|
}
|
|
|
|
hr = Config_exitfunc(rsrc_cleanup);
|
|
if (FAILED(hr))
|
|
rsrc_cleanup();
|
|
return hr;
|
|
|
|
error_1:
|
|
zip_source_free(syssource);
|
|
error_0:
|
|
zip_error_fini(&errinfo);
|
|
return hr;
|
|
}
|