/* * 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 #include #include #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; }