| /* |
| * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @file picoos.c |
| * |
| * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland |
| * All rights reserved. |
| * |
| * History: |
| * - 2009-04-20 -- initial version |
| * |
| */ |
| |
| #include <stdarg.h> |
| #include "picodefs.h" |
| #include "picopal.h" |
| #include "picoos.h" |
| #include "picodbg.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| #if 0 |
| } |
| #endif |
| |
| |
| #define picoos_SVOXFileHeader (picoos_char *)" (C) SVOX AG " |
| |
| /* ********************************************** |
| * default error and warning messages |
| * **********************************************/ |
| |
| |
| #define PICOOS_MSG_EXC_NUMBER_FORMAT (picoos_char *) "wrong number format" |
| #define PICOOS_MSG_EXC_MAX_NUM_EXCEED (picoos_char *) "number exceeded" |
| #define PICOOS_MSG_EXC_NAME_CONFLICT (picoos_char *) "name conflict" |
| #define PICOOS_MSG_EXC_NAME_UNDEFINED (picoos_char *) "name undefined" |
| #define PICOOS_MSG_EXC_NAME_ILLEGAL (picoos_char *) "illegal name" |
| |
| /* buffer interaction */ |
| #define PICOOS_MSG_EXC_BUF_OVERFLOW (picoos_char *) "buffer overflow" |
| #define PICOOS_MSG_EXC_BUF_UNDERFLOW (picoos_char *) "buffer underflow" |
| #define PICOOS_MSG_EXC_BUF_IGNORE (picoos_char *) "buffer error" |
| |
| /* memory allocation */ |
| #define PICOOS_MSG_EXC_OUT_OF_MEM (picoos_char *) "out of memory" |
| |
| /* files */ |
| #define PICOOS_MSG_EXC_CANT_OPEN_FILE (picoos_char *) "cannot open file" |
| #define PICOOS_MSG_EXC_UNEXPECTED_FILE_TYPE (picoos_char *) "unexpected file type" |
| #define PICOOS_MSG_EXC_FILE_CORRUPT (picoos_char *) "corrupt file" |
| #define PICOOS_MSG_EXC_FILE_NOT_FOUND (picoos_char *) "file not found" |
| |
| /* resources */ |
| #define PICOOS_MSG_EXC_RESOURCE_BUSY (picoos_char *) "resource is busy" |
| #define PICOOS_MSG_EXC_RESOURCE_MISSING (picoos_char *) "cannot find resource" |
| |
| /* knowledge bases */ |
| #define PICOOS_MSG_EXC_KB_MISSING (picoos_char *) "knowledge base missing" |
| |
| /* runtime exceptions (programming problems, usually a bug. E.g. trying to access null pointer) */ |
| #define PICOOS_MSG_ERR_NULLPTR_ACCESS (picoos_char *) "access violation" |
| #define PICOOS_MSG_ERR_INVALID_HANDLE (picoos_char *) "invalid handle value" |
| #define PICOOS_MSG_ERR_INVALID_ARGUMENT (picoos_char *) "invalid argument supplied" |
| #define PICOOS_MSG_ERR_INDEX_OUT_OF_RANGE (picoos_char *) "index out of range" |
| |
| |
| /* errors ("external" errors, e.g. hardware failure. Usually cannot be dealt with from inside pico.) */ |
| #define PICOOS_MSG_ERR_OTHER (picoos_char *) "other error" |
| |
| #define PICOOS_MSG_ERR_PU (picoos_char *) "error in processing unit" |
| |
| /* WARNINGS */ |
| |
| /* general */ |
| #define PICOOS_MSG_WARN_INCOMPLETE (picoos_char *) "incomplete output" |
| #define PICOOS_MSG_WARN_FALLBACK (picoos_char *) "using fall-back" |
| #define PICOOS_MSG_WARN_OTHER (picoos_char *) "other warning" |
| |
| /* resources */ |
| #define PICOOS_MSG_WARN_KB_OVERWRITE (picoos_char *) "overwriting knowledge base" |
| #define PICOOS_MSG_WARN_RESOURCE_DOUBLE_LOAD (picoos_char *) "resource already loaded" |
| |
| /* decision trees */ |
| #define PICOOS_MSG_WARN_INVECTOR (picoos_char *) "input vector not constructed" |
| #define PICOOS_MSG_WARN_CLASSIFICATION (picoos_char *) "output not classified" |
| #define PICOOS_MSG_WARN_OUTVECTOR (picoos_char *) "output vector not decomposed" |
| |
| /* processing units */ |
| #define PICOOS_MSG_WARN_PU_IRREG_ITEM (picoos_char *) "irregular item in processing unit" |
| #define PICOOS_MSG_WARN_PU_DISCARD_BUF (picoos_char *) "discarding processing unit buffer" |
| |
| |
| /* ********************************************** |
| * wrappers for picopal functions |
| * **********************************************/ |
| |
| picoos_int32 picoos_atoi(const picoos_char *s) |
| { |
| return (picoos_int32)picopal_atoi((const picoos_char *)s); |
| } |
| |
| |
| picoos_int8 picoos_strcmp(const picoos_char *a, const picoos_char *b) |
| { |
| picopal_int32 res = picopal_strcmp((const picopal_char *)a, |
| (const picopal_char *)b); |
| return (picoos_int8) ((res < 0) ? -1 : (res > 0) ? 1 : 0); |
| } |
| picoos_int8 picoos_strncmp(const picoos_char *a, const picoos_char *b, picoos_objsize_t siz) |
| { |
| picopal_int32 res = picopal_strncmp((const picopal_char *)a, |
| (const picopal_char *)b, siz); |
| return (picoos_int8) ((res < 0) ? -1 : (res > 0) ? 1 : 0); |
| } |
| |
| picoos_uint32 picoos_strlen(const picoos_char *s) |
| { |
| return (picoos_uint32)picopal_strlen((const picopal_char *)s); |
| } |
| |
| picoos_char *picoos_strchr(const picoos_char *s, picoos_char c) |
| { |
| return (picoos_char *)picopal_strchr((const picopal_char *)s, |
| (picopal_char)c); |
| } |
| |
| picoos_char *picoos_strstr(const picoos_char *s, const picoos_char * substr) |
| { |
| return (picoos_char *)picopal_strstr((const picopal_char *)s, |
| (const picopal_char *)substr); |
| } |
| |
| picoos_int16 picoos_slprintf(picoos_char * b, picoos_uint32 bsize, const picoos_char *f, ...) |
| { |
| picopal_int16 i; |
| va_list args; |
| |
| va_start(args, (char *)f); |
| i = (picoos_int16)picopal_vslprintf((picoos_char *) b, bsize, (const picoos_char *)f, args); |
| va_end(args); |
| return i; |
| } |
| |
| picoos_char *picoos_strcpy(picoos_char *d, const picoos_char *s) |
| { |
| return (picoos_char *)picopal_strcpy((picopal_char *)d, |
| (const picopal_char *)s); |
| } |
| |
| picoos_char *picoos_strcat(picoos_char *d, const picoos_char *s) |
| { |
| return (picoos_char *)picopal_strcat((picopal_char *)d, |
| (const picopal_char *)s); |
| } |
| |
| picoos_objsize_t picoos_strlcpy(picoos_char *dst, const picoos_char *src, picoos_objsize_t siz) |
| { |
| return (picoos_objsize_t) picopal_strlcpy((picopal_char *) dst, (const picopal_char *) src, (picopal_objsize_t) siz); |
| } |
| |
| /* copies 'length' bytes from 'src' to 'dest'. (regions may be overlapping) no error checks! */ |
| void * picoos_mem_copy(const void * src, void * dst, picoos_objsize_t length) |
| { |
| return picopal_mem_copy(src,dst,(picopal_objsize_t) length); |
| } |
| |
| /* sets 'length' bytes starting at dest[0] to 'byte_val' */ |
| void * picoos_mem_set(void * dest, picoos_uint8 byte_val, picoos_objsize_t length) { |
| return picopal_mem_set(dest,(picopal_uint8)byte_val, (picopal_objsize_t)length); |
| } |
| |
| |
| picoos_double picoos_cos (const picoos_double cos_arg) |
| { |
| return (picoos_double) picopal_cos ((picopal_double) cos_arg); |
| } |
| |
| |
| picoos_double picoos_sin (const picoos_double sin_arg) |
| { |
| return (picoos_double) picopal_sin((picopal_double) sin_arg); |
| } |
| picoos_double picoos_fabs (const picoos_double fabs_arg) |
| { |
| return (picoos_double) picopal_fabs((picopal_double) fabs_arg); |
| } |
| |
| picoos_double picoos_quick_exp(const picoos_double y) { |
| return (picoos_double) picopal_quick_exp ((picopal_double)y); |
| } |
| |
| |
| /* *****************************************************************/ |
| /* "Common" */ |
| /* *****************************************************************/ |
| /* picoos_common is a collection of basic functionalities that must be globally |
| * accessible from every "big" function. It includes pointers to the MemoryManasger, |
| * ExceptionManager and a system-wide list of open files. */ |
| |
| picoos_Common picoos_newCommon(picoos_MemoryManager mm) |
| { |
| picoos_Common this = (picoos_Common) picoos_allocate(mm,sizeof(*this)); |
| if (NULL != this) { |
| /* initialize */ |
| this->em = NULL; |
| this->mm = NULL; |
| this->fileList = NULL; |
| } |
| return this; |
| } |
| |
| void picoos_disposeCommon(picoos_MemoryManager mm, picoos_Common * this) |
| { |
| if (NULL != (*this)) { |
| /* terminate */ |
| picoos_deallocate(mm,(void *)this); |
| } |
| } |
| |
| |
| /* *****************************************************************/ |
| /* Memory Management */ |
| /* *****************************************************************/ |
| |
| typedef struct mem_block_hdr * MemBlockHdr; |
| typedef struct mem_block_hdr |
| { |
| MemBlockHdr next; |
| byte_ptr_t data; |
| picoos_objsize_t size; |
| } mem_block_hdr_t; |
| |
| typedef struct mem_cell_hdr * MemCellHdr; |
| typedef struct mem_cell_hdr |
| { |
| /* size may be <0 if used */ |
| picoos_ptrdiff_t size; |
| MemCellHdr leftCell; |
| MemCellHdr prevFree, nextFree; |
| } mem_cell_hdr_t; |
| |
| typedef struct memory_manager |
| { |
| MemBlockHdr firstBlock, lastBlock; /* memory blockList */ |
| MemCellHdr freeCells, lastFree; /* free memory cells (first/last sentinel */ |
| /* "constants" */ |
| picoos_objsize_t fullCellHdrSize; /* aligned size of full cell header, including free-links */ |
| picoos_objsize_t usedCellHdrSize; /* aligned size of header part without free-links */ |
| picoos_objsize_t minContSize; /* minimum requestable application content size for allocation; |
| must hold free-list info; = fullCellHdrSize-usedCellHdrSize */ |
| picoos_objsize_t minCellSize; /* minimum remaining cell size when a free cell is split */ |
| picoos_bool protMem; /* true if memory protection is enabled */ |
| picoos_ptrdiff_t usedSize; |
| picoos_ptrdiff_t prevUsedSize; |
| picoos_ptrdiff_t maxUsedSize; |
| } memory_manager_t; |
| |
| /** allocates 'alloc_size' bytes at start of raw memory block ('raw_mem',raw_mem_size) |
| * and returns pointer to allocated region. Returns remaining (correctly aligned) raw memory block |
| * in ('rest_mem','rest_mem_size'). |
| * The allocated memory is not subject to memory management, so that it can never be freed again! |
| * |
| */ |
| void * picoos_raw_malloc(byte_ptr_t raw_mem, |
| picoos_objsize_t raw_mem_size, picoos_objsize_t alloc_size, |
| byte_ptr_t * rest_mem, picoos_objsize_t * rest_mem_size) |
| { |
| picoos_ptrdiff_t rest; |
| if (raw_mem == NULL) { |
| return NULL; |
| } else { |
| if (alloc_size < 1) { |
| alloc_size = 1; |
| } |
| alloc_size = ((alloc_size + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE) |
| * PICOOS_ALIGN_SIZE; |
| |
| rest = raw_mem_size - alloc_size; |
| if (rest < 0) { |
| return NULL; |
| } else { |
| *rest_mem_size = rest; |
| *rest_mem = raw_mem + alloc_size; |
| return (void *) raw_mem; |
| } |
| } |
| } |
| |
| /** initializes the last block of mm */ |
| static int os_init_mem_block(picoos_MemoryManager this) |
| { |
| int isFirstBlock; |
| void * newBlockAddr; |
| picoos_objsize_t size; |
| MemCellHdr cbeg, cmid, cend; |
| |
| isFirstBlock = (this->freeCells == NULL); |
| newBlockAddr = (void *) this->lastBlock->data; |
| size = this->lastBlock->size; |
| cbeg = (MemCellHdr) newBlockAddr; |
| cmid = (MemCellHdr)((picoos_objsize_t)newBlockAddr + this->fullCellHdrSize); |
| cend = (MemCellHdr)((picoos_objsize_t)newBlockAddr + size |
| - this->fullCellHdrSize); |
| cbeg->size = 0; |
| |
| cbeg->leftCell = NULL; |
| cmid->size = size - 2 * this->fullCellHdrSize; |
| cmid->leftCell = cbeg; |
| cend->size = 0; |
| cend->leftCell = cmid; |
| if (isFirstBlock) { |
| cbeg->nextFree = cmid; |
| cbeg->prevFree = NULL; |
| cmid->nextFree = cend; |
| cmid->prevFree = cbeg; |
| cend->nextFree = NULL; |
| cend->prevFree = cmid; |
| this->freeCells = cbeg; |
| this->lastFree = cend; |
| } else { |
| /* add cmid to free cell list */ |
| cbeg->nextFree = NULL; |
| cbeg->prevFree = NULL; |
| cmid->nextFree = this->freeCells->nextFree; |
| cmid->prevFree = this->freeCells; |
| cmid->nextFree->prevFree = cmid; |
| cmid->prevFree->nextFree = cmid; |
| cend->nextFree = NULL; |
| cbeg->prevFree = NULL; |
| } |
| return PICO_OK; |
| } |
| |
| |
| picoos_MemoryManager picoos_newMemoryManager( |
| void *raw_memory, |
| picoos_objsize_t size, |
| picoos_bool enableMemProt) |
| { |
| byte_ptr_t rest_mem; |
| picoos_objsize_t rest_mem_size; |
| picoos_MemoryManager this; |
| picoos_objsize_t size2; |
| mem_cell_hdr_t test_cell; |
| |
| this = picoos_raw_malloc(raw_memory, size, sizeof(memory_manager_t), |
| &rest_mem, &rest_mem_size); |
| if (this == NULL) { |
| return NULL; |
| } |
| |
| /* test if memory protection functionality is available on the current |
| platform (if not, picopal_mpr_alloc() always returns NULL) */ |
| if (enableMemProt) { |
| void *addr = picopal_mpr_alloc(100); |
| if (addr == NULL) { |
| enableMemProt = FALSE; |
| } else { |
| picopal_mpr_free(&addr); |
| } |
| } |
| |
| this->firstBlock = NULL; |
| this->lastBlock = NULL; |
| this->freeCells = NULL; |
| this->lastFree = NULL; |
| |
| this->protMem = enableMemProt; |
| this->usedSize = 0; |
| this->prevUsedSize = 0; |
| this->maxUsedSize = 0; |
| |
| /* get aligned full header size */ |
| this->fullCellHdrSize = ((sizeof(mem_cell_hdr_t) + PICOOS_ALIGN_SIZE - 1) |
| / PICOOS_ALIGN_SIZE) * PICOOS_ALIGN_SIZE; |
| /* get aligned size of header without free-list fields; the result may be compiler-dependent; |
| the size is therefore computed by inspecting the end addresses of the fields 'size' and 'leftCell'; |
| the higher of the ending addresses is used to get the (aligned) starting address |
| of the application contents */ |
| this->usedCellHdrSize = (picoos_objsize_t) &test_cell.size |
| - (picoos_objsize_t) &test_cell + sizeof(picoos_objsize_t); |
| size2 = (picoos_objsize_t) &test_cell.leftCell - (picoos_objsize_t) |
| &test_cell + sizeof(MemCellHdr); |
| if (size2 > this->usedCellHdrSize) { |
| this->usedCellHdrSize = size2; |
| } |
| /* get minimum application-usable size; must be large enough to hold remainder of |
| cell header (free-list links) when in free-list */ |
| this->minContSize = this->fullCellHdrSize - this->usedCellHdrSize; |
| /* get minimum required size of a cell remaining after a cell split */ |
| this->minCellSize = this->fullCellHdrSize + PICOOS_ALIGN_SIZE; |
| |
| /* install remainder of raw memory block as first block */ |
| raw_memory = rest_mem; |
| size = rest_mem_size; |
| this->firstBlock = this->lastBlock = picoos_raw_malloc(raw_memory, size, |
| sizeof(mem_block_hdr_t), &rest_mem, &rest_mem_size); |
| if (this->lastBlock == NULL) { |
| return NULL; |
| } |
| this->lastBlock->next = NULL; |
| this->lastBlock->data = rest_mem; |
| this->lastBlock->size = rest_mem_size; |
| |
| os_init_mem_block(this); |
| |
| return this; |
| } |
| |
| void picoos_disposeMemoryManager(picoos_MemoryManager * mm) |
| { |
| *mm = NULL; |
| } |
| |
| |
| /* the following memory manager routines are for testing and |
| debugging purposes */ |
| |
| |
| void *picoos_allocProtMem(picoos_MemoryManager mm, picoos_objsize_t byteSize) |
| { |
| if (mm->protMem) { |
| return picopal_mpr_alloc(byteSize); |
| } else { |
| return picoos_allocate(mm, byteSize); |
| } |
| } |
| |
| |
| void picoos_deallocProtMem(picoos_MemoryManager mm, void **addr) |
| { |
| if (mm->protMem) { |
| picopal_mpr_free(addr); |
| } else { |
| picoos_deallocate(mm, addr); |
| } |
| } |
| |
| |
| void picoos_protectMem( |
| picoos_MemoryManager mm, |
| void *addr, |
| picoos_objsize_t len, |
| picoos_bool enable) |
| { |
| if (mm->protMem) { |
| int prot = PICOPAL_PROT_READ; |
| if (!enable) { |
| prot |= PICOPAL_PROT_WRITE; |
| } |
| picopal_mpr_protect(addr, len, prot); |
| } else { |
| /* memory protection disabled; nothing to do */ |
| } |
| } |
| |
| #define PICOPAL_PROT_NONE 0 /* the memory cannot be accessed at all */ |
| #define PICOPAL_PROT_READ 1 /* the memory can be read */ |
| #define PICOPAL_PROT_WRITE 2 /* the memory can be written to */ |
| |
| void picoos_getMemUsage( |
| picoos_MemoryManager this, |
| picoos_bool resetIncremental, |
| picoos_int32 *usedBytes, |
| picoos_int32 *incrUsedBytes, |
| picoos_int32 *maxUsedBytes) |
| { |
| *usedBytes = (picoos_int32) this->usedSize; |
| *incrUsedBytes = (picoos_int32) (this->usedSize - this->prevUsedSize); |
| *maxUsedBytes = (picoos_int32) this->maxUsedSize; |
| if (resetIncremental) { |
| this->prevUsedSize = this->usedSize; |
| } |
| } |
| |
| |
| void picoos_showMemUsage(picoos_MemoryManager this, picoos_bool incremental, |
| picoos_bool resetIncremental) |
| { |
| picoos_int32 usedBytes, incrUsedBytes, maxUsedBytes; |
| |
| picoos_getMemUsage(this, resetIncremental, &usedBytes, &incrUsedBytes, |
| &maxUsedBytes); |
| if (incremental) { |
| PICODBG_DEBUG(("additional memory used: %d", incrUsedBytes)); |
| } else { |
| PICODBG_DEBUG(("memory used: %d, maximally used: %d", usedBytes, maxUsedBytes)); |
| } |
| } |
| |
| |
| void * picoos_allocate(picoos_MemoryManager this, |
| picoos_objsize_t byteSize) |
| { |
| |
| picoos_objsize_t cellSize; |
| MemCellHdr c, c2, c2r; |
| void * adr; |
| |
| if (byteSize < this->minContSize) { |
| byteSize = this->minContSize; |
| } |
| byteSize = ((byteSize + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE) |
| * PICOOS_ALIGN_SIZE; |
| |
| cellSize = byteSize + this->usedCellHdrSize; |
| /*PICODBG_TRACE(("allocating %d", cellSize));*/ |
| c = this->freeCells->nextFree; |
| while ( |
| (c != NULL) && |
| (c->size != (picoos_ptrdiff_t) cellSize) && |
| (c->size < (picoos_ptrdiff_t)(cellSize+ this->minCellSize))) { |
| c = c->nextFree; |
| } |
| if (c == NULL) { |
| return NULL; |
| } |
| if ((c->size == (picoos_ptrdiff_t) cellSize)) { |
| c->prevFree->nextFree = c->nextFree; |
| c->nextFree->prevFree = c->prevFree; |
| } else { |
| c2 = (MemCellHdr)((picoos_objsize_t)c + cellSize); |
| c2->size = c->size - cellSize; |
| c->size = cellSize; |
| c2->leftCell = c; |
| c2r = (MemCellHdr)((picoos_objsize_t)c2 + c2->size); |
| c2r->leftCell = c2; |
| c2->nextFree = c->nextFree; |
| c2->nextFree->prevFree = c2; |
| c2->prevFree = c->prevFree; |
| c2->prevFree->nextFree = c2; |
| } |
| |
| /* statistics */ |
| this->usedSize += cellSize; |
| if (this->usedSize > this->maxUsedSize) { |
| this->maxUsedSize = this->usedSize; |
| } |
| |
| c->size = -(c->size); |
| adr = (void *)((picoos_objsize_t)c + this->usedCellHdrSize); |
| return adr; |
| } |
| |
| void picoos_deallocate(picoos_MemoryManager this, void * * adr) |
| { |
| MemCellHdr c; |
| MemCellHdr cr; |
| MemCellHdr cl; |
| MemCellHdr crr; |
| |
| |
| if ((*adr) != NULL) { |
| c = (MemCellHdr)((picoos_objsize_t)(*adr) - this->usedCellHdrSize); |
| c->size = -(c->size); |
| |
| /*PICODBG_TRACE(("deallocating %d", c->size));*/ |
| /* statistics */ |
| this->usedSize -= c->size; |
| |
| cr = (MemCellHdr)((picoos_objsize_t)c + c->size); |
| cl = c->leftCell; |
| if (cl->size > 0) { |
| if (cr->size > 0) { |
| crr = (MemCellHdr)((picoos_objsize_t)cr + cr->size); |
| crr->leftCell = cl; |
| cl->size = ((cl->size + c->size) + cr->size); |
| cr->nextFree->prevFree = cr->prevFree; |
| cr->prevFree->nextFree = cr->nextFree; |
| } else { |
| cl->size = (cl->size + c->size); |
| cr->leftCell = cl; |
| } |
| } else { |
| if ((cr->size > 0)) { |
| crr = (MemCellHdr)((picoos_objsize_t)cr + cr->size); |
| crr->leftCell = c; |
| c->size = (c->size + cr->size); |
| c->nextFree = cr->nextFree; |
| c->prevFree = cr->prevFree; |
| c->nextFree->prevFree = c; |
| c->prevFree->nextFree = c; |
| } else { |
| c->nextFree = this->freeCells->nextFree; |
| c->prevFree = this->freeCells; |
| c->nextFree->prevFree = c; |
| c->prevFree->nextFree = c; |
| } |
| } |
| } |
| *adr = NULL; |
| } |
| |
| /* *****************************************************************/ |
| /* Exception Management */ |
| /* *****************************************************************/ |
| /** object : exceptionManager |
| * shortcut : em |
| * |
| */ |
| |
| typedef picoos_char picoos_exc_msg[PICOOS_MAX_EXC_MSG_LEN]; |
| typedef picoos_char picoos_warn_msg[PICOOS_MAX_WARN_MSG_LEN]; |
| |
| typedef struct picoos_exception_manager |
| { |
| picoos_int32 curExceptionCode; |
| picoos_exc_msg curExceptionMessage; |
| |
| picoos_uint8 curNumWarnings; |
| picoos_int32 curWarningCode[PICOOS_MAX_NUM_WARNINGS]; |
| picoos_warn_msg curWarningMessage[PICOOS_MAX_NUM_WARNINGS]; |
| |
| } picoos_exception_manager_t; |
| |
| void picoos_emReset(picoos_ExceptionManager this) |
| { |
| this->curExceptionCode = PICO_OK; |
| this->curExceptionMessage[0] = '\0'; |
| this->curNumWarnings = 0; |
| } |
| |
| picoos_ExceptionManager picoos_newExceptionManager(picoos_MemoryManager mm) |
| { |
| picoos_ExceptionManager this = (picoos_ExceptionManager) picoos_allocate( |
| mm, sizeof(*this)); |
| if (NULL != this) { |
| /* initialize */ |
| picoos_emReset(this); |
| } |
| return this; |
| } |
| |
| void picoos_disposeExceptionManager(picoos_MemoryManager mm, |
| picoos_ExceptionManager * this) |
| { |
| if (NULL != (*this)) { |
| /* terminate */ |
| picoos_deallocate(mm, (void *)this); |
| } |
| } |
| |
| static void picoos_vSetErrorMsg(picoos_char * dst, picoos_objsize_t siz, |
| picoos_int16 code, picoos_char * base, const picoos_char *fmt, va_list args) |
| { |
| picoos_uint16 bsize; |
| |
| if (NULL == base) { |
| switch (code) { |
| case PICO_EXC_NUMBER_FORMAT: |
| base = PICOOS_MSG_EXC_NUMBER_FORMAT; |
| break; |
| case PICO_EXC_MAX_NUM_EXCEED: |
| base = PICOOS_MSG_EXC_MAX_NUM_EXCEED; |
| break; |
| case PICO_EXC_NAME_CONFLICT: |
| base = PICOOS_MSG_EXC_NAME_CONFLICT; |
| break; |
| case PICO_EXC_NAME_UNDEFINED: |
| base = PICOOS_MSG_EXC_NAME_UNDEFINED; |
| break; |
| case PICO_EXC_NAME_ILLEGAL: |
| base = PICOOS_MSG_EXC_NAME_ILLEGAL; |
| break; |
| |
| /* buffer interaction */ |
| case PICO_EXC_BUF_OVERFLOW: |
| base = PICOOS_MSG_EXC_BUF_OVERFLOW; |
| break; |
| case PICO_EXC_BUF_UNDERFLOW: |
| base = PICOOS_MSG_EXC_BUF_UNDERFLOW; |
| break; |
| case PICO_EXC_BUF_IGNORE: |
| base = PICOOS_MSG_EXC_BUF_IGNORE; |
| break; |
| |
| /* memory allocation */ |
| case PICO_EXC_OUT_OF_MEM: |
| base = PICOOS_MSG_EXC_OUT_OF_MEM; |
| break; |
| |
| /* files */ |
| case PICO_EXC_CANT_OPEN_FILE: |
| base = PICOOS_MSG_EXC_CANT_OPEN_FILE; |
| break; |
| case PICO_EXC_UNEXPECTED_FILE_TYPE: |
| base = PICOOS_MSG_EXC_UNEXPECTED_FILE_TYPE; |
| break; |
| case PICO_EXC_FILE_CORRUPT: |
| base = PICOOS_MSG_EXC_FILE_CORRUPT; |
| break; |
| |
| case PICO_EXC_FILE_NOT_FOUND: |
| base = PICOOS_MSG_EXC_FILE_NOT_FOUND; |
| break; |
| |
| /* resources */ |
| case PICO_EXC_RESOURCE_BUSY: |
| base = PICOOS_MSG_EXC_RESOURCE_BUSY; |
| break; |
| case PICO_EXC_RESOURCE_MISSING: |
| base = PICOOS_MSG_EXC_RESOURCE_MISSING; |
| break; |
| |
| /* knowledge bases */ |
| case PICO_EXC_KB_MISSING: |
| fmt = PICOOS_MSG_EXC_KB_MISSING; |
| break; |
| |
| /* runtime exceptions (programming problems, usually a bug. E.g. trying to access null pointer) */ |
| case PICO_ERR_NULLPTR_ACCESS: |
| base = PICOOS_MSG_ERR_NULLPTR_ACCESS; |
| break; |
| case PICO_ERR_INVALID_HANDLE: |
| base = PICOOS_MSG_ERR_INVALID_HANDLE; |
| break; |
| case PICO_ERR_INVALID_ARGUMENT: |
| base = PICOOS_MSG_ERR_INVALID_ARGUMENT; |
| break; |
| case PICO_ERR_INDEX_OUT_OF_RANGE: |
| base = PICOOS_MSG_ERR_INDEX_OUT_OF_RANGE; |
| break; |
| |
| /* errors ("external" errors, e.g. hardware failure. Usually cannot be dealt with from inside pico.) */ |
| case PICO_ERR_OTHER: |
| base = PICOOS_MSG_ERR_OTHER; |
| break; |
| |
| /* other error inside pu */ |
| case PICO_STEP_ERROR: |
| base = PICOOS_MSG_ERR_PU; |
| break; |
| |
| /* WARNINGS */ |
| |
| /* general */ |
| case PICO_WARN_INCOMPLETE: |
| base = PICOOS_MSG_WARN_INCOMPLETE; |
| break; |
| case PICO_WARN_FALLBACK: |
| base = PICOOS_MSG_WARN_FALLBACK; |
| break; |
| |
| case PICO_WARN_OTHER: |
| base = PICOOS_MSG_WARN_OTHER; |
| break; |
| |
| /* resources */ |
| case PICO_WARN_KB_OVERWRITE: |
| base = PICOOS_MSG_WARN_KB_OVERWRITE; |
| break; |
| case PICO_WARN_RESOURCE_DOUBLE_LOAD: |
| base = PICOOS_MSG_WARN_RESOURCE_DOUBLE_LOAD; |
| break; |
| |
| /* decision trees */ |
| case PICO_WARN_INVECTOR: |
| base = PICOOS_MSG_WARN_INVECTOR; |
| break; |
| case PICO_WARN_CLASSIFICATION: |
| base = PICOOS_MSG_WARN_CLASSIFICATION; |
| break; |
| case PICO_WARN_OUTVECTOR: |
| base = PICOOS_MSG_WARN_OUTVECTOR; |
| break; |
| |
| /* processing units */ |
| case PICO_WARN_PU_IRREG_ITEM: |
| base = PICOOS_MSG_WARN_PU_IRREG_ITEM; |
| break; |
| case PICO_WARN_PU_DISCARD_BUF: |
| base = PICOOS_MSG_WARN_PU_DISCARD_BUF; |
| break; |
| |
| default: |
| base = (picoos_char *) "unknown error"; |
| break; |
| } |
| } |
| bsize = picoos_strlcpy(dst,base,siz); |
| if ((NULL != fmt) && (bsize < siz)) { /* there is something to add and more space to add it */ |
| if (bsize > 0) { |
| dst += bsize; |
| siz -= bsize; |
| bsize = picoos_strlcpy(dst,(picoos_char *)": ",siz); |
| } |
| if (bsize < siz) { |
| picopal_vslprintf((picopal_char *) dst + bsize, siz - bsize, (picopal_char *)fmt, args); |
| } |
| } |
| } |
| |
| void picoos_setErrorMsg(picoos_char * dst, picoos_objsize_t siz, |
| picoos_int16 code, picoos_char * base, const picoos_char *fmt, ...) |
| { |
| va_list args; |
| va_start(args, (char *)fmt); |
| picoos_vSetErrorMsg(dst,siz, code, base, fmt,args); |
| va_end(args); |
| } |
| |
| /* For convenience, this function returns the resulting current exception code. The return value therefore is NOT the status of raising |
| * the error! */ |
| pico_status_t picoos_emRaiseException(picoos_ExceptionManager this, |
| pico_status_t exceptionCode, picoos_char * baseMessage, picoos_char * fmt, ...) |
| { |
| va_list args; |
| |
| |
| if (PICO_OK == this->curExceptionCode && PICO_OK != exceptionCode) { |
| this->curExceptionCode = exceptionCode; |
| va_start(args, (char *)fmt); |
| picoos_vSetErrorMsg(this->curExceptionMessage,PICOOS_MAX_EXC_MSG_LEN, exceptionCode, baseMessage, fmt,args); |
| PICODBG_DEBUG(( |
| "exit with exception code=%i, exception message='%s'", |
| this->curExceptionCode, this->curExceptionMessage)); |
| |
| va_end(args); |
| |
| } |
| return this->curExceptionCode; |
| } |
| |
| pico_status_t picoos_emGetExceptionCode(picoos_ExceptionManager this) |
| { |
| return this->curExceptionCode; |
| } |
| |
| void picoos_emGetExceptionMessage(picoos_ExceptionManager this, picoos_char * msg, picoos_uint16 maxsize) |
| { |
| picoos_strlcpy(msg,this->curExceptionMessage,maxsize); |
| } |
| |
| void picoos_emRaiseWarning(picoos_ExceptionManager this, |
| pico_status_t warningCode, picoos_char * baseMessage, picoos_char * fmt, ...) |
| { |
| va_list args; |
| if ((this->curNumWarnings < PICOOS_MAX_NUM_WARNINGS) && (PICO_OK != warningCode)) { |
| if (PICOOS_MAX_NUM_WARNINGS-1 == this->curNumWarnings) { |
| this->curWarningCode[this->curNumWarnings] = PICO_EXC_MAX_NUM_EXCEED; |
| picoos_strlcpy(this->curWarningMessage[this->curNumWarnings],(picoos_char *) "too many warnings",PICOOS_MAX_WARN_MSG_LEN); |
| } else { |
| this->curWarningCode[this->curNumWarnings] = warningCode; |
| va_start(args, (char *)fmt); |
| picoos_vSetErrorMsg(this->curWarningMessage[this->curNumWarnings],PICOOS_MAX_WARN_MSG_LEN, warningCode, baseMessage, fmt,args); |
| va_end(args); |
| } |
| this->curNumWarnings++; |
| } |
| PICODBG_DEBUG(( |
| "exit with code=%i and message='%s', resulting in #warnings=%i", |
| this->curWarningCode[this->curNumWarnings-1], |
| this->curWarningMessage[this->curNumWarnings-1], |
| this->curNumWarnings)); |
| } |
| |
| picoos_uint8 picoos_emGetNumOfWarnings(picoos_ExceptionManager this) |
| { |
| return this->curNumWarnings; |
| } |
| |
| pico_status_t picoos_emGetWarningCode(picoos_ExceptionManager this, picoos_uint8 index) |
| { |
| if (index < this->curNumWarnings) { |
| return this->curWarningCode[index]; |
| } else { |
| return PICO_OK; |
| } |
| } |
| |
| void picoos_emGetWarningMessage(picoos_ExceptionManager this, picoos_uint8 index, picoos_char * msg, picoos_uint16 maxsize) |
| { |
| if (index < this->curNumWarnings) { |
| picoos_strlcpy(msg,this->curWarningMessage[index],maxsize); |
| } else { |
| msg[0] = NULLC; |
| } |
| } |
| |
| |
| |
| |
| /* *****************************************************************/ |
| /* File Access */ |
| /* *****************************************************************/ |
| |
| #define picoos_MagicNumber 192837465 |
| #define picoos_MaxBufSize 1000000 |
| #define picoos_MaxNrOfBuffers 1000000 |
| #define picoos_MaxBufLen 8192 |
| #define picoos_HashFuncId0 0 |
| #define picoos_HashTableSize0 101 |
| #define picoos_HashTableSize1 1731 |
| #define picoos_MaxHashTableSize HashTableSize1 |
| |
| #define cardinal_ptr_t picoos_uint32 * |
| |
| typedef struct picoos_buffer |
| { |
| picoos_char * data; |
| int start; /* denotes the file position of the buffer beginning */ |
| int len; /* denotes the length of the buffer; -1 means invalid buffer */ |
| int pos; /* denotes the position in the buffer */ |
| } picoos_buffer_t; |
| |
| typedef picoos_buffer_t picoos_buffer_array_t[picoos_MaxNrOfBuffers]; |
| typedef picoos_int32 picoos_buffer_index_array_t[picoos_MaxNrOfBuffers]; |
| |
| /** object : File |
| * shortcut : f |
| * |
| */ |
| typedef struct picoos_file |
| { |
| picoos_FileName name; |
| picoos_uint8 binary; |
| picoos_uint8 write; |
| |
| picopal_File nf; |
| |
| picoos_uint32 lFileLen; |
| picoos_uint32 lPos; |
| |
| picoos_File next; |
| picoos_File prev; |
| |
| } picoos_file_t; |
| |
| picoos_File picoos_newFile(picoos_MemoryManager mm) |
| { |
| picoos_File this = (picoos_File) picoos_allocate(mm, sizeof(*this)); |
| if (NULL != this) { |
| /* initialize */ |
| } |
| return this; |
| } |
| |
| void picoos_disposeFile(picoos_MemoryManager mm, picoos_File * this) |
| { |
| if (NULL != (*this)) { |
| /* terminate */ |
| picoos_deallocate(mm, (void *)this); |
| } |
| } |
| |
| |
| /* ************************************************************ |
| * low-level file operations |
| **************************************************************/ |
| |
| static picoos_int32 os_min(const picoos_int32 x, const picoos_int32 y) |
| { |
| return (x < y) ? x : y; |
| } |
| |
| /* |
| static picoos_uint8 LReadChar (picoos_File f, picoos_char * ch); |
| |
| |
| static picoos_uint8 LSetPos (picoos_File f, unsigned int pos); |
| |
| |
| static picoos_uint8 LGetPos (picoos_File f, picoos_uint32 * pos); |
| |
| |
| static picoos_uint8 LEof (picoos_File f); |
| */ |
| |
| static picoos_bool LOpen(picoos_Common g, picoos_File * f, |
| picoos_char fileName[], picopal_access_mode mode) |
| { |
| picoos_bool done = TRUE; |
| |
| *f = picoos_newFile(g->mm); |
| picopal_strcpy((*f)->name, fileName); |
| (*f)->write = ((mode == PICOPAL_TEXT_WRITE) || (mode |
| == PICOPAL_BINARY_WRITE)); |
| (*f)->binary = (mode |
| == PICOPAL_BINARY_WRITE); |
| (*f)->next = NULL; |
| (*f)->prev = NULL; |
| (*f)->nf = picopal_get_fnil(); |
| (*f)->lFileLen = 0; |
| (*f)->lPos = 0; |
| if (picopal_strlen((*f)->name)) { |
| (*f)->nf = picopal_fopen((*f)->name, mode); |
| done = !(picopal_is_fnil((*f)->nf)); |
| if (done) { |
| (*f)->lFileLen = picopal_flength((*f)->nf); |
| } |
| } |
| if (done) { |
| (*f)->next = g->fileList; |
| if (g->fileList != NULL) { |
| g->fileList->prev = (*f); |
| } |
| g->fileList = (*f); |
| } else { |
| picoos_disposeFile(g->mm, f); |
| (*f) = NULL; |
| } |
| return done; |
| } |
| |
| static picoos_bool LClose(picoos_Common g, picoos_File * f) |
| { |
| |
| picoos_bool done; |
| |
| if (((*f) != NULL)) { |
| done = (PICO_OK == picopal_fclose((*f)->nf)); |
| if (((*f)->next != NULL)) { |
| (*f)->next->prev = (*f)->prev; |
| } |
| if (((*f)->prev != NULL)) { |
| (*f)->prev->next = (*f)->next; |
| } else { |
| g->fileList = (*f)->next; |
| } |
| picoos_disposeFile(g->mm, f); |
| |
| done = TRUE; |
| } else { |
| done = FALSE; |
| } |
| return done; |
| |
| } |
| |
| /* caller must ensure that bytes[] has at least len allocated bytes */ |
| static picoos_bool LReadBytes(picoos_File f, picoos_uint8 bytes[], |
| picoos_uint32 * len) |
| { |
| picoos_bool done; |
| picoos_int32 res; |
| |
| PICODBG_TRACE(("trying to read %i bytes",*len)); |
| if ((f != NULL)) { |
| res = picopal_fread_bytes(f->nf, (void *) &bytes[(0)], 1, (*len)); |
| PICODBG_TRACE(("res = %i",res)); |
| if (res < 0) { /* non-ansi */ |
| (*len) = 0; |
| done = FALSE; |
| } else if (((picoos_uint32)res != (*len))) { |
| (*len) = res; |
| done = FALSE; |
| } else { |
| done = TRUE; |
| } |
| f->lPos = (f->lPos + (*len)); |
| } else { |
| (*len) = 0; |
| done = FALSE; |
| } |
| return done; |
| } |
| |
| static picoos_bool LWriteBytes(picoos_File f, const picoos_char bytes[], int * len) { |
| picoos_bool done; |
| int res; |
| /*int n; |
| void * bptr; */ |
| |
| if (f != NULL) { |
| res = picopal_fwrite_bytes(f->nf, (void *) bytes, 1, *len); |
| if ((res < 0)) { |
| (*len) = 0; |
| done = FALSE; |
| } else if ((res != (*len))) { |
| (*len) = res; |
| done = FALSE; |
| } else { |
| done = TRUE; |
| } |
| f->lPos = (f->lPos + (unsigned int) (*len)); |
| if ((f->lPos > f->lFileLen)) { |
| f->lFileLen = f->lPos; |
| } |
| } else { |
| (*len) = 0; |
| done = FALSE; |
| } |
| return done; |
| } |
| |
| |
| static picoos_bool LSetPos(picoos_File f, unsigned int pos) |
| { |
| |
| picoos_bool done; |
| |
| if ((f != NULL)) { |
| if ((pos == f->lPos)) { |
| done = TRUE; |
| } else { |
| done = (PICO_OK == picopal_fseek(f->nf, pos, PICOPAL_SEEK_SET)); |
| if (done) { |
| f->lPos = pos; |
| } |
| } |
| } else { |
| done = FALSE; |
| } |
| return done; |
| } |
| |
| static picoos_bool LGetPos(picoos_File f, picoos_uint32 * pos) |
| { |
| picoos_bool done = TRUE; |
| if ((f != NULL)) { |
| (*pos) = f->lPos; |
| } else { |
| done = FALSE; |
| (*pos) = 0; |
| } |
| return done; |
| |
| } |
| |
| static picoos_bool LEof(picoos_File f) |
| { |
| picoos_bool isEof; |
| |
| if ((f != NULL)) { |
| isEof = picopal_feof(f->nf); |
| } else { |
| isEof = TRUE; |
| } |
| return isEof; |
| |
| } |
| |
| /* **************************************************************************************/ |
| |
| |
| |
| /* read a given string 'str' from file. If no match was found, the read position is advanced until and including the first |
| * non-matching character */ |
| static picoos_bool picoos_StrRead (picoos_File f, picoos_char str[]) |
| { |
| picoos_uint32 i = 0; |
| picoos_bool done = TRUE; |
| picoos_char b; |
| |
| while (done && (str[i] != NULLC)) { |
| done = done && picoos_ReadByte(f,(picoos_char *)&b); |
| done = done && (b == str[i]); |
| i++; |
| } |
| return done; |
| } |
| |
| /* write 'str' to file */ |
| static picoos_bool picoos_WriteStr (picoos_File f, picoos_char str[]) |
| { |
| picoos_uint32 i = 0; |
| picoos_bool done = TRUE; |
| |
| while (done && (str[i] != NULLC)) { |
| done = done && picoos_WriteByte(f,str[i]); |
| i++; |
| } |
| return done; |
| } |
| |
| |
| |
| /* **** Sequential binary file access ******/ |
| |
| /* Remark: 'ReadByte', 'ReadBytes' and 'ReadVar' may be mixed; |
| 'WriteByte', 'WriteBytes' and 'WriteVar' may be mixed. */ |
| |
| /* Open existing binary file for read access. Reading is buffered |
| * with 'nrOfBufs' buffers of size 'bufSize'. If 'nrOfBufs' or |
| * 'bufSize' is 0 reading is not buffered. |
| * If 'key' is not empty, the file is decrypted with 'key'. |
| * If the opened file is in an encrypted archive file, it |
| */ |
| picoos_uint8 picoos_OpenBinary(picoos_Common g, picoos_File * f, |
| picoos_char fileName[]) |
| { |
| return LOpen(g, f, fileName, PICOPAL_BINARY_READ); |
| } |
| |
| |
| /* Read next byte from file 'f'. */ |
| picoos_bool picoos_ReadByte(picoos_File f, picoos_uint8 * by) |
| { |
| picoos_uint32 n = 1; |
| |
| return picoos_ReadBytes(f, by, &n) && (n == 1); |
| |
| } |
| |
| /* Read next 'len' bytes from 'f' into 'bytes'; 'len' returns the |
| number of bytes actually read (may be smaller than requested |
| length if at end of file). bytes[] must be big enough to hold at least len bytes. |
| */ |
| picoos_bool picoos_ReadBytes(picoos_File f, picoos_uint8 bytes[], |
| picoos_uint32 * len) |
| { |
| picoos_bool done = TRUE; |
| /* unsigned int origPos; */ |
| |
| if ((f != NULL)) { |
| done = LReadBytes(f, bytes, len); |
| /*if ((f->keyLen > 0)) { |
| DecryptBytes(f->key,picoos_MaxKeyLen,f->keyLen,origPos,bytes,(*len)); |
| }*/ |
| } |
| |
| return done; |
| } |
| |
| |
| /* Create new binary file. |
| If 'key' is not empty, the file is encrypted with 'key'. */ |
| picoos_bool picoos_CreateBinary(picoos_Common g, picoos_File * f, |
| picoos_char fileName[]) |
| { |
| return LOpen(g, f, fileName, PICOPAL_BINARY_WRITE); |
| |
| } |
| |
| |
| picoos_uint8 picoos_WriteByte(picoos_File f, picoos_char by) |
| { |
| int n = 1; |
| |
| return picoos_WriteBytes(f, (picoos_char *) &by, &n); |
| } |
| |
| |
| /* Writes 'len' bytes from 'bytes' onto file 'f'; 'len' returns |
| the number of bytes actually written. */ |
| picoos_bool picoos_WriteBytes(picoos_File f, const picoos_char bytes[], picoos_int32 * len) { |
| picoos_bool done = FALSE; |
| |
| if (f != NULL) { |
| done = LWriteBytes(f, bytes, len); |
| } |
| |
| return done; |
| } |
| |
| |
| |
| /* Close previously opened binary file. */ |
| picoos_uint8 picoos_CloseBinary(picoos_Common g, picoos_File * f) |
| { |
| return LClose(g, f); |
| |
| } |
| |
| /* **************************************************************************************/ |
| /* *** general routines *****/ |
| |
| |
| /* Returns whether end of file was encountered in previous |
| read operation. */ |
| picoos_bool picoos_Eof(picoos_File f) |
| { |
| if ((NULL != f)) { |
| return LEof(f); |
| } else { |
| return TRUE; |
| } |
| |
| } |
| |
| /* sets the file pointer to |
| 'pos' bytes from beginning (first byte = byte 0). This |
| routine should only be used for binary files. */ |
| picoos_bool picoos_SetPos(picoos_File f, picoos_int32 pos) |
| { |
| picoos_bool done = TRUE; |
| if ((NULL != f)) { |
| done = LSetPos(f, pos); |
| } else { |
| done = FALSE; |
| } |
| return done; |
| |
| } |
| |
| /* Get position from file 'f'. */ |
| picoos_bool picoos_GetPos(picoos_File f, picoos_uint32 * pos) |
| { |
| if (NULL != f) { |
| /* if (f->bFile) { |
| (*pos) = BGetPos(f); |
| } else { */ |
| (*pos) = LGetPos(f, pos); |
| /* } */ |
| return TRUE; |
| } else { |
| (*pos) = 0; |
| return FALSE; |
| } |
| } |
| |
| /* Returns the length of the file in bytes. */ |
| picoos_bool picoos_FileLength(picoos_File f, picoos_uint32 * len) |
| { |
| |
| if (NULL != f) { |
| *len = f->lFileLen; |
| return TRUE; |
| } else { |
| *len = 0; |
| return FALSE; |
| } |
| } |
| |
| /* Return full name of file 'f'. maxsize is the size of 'name[]' in bytes */ |
| picoos_bool picoos_Name(picoos_File f, picoos_char name[], picoos_uint32 maxsize) |
| { |
| picoos_bool done = TRUE; |
| |
| if (NULL != f) { |
| done = (picoos_strlcpy(name, f->name,maxsize) < maxsize); |
| } else { |
| name[0] = (picoos_char)NULLC; |
| done = FALSE; |
| } |
| |
| return done; |
| } |
| |
| /* Returns whether file 'name' exists or not. */ |
| picoos_bool picoos_FileExists(picoos_Common g, picoos_char name[]) |
| { |
| picoos_File f; |
| |
| if (picoos_OpenBinary(g, & f,name)) { |
| picoos_CloseBinary(g, & f); |
| return TRUE; |
| } else { |
| return FALSE; |
| } |
| } |
| |
| |
| /* ******************************************************************/ |
| /* Array conversion operations: all procedures convert 'nrElems' values from |
| 'src' starting with index 'srcStartInd' into corresponding (possibly |
| rounded) values in 'dst' starting at 'dstStartInd'. */ |
| |
| /* taking pi to be le, these are just the array versions of read_mem_pi_*int16 */ |
| typedef picoos_uint8 two_byte_t[2]; |
| |
| static void arr_conv_le_int16 (picoos_uint8 src[], picoos_uint32 srcShortStartInd, picoos_uint32 nrElems, picoos_int16 dst[], picoos_uint32 dstStartInd) |
| { |
| two_byte_t * src_p = (two_byte_t *) (src + (srcShortStartInd * 2)); |
| picoos_int16 * dst_p = dst + dstStartInd; |
| picoos_uint32 i; |
| |
| for (i=0; i<nrElems; i++) { |
| *(dst_p++) = (*src_p)[0] + (((*src_p)[1] & 0x7F) << 8) - (((*src_p)[1] & 0x80) ? 0x8000 : 0); |
| src_p++; |
| } |
| } |
| |
| |
| |
| /* convert array of int16 into little-endian format */ |
| static void arr_conv_int16_le (picoos_int16 src[], picoos_uint32 srcStartInd, picoos_uint32 nrElems, picoos_uint8 dst[], picoos_uint32 dstShortStartInd) |
| { |
| two_byte_t * dst_p = (two_byte_t *) (dst + (dstShortStartInd * 2)); |
| picoos_int16 * src_p = src + srcStartInd; |
| picoos_uint32 i; |
| picoos_uint16 val; |
| |
| for (i=0; i<nrElems; i++) { |
| val = (picoos_uint16) *(src_p++); |
| (*dst_p)[0] = (picoos_uint8)(val & 0x00FF); |
| (*dst_p)[1] = (picoos_uint8)((val & 0xFF00)>>8); |
| dst_p++; |
| } |
| } |
| |
| /* *****************************************************************/ |
| /* Sampled Data Files */ |
| /* *****************************************************************/ |
| |
| #define PICOOS_SDF_BUF_LEN 1024 |
| |
| #define PICOOS_INT16_MIN -32768 |
| #define PICOOS_INT16_MAX 32767 |
| #define PICOOS_UINT16_MAX 0xffff |
| #define PICOOS_INT32_MIN -2147483648 |
| #define PICOOS_INT32_MAX 2147483647 |
| #define PICOOS_UINT32_MAX 0xffffffff |
| |
| /** object : SDFile |
| * shortcut : sdf |
| * |
| */ |
| /* typedef struct picoos_sd_file * picoos_SDFile */ |
| typedef struct picoos_sd_file |
| { |
| picoos_uint32 sf; |
| wave_file_type_t fileType; /* (acoustic) wav, au, raw, other */ |
| picoos_uint32 hdrSize; |
| picoos_encoding_t enc; |
| picoos_File file; |
| picoos_uint32 nrFileSamples; |
| picoos_int16 buf[PICOOS_SDF_BUF_LEN]; |
| picoos_int32 bufPos; |
| picoos_uint8 bBuf[2*PICOOS_SDF_BUF_LEN]; |
| picoos_bool aborted; |
| } picoos_sd_file_t; |
| |
| |
| /* Tries to read wav header at beginning of file 'f'; |
| returns sampling rate 'sf', encoding type 'enc', |
| nr of samples in file 'nrSamples', header size 'hdrSize', |
| and byte order 'bOrder'; returns whether a supported |
| wav header and format was found. */ |
| static picoos_bool picoos_readWavHeader(picoos_File f, picoos_uint32 * sf, |
| picoos_encoding_t * enc, picoos_uint32 * nrSamples, |
| picoos_uint32 * hdrSize) { |
| picoos_uint16 n16; |
| picoos_uint32 n32; |
| picoos_uint16 formatTag; |
| picoos_uint32 sampleRate; |
| picoos_uint32 bytesPerSec; |
| picoos_uint16 blockAlign; |
| picoos_uint16 sampleSize; |
| picoos_uint32 dataLength; |
| picoos_uint32 fileLen; |
| picoos_uint32 nrFileSamples; |
| picoos_bool done; |
| |
| |
| picoos_SetPos(f, 0); |
| picoos_FileLength(f, &fileLen); |
| done = picoos_StrRead(f, (picoos_char *) "RIFF"); |
| done = done && (PICO_OK == picoos_read_le_uint32(f, &n32)); /* length of riff chunk, unused */ |
| done = done && picoos_StrRead(f, (picoos_char *) "WAVE"); |
| done = done && picoos_StrRead(f, (picoos_char *) "fmt "); |
| done = done && (PICO_OK == picoos_read_le_uint32(f, &n32)); /* length of fmt chunk in bytes; must be 16 */ |
| done = done && (n32 == 16); |
| done = done && (PICO_OK == picoos_read_le_uint16(f, &formatTag)); |
| done = done && (PICO_OK == picoos_read_le_uint16(f, &n16)); /* number of channels; must be mono */ |
| done = done && (n16 == 1); |
| done = done && (PICO_OK == picoos_read_le_uint32(f, &sampleRate)); |
| done = done && (PICO_OK == picoos_read_le_uint32(f, &bytesPerSec)); |
| done = done && (PICO_OK == picoos_read_le_uint16(f, &blockAlign)); |
| done = done && (PICO_OK == picoos_read_le_uint16(f, &sampleSize)); |
| done = done && picoos_StrRead(f, (picoos_char *) "data"); |
| done = done && (PICO_OK == picoos_read_le_uint32(f, &dataLength)); /* length of data chunk in bytes */ |
| (*hdrSize) = 44; |
| if (done) { |
| (*sf) = sampleRate; |
| (*nrSamples) = 0; |
| switch (formatTag) { |
| case FORMAT_TAG_LIN: |
| (*enc) = PICOOS_ENC_LIN; |
| done = ((blockAlign == 2) && (sampleSize == 16)); |
| (*nrSamples) = (dataLength / 2); |
| nrFileSamples = ((fileLen - (*hdrSize)) / 2); |
| break; |
| case FORMAT_TAG_ULAW: |
| (*enc) = PICOOS_ENC_ULAW; |
| done = ((blockAlign == 1) && (sampleSize == 8)); |
| (*nrSamples) = dataLength; |
| nrFileSamples = (fileLen - (*hdrSize)); |
| break; |
| case FORMAT_TAG_ALAW: |
| (*enc) = PICOOS_ENC_ALAW; |
| done = ((blockAlign == 1) && (sampleSize == 8)); |
| (*nrSamples) = dataLength; |
| nrFileSamples = (fileLen - (*hdrSize)); |
| break; |
| default: |
| done = FALSE; |
| break; |
| } |
| if (!done) { |
| /* communicate "unsupported format" */ |
| PICODBG_WARN(("unsupported wav format")); |
| } else { |
| if (nrFileSamples != (*nrSamples)) { |
| /* warn "inconsistent number of samples" */ |
| PICODBG_WARN(("inconsistent number of samples in wav file: %d vs. %d",nrFileSamples,(*nrSamples))); |
| (*nrSamples) = nrFileSamples; |
| } |
| } |
| } |
| return done; |
| } |
| |
| |
| |
| extern picoos_bool picoos_sdfOpenIn(picoos_Common g, picoos_SDFile * sdFile, |
| picoos_char fileName[], picoos_uint32 * sf, picoos_encoding_t * enc, |
| picoos_uint32 * numSamples) |
| { |
| picoos_bool done = FALSE; |
| picoos_sd_file_t * sdf = NULL; |
| wave_file_type_t fileType = FILE_TYPE_OTHER; |
| |
| (*sf) = 0; |
| (*numSamples) = 0; |
| (*enc) = PICOOS_ENC_LIN; |
| (*sdFile) = NULL; |
| |
| sdf = picoos_allocate(g->mm,sizeof(picoos_sd_file_t)); |
| if (NULL == sdf) { |
| picoos_emRaiseWarning(g->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); |
| return FALSE; |
| } |
| |
| /* buffered access not supported, yet */ |
| if (picoos_OpenBinary(g,&(sdf->file),fileName)) { |
| if (picoos_has_extension(fileName,(picoos_char *) ".wav")) { |
| fileType = FILE_TYPE_WAV; |
| done = picoos_readWavHeader(sdf->file,&(sdf->sf),&(sdf->enc),&(sdf->nrFileSamples),&(sdf->hdrSize)); |
| } else { |
| /* we prefer not to treat other formats, rather than treat it as raw */ |
| /* fileType = FILE_TYPE_RAW; */ |
| fileType = FILE_TYPE_OTHER; |
| done = FALSE; |
| } |
| |
| if (FILE_TYPE_OTHER == fileType) { |
| picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,(picoos_char *)"unsupported filename suffix",NULL); |
| } else if (!done) { |
| picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,(picoos_char *)"non-conforming header",NULL); |
| } else { |
| (*numSamples) = sdf->nrFileSamples; |
| (*sf) = sdf->sf; |
| (*enc) = sdf->enc; |
| /* check whether sd file properties are supported */ |
| if (PICOOS_ENC_LIN != sdf->enc) { |
| done = FALSE; |
| picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,NULL,(picoos_char *)"encoding not supported"); |
| } |
| if (SAMPLE_FREQ_16KHZ != sdf->sf) { |
| done = FALSE; |
| picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,NULL,(picoos_char *)"sample frequency not supported"); |
| } |
| (*sdFile) = sdf; |
| } |
| if (!done){ |
| picoos_CloseBinary(g,&(sdf->file)); |
| } |
| } else { |
| picoos_emRaiseException(g->em,PICO_EXC_CANT_OPEN_FILE,NULL,NULL); |
| } |
| if (!done) { |
| picoos_deallocate(g->mm,(void *)&sdf); |
| (*sdFile) = NULL; |
| } |
| return done; |
| } |
| |
| |
| static void picoos_sdfLoadSamples(picoos_SDFile sdFile, |
| picoos_uint32 * nrSamples) { |
| picoos_uint32 len; |
| picoos_sd_file_t * sdf = sdFile; |
| |
| switch (sdFile->enc) { |
| case PICOOS_ENC_LIN: |
| if ((*nrSamples) > PICOOS_SDF_BUF_LEN) { |
| (*nrSamples) = PICOOS_SDF_BUF_LEN; |
| } |
| len = 2 * (*nrSamples); |
| picoos_ReadBytes(sdf->file, sdf->bBuf, &len); |
| (*nrSamples) = len / 2; |
| arr_conv_le_int16(sdf->bBuf, 0, (*nrSamples), sdf->buf, 0); |
| break; |
| /* @todo : may be useful */ |
| case PICOOS_ENC_ULAW: |
| case PICOOS_ENC_ALAW: |
| default: |
| (*nrSamples) = 0; |
| } |
| |
| } |
| |
| extern picoos_bool picoos_sdfGetSamples ( |
| picoos_SDFile sdFile, |
| picoos_uint32 start, |
| picoos_uint32 * nrSamples, |
| picoos_int16 samples[]) |
| { |
| picoos_uint32 b; |
| picoos_uint32 rem; |
| picoos_uint32 n; |
| picoos_uint32 i; |
| picoos_uint32 j; |
| picoos_bool done = FALSE; |
| |
| if (NULL == sdFile) { |
| (*nrSamples) = 0; |
| } else { |
| if (start >= sdFile->nrFileSamples) { |
| if (start > sdFile->nrFileSamples) { |
| PICODBG_WARN(("start has to be <= sdFile->nrFileSamples")); |
| } |
| (*nrSamples) = 0; |
| } else { |
| if (((start + (*nrSamples)) > sdFile->nrFileSamples)) { |
| (*nrSamples) = (sdFile->nrFileSamples - start); |
| } |
| if ((sdFile->enc == PICOOS_ENC_LIN)) { |
| b = 2; |
| } else { |
| b = 1; |
| } |
| picoos_SetPos(sdFile->file,(sdFile->hdrSize + (b * start))); |
| j = 0; |
| rem = (*nrSamples); |
| n = rem; |
| while ((rem > 0) && (n > 0)) { |
| /* set n=min(rem,buffer_length) and try loading next n samples */ |
| n = (rem < PICOOS_SDF_BUF_LEN) ? rem : PICOOS_SDF_BUF_LEN; |
| picoos_sdfLoadSamples(sdFile, &n); |
| /* n may be smaller now */ |
| for (i = 0; i < n; i++) { |
| samples[j] = sdFile->buf[i]; |
| j++; |
| } |
| rem -= n; |
| start += n; |
| } |
| (*nrSamples) = j; |
| done = ((*nrSamples) > 0); |
| } |
| } |
| return done; |
| } |
| |
| |
| extern picoos_bool picoos_sdfCloseIn (picoos_Common g, picoos_SDFile * sdFile) |
| { |
| if (NULL != (*sdFile)) { |
| picoos_CloseBinary(g,&((*sdFile)->file)); |
| picoos_deallocate(g->mm,(void *)sdFile); |
| } |
| return TRUE; |
| } |
| |
| |
| static picoos_bool picoos_writeWavHeader(picoos_File f, picoos_uint32 sf, |
| picoos_encoding_t enc, picoos_uint32 nrSamples, |
| picoos_uint32 * hdrSize) { |
| picoos_uint16 formatTag = FORMAT_TAG_LIN; |
| picoos_uint32 sampleRate; |
| picoos_uint32 bytesPerSec; |
| picoos_uint32 bytesPerSample = 2; |
| picoos_uint16 blockAlign; |
| picoos_uint16 sampleSize = 16; |
| picoos_uint32 dataLength; |
| picoos_bool done = TRUE; |
| |
| picoos_SetPos(f, 0); |
| |
| switch (enc) { |
| case PICOOS_ENC_LIN: |
| formatTag = FORMAT_TAG_LIN; |
| bytesPerSample = 2; |
| sampleSize = 16; |
| break; |
| case PICOOS_ENC_ULAW: |
| formatTag = FORMAT_TAG_ULAW; |
| bytesPerSample = 1; |
| sampleSize = 8; |
| break; |
| case PICOOS_ENC_ALAW: |
| formatTag = FORMAT_TAG_ALAW; |
| bytesPerSample = 1; |
| sampleSize = 8; |
| break; |
| default: |
| done = FALSE; |
| break; |
| } |
| |
| bytesPerSec = (sf * bytesPerSample); |
| blockAlign = bytesPerSample; |
| sampleRate = sf; |
| dataLength = (bytesPerSample * nrSamples); |
| done = done && picoos_WriteStr(f,(picoos_char *)"RIFF"); |
| done = done && picoos_write_le_uint32(f,dataLength + 36); |
| done = done && picoos_WriteStr(f,(picoos_char *)"WAVE"); |
| done = done && picoos_WriteStr(f,(picoos_char *)"fmt "); |
| done = done && picoos_write_le_uint32(f,16); |
| done = done && picoos_write_le_uint16(f,formatTag); |
| done = done && picoos_write_le_uint16(f,1); |
| done = done && picoos_write_le_uint32(f,sampleRate); |
| done = done && picoos_write_le_uint32(f,bytesPerSec); |
| done = done && picoos_write_le_uint16(f,blockAlign); |
| done = done && picoos_write_le_uint16(f,sampleSize); |
| done = done && picoos_WriteStr(f,(picoos_char *)"data"); |
| done = done && picoos_write_le_uint32(f,dataLength); |
| (*hdrSize) = 44; |
| return done; |
| } |
| |
| |
| #define DummyLen 100000000 |
| |
| extern picoos_bool picoos_sdfOpenOut(picoos_Common g, picoos_SDFile * sdFile, |
| picoos_char fileName[], int sf, picoos_encoding_t enc) |
| { |
| picoos_bool done = TRUE; |
| picoos_sd_file_t * sdf = NULL; |
| |
| (*sdFile) = NULL; |
| sdf = picoos_allocate(g->mm, sizeof(picoos_sd_file_t)); |
| if (NULL == sdf) { |
| picoos_emRaiseWarning(g->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); |
| return FALSE; |
| } |
| sdf->sf = sf; |
| sdf->enc = enc; |
| /* check whether sd file properties are supported */ |
| if (PICOOS_ENC_LIN != sdf->enc) { |
| done = FALSE; |
| picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, NULL, |
| (picoos_char *) "encoding not supported"); |
| } |
| if (SAMPLE_FREQ_16KHZ != sdf->sf) { |
| done = FALSE; |
| picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, NULL, |
| (picoos_char *) "sample frequency not supported"); |
| } |
| if (done) { |
| sdf->nrFileSamples = 0; |
| sdf->bufPos = 0; |
| sdf->aborted = FALSE; |
| if (picoos_CreateBinary(g, &(sdf->file), fileName)) { |
| if (picoos_has_extension(fileName, (picoos_char *) ".wav")) { |
| sdf->fileType = FILE_TYPE_WAV; |
| done = picoos_writeWavHeader(sdf->file, sdf->sf, sdf->enc, |
| DummyLen, &(sdf->hdrSize)); |
| } else { |
| /* we prefer not to treat other formats, rather than treat it as raw */ |
| /* fileType = FILE_TYPE_RAW; */ |
| sdf->fileType = FILE_TYPE_OTHER; |
| done = FALSE; |
| } |
| |
| if (FILE_TYPE_OTHER == sdf->fileType) { |
| picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, |
| (picoos_char *) "unsupported filename suffix", NULL); |
| } else if (!done) { |
| picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, |
| (picoos_char *) "non-conforming header", NULL); |
| } else { |
| (*sdFile) = sdf; |
| } |
| if (!done) { |
| picoos_CloseBinary(g, &(sdf->file)); |
| } |
| } else { |
| picoos_emRaiseException(g->em, PICO_EXC_CANT_OPEN_FILE, NULL, NULL); |
| } |
| } |
| if (!done) { |
| picoos_deallocate(g->mm, (void *) &sdf); |
| (*sdFile) = NULL; |
| } |
| return done; |
| } |
| |
| static picoos_bool picoos_sdfFlushOutBuf(picoos_SDFile sdFile) |
| { |
| picoos_bool done = FALSE; |
| picoos_int32 len; |
| picoos_int32 nrSamples; |
| |
| if (!(sdFile->aborted)) { |
| nrSamples = sdFile->bufPos; |
| switch (sdFile->enc) { |
| case PICOOS_ENC_LIN: |
| arr_conv_int16_le(sdFile->buf, 0, nrSamples, sdFile->bBuf, 0); |
| len = (nrSamples * 2); |
| done = picoos_WriteBytes(sdFile->file, sdFile->bBuf, &len) |
| && ((nrSamples * 2) == len); |
| break; |
| case PICOOS_ENC_ULAW: |
| case PICOOS_ENC_ALAW: |
| default: |
| nrSamples = 0; |
| break; |
| } |
| sdFile->nrFileSamples = (sdFile->nrFileSamples + nrSamples); |
| } |
| |
| sdFile->bufPos = 0; |
| return done; |
| } |
| |
| extern picoos_bool picoos_sdfFlushOutput(picoos_SDFile sdFile) |
| { |
| if ((sdFile != NULL) && !(sdFile->aborted) && (sdFile->bufPos > 0)) { |
| return picoos_sdfFlushOutBuf(sdFile); |
| } |
| return TRUE; |
| } |
| |
| |
| |
| extern picoos_bool picoos_sdfPutSamples (picoos_SDFile sdFile, picoos_uint32 nrSamples, picoos_int16 samples[]) |
| { |
| picoos_uint32 i; |
| picoos_int32 s; |
| picoos_bool done = FALSE; |
| |
| if ((sdFile != NULL) && !(sdFile->aborted)) { |
| done = TRUE; |
| for (i = 0; i < nrSamples; i++) { |
| s = samples[i]; |
| if ((s > PICOOS_INT16_MAX)) { |
| s = PICOOS_INT16_MAX; |
| } else if (s < PICOOS_INT16_MIN) { |
| s = PICOOS_INT16_MIN; |
| } |
| sdFile->buf[sdFile->bufPos++] = s; |
| if (sdFile->bufPos >= PICOOS_SDF_BUF_LEN) { |
| done = picoos_sdfFlushOutBuf(sdFile); |
| } |
| } |
| } else { |
| done = FALSE; |
| } |
| return done; |
| } |
| |
| |
| extern picoos_bool picoos_sdfCloseOut (picoos_Common g, picoos_SDFile * sdFile) |
| { |
| |
| picoos_bool done = TRUE; |
| picoos_uint32 hdrSize; |
| |
| if (NULL != (*sdFile)) { |
| if (!((*sdFile)->aborted) && ((*sdFile)->bufPos > 0)) { |
| done = picoos_sdfFlushOutBuf(*sdFile); |
| } |
| if (FILE_TYPE_WAV == (*sdFile)->fileType) { |
| done = picoos_writeWavHeader((*sdFile)->file, (*sdFile)->sf, |
| (*sdFile)->enc, (*sdFile)->nrFileSamples, &hdrSize); |
| } |
| done = picoos_CloseBinary(g, &((*sdFile)->file)); |
| picoos_deallocate(g->mm, (void *) sdFile); |
| } |
| return done; |
| } |
| |
| |
| /* *****************************************************************/ |
| /* FileHeader */ |
| /* *****************************************************************/ |
| |
| |
| |
| pico_status_t picoos_clearHeader(picoos_FileHeader header) |
| { |
| picoos_uint8 i; |
| for (i=0; i < PICOOS_MAX_NUM_HEADER_FIELDS; i++) { |
| header->field[i].key[0] = NULLC; |
| header->field[i].value[0] = NULLC; |
| header->field[i].op = PICOOS_FIELD_IGNORE; |
| } |
| header->numFields = 0; |
| return PICO_OK; |
| } |
| |
| pico_status_t picoos_setHeaderField(picoos_FileHeader header, |
| picoos_uint8 index, picoos_char * key, picoos_char * value, |
| picoos_compare_op_t op) |
| { |
| if (index >= header->numFields) { |
| return PICO_ERR_INDEX_OUT_OF_RANGE; |
| } |
| header->field[index].op = op; |
| if ((picoos_strlcpy(header->field[index].key, key, |
| PICOOS_MAX_FIELD_STRING_LEN) < PICOOS_MAX_FIELD_STRING_LEN) |
| && (picoos_strlcpy(header->field[index].value, value, |
| PICOOS_MAX_FIELD_STRING_LEN)) < PICOOS_MAX_FIELD_STRING_LEN) { |
| return PICO_OK; |
| } else { |
| return PICO_ERR_INDEX_OUT_OF_RANGE; |
| } |
| } |
| |
| |
| /* caller has to make sure allocated space at key and value are large enough to hold a picoos_field_string */ |
| pico_status_t picoos_getHeaderField(picoos_FileHeader header, picoos_uint8 index, picoos_field_string_t key, picoos_field_string_t value, picoos_compare_op_t * op) |
| { |
| if (index >= header->numFields) { |
| return PICO_ERR_INDEX_OUT_OF_RANGE; |
| } |
| *op = header->field[index].op; |
| if ((picoos_strlcpy(key,header->field[index].key, |
| PICOOS_MAX_FIELD_STRING_LEN) < PICOOS_MAX_FIELD_STRING_LEN) |
| && (picoos_strlcpy(value,header->field[index].value, |
| PICOOS_MAX_FIELD_STRING_LEN)) < PICOOS_MAX_FIELD_STRING_LEN) { |
| return PICO_OK; |
| } else { |
| return PICO_ERR_INDEX_OUT_OF_RANGE; |
| } |
| return PICO_OK; |
| } |
| |
| |
| /* check whether 'str' of length strlen matches contents in circular buffer buf, located in the first strlen bytes and ending |
| * position bufpos. */ |
| static picoos_uint8 os_matched( picoos_char * str, picoos_uint32 strlen, picoos_char * buf, picoos_int32 bufpos) { |
| picoos_int32 i = strlen-1; |
| while (i >= 0 && buf[bufpos] == str[i]) { |
| i--; |
| bufpos--; |
| if (bufpos < 0) { |
| bufpos = strlen-1; |
| } |
| } |
| return (i<0); |
| } |
| |
| pico_status_t picoos_getSVOXHeaderString(picoos_char * str, picoos_uint8 * len, picoos_uint32 maxlen) |
| { |
| picoos_char * ch; |
| *len = picoos_strlcpy(str,picoos_SVOXFileHeader,maxlen); |
| if (*len < maxlen) { |
| ch = str; |
| /* SVOX header is made less readable */ |
| while (*ch) { |
| *ch -= ' '; |
| ch++; |
| } |
| return PICO_OK; |
| } else { |
| return PICO_ERR_OTHER; |
| } |
| } |
| |
| pico_status_t picoos_readPicoHeader(picoos_File f, picoos_uint32 * headerlen) |
| { |
| picoos_char str[32]; |
| picoos_char buf[32]; |
| picoos_uint8 strlen, bufpos; |
| picoos_uint32 n; |
| picoos_uint8 done; |
| |
| picoos_getSVOXHeaderString(str,&strlen,32); |
| /* search for svox header somewhere near the file start. This allows for initial |
| * non-svox-header bytes for a customer-specific header and/or filling bytes for alignment */ |
| *headerlen = 0; |
| /* read in initial chunk of length strlen */ |
| n = strlen; |
| done = picoos_ReadBytes(f,(picoos_uint8 *)buf,&n) && (n == strlen); |
| if (done) { |
| *headerlen = n; |
| bufpos = strlen-1; /* last legal buf position */ |
| done = os_matched(str,strlen,buf,bufpos); |
| while (!done && *headerlen < PICO_MAX_FOREIGN_HEADER_LEN) { |
| n = 1; |
| bufpos = (bufpos + 1) % strlen; |
| done = picoos_ReadBytes(f,(picoos_uint8 *)buf+bufpos,&n) && 1 == n; |
| done = done && os_matched(str,strlen,buf,bufpos); |
| headerlen++; |
| } |
| } |
| if (done) { |
| return PICO_OK; |
| } else { |
| return PICO_EXC_UNEXPECTED_FILE_TYPE; |
| } |
| } |
| |
| picoos_uint8 picoos_get_str (picoos_char * fromStr, picoos_uint32 * pos, picoos_char * toStr, picoos_objsize_t maxsize) |
| { |
| picoos_uint8 i = 0; |
| /* skip non-printables */ |
| |
| while ((fromStr[*pos] != NULLC) && (fromStr[*pos] <= ' ')) { |
| (*pos)++; |
| } |
| /* copy printable portion */ |
| while ((fromStr[*pos] != NULLC) && (fromStr[*pos] > ' ') && (i < maxsize-1)) { |
| toStr[i++] = fromStr[(*pos)++]; |
| } |
| toStr[i] = NULLC; |
| return (i > 0) && (fromStr[*pos] <= ' '); |
| } |
| |
| pico_status_t picoos_hdrParseHeader(picoos_FileHeader header, picoos_header_string_t str) |
| { |
| picoos_uint32 curpos = 0; |
| picoos_uint8 i, numFields; |
| |
| |
| /* read number of fields */ |
| numFields = str[curpos++]; |
| numFields = os_min(numFields,PICOOS_MAX_NUM_HEADER_FIELDS); |
| /* read in all field pairs */ |
| PICODBG_DEBUG(("number of fields = %i", numFields)); |
| for (i = 0; i < numFields; i++) { |
| picoos_get_str(str,&curpos,header->field[i].key,PICOOS_MAX_FIELD_STRING_LEN); |
| picoos_get_str(str,&curpos,header->field[i].value,PICOOS_MAX_FIELD_STRING_LEN); |
| } |
| return PICO_OK; |
| } |
| |
| |
| |
| |
| |
| /* **************************************************************************/ |
| /* Read little-endian / platform-independent integers from file or memory */ |
| /* **************************************************************************/ |
| |
| /* read little-endian */ |
| pico_status_t picoos_read_le_uint16 (picoos_File file, picoos_uint16 * val) |
| { |
| picoos_uint8 by[2]; |
| picoos_uint32 n = 2; |
| if (picoos_ReadBytes(file, by, &n) && 2 == n) { |
| /* little-endian */ |
| *val = (picoos_uint16) by[1] << 8 | (picoos_uint16) by[0]; |
| return PICO_OK; |
| } else { |
| *val = 0; |
| return PICO_ERR_OTHER; |
| } |
| } |
| |
| pico_status_t picoos_read_le_int16 (picoos_File file, picoos_int16 * val) |
| { |
| return picoos_read_le_uint16(file, (picoos_uint16 *)val); |
| } |
| |
| pico_status_t picoos_read_le_uint32 (picoos_File file, picoos_uint32 * val) |
| { |
| picoos_uint8 by[4]; |
| picoos_uint32 n = 4; |
| if (picoos_ReadBytes(file, by, &n) && (4 == n)) { |
| /* little-endian */ |
| PICODBG_TRACE(("reading uint 32: %i %i %i %i", |
| by[0], by[1], by[2], by[3])); |
| *val = (((picoos_uint32) by[3] << 8 | (picoos_uint32) by[2]) << 8 | (picoos_uint32) by[1]) << 8 | (picoos_uint32) by[0]; |
| PICODBG_TRACE(("uint 32: %i %i %i %i corresponds %i", |
| by[0], by[1], by[2], by[3], *val)); |
| return PICO_OK; |
| } else { |
| *val = 0; |
| return PICO_ERR_OTHER; |
| } |
| } |
| |
| /* platform-independent */ |
| /* our convention is that pi is little-endian. */ |
| |
| /** @todo : direct implementation if too slow */ |
| |
| pico_status_t picoos_read_pi_uint16 (picoos_File file, picoos_uint16 * val) |
| { |
| return picoos_read_le_uint16(file,val); |
| } |
| |
| pico_status_t picoos_read_pi_uint32 (picoos_File file, picoos_uint32 * val) |
| { |
| return picoos_read_le_uint32(file, val); |
| } |
| |
| pico_status_t picoos_read_pi_int32 (picoos_File file, picoos_int32 * val) |
| { |
| return picoos_read_le_uint32(file, (picoos_uint32 *)val); |
| } |
| |
| /* read pi from memory */ |
| |
| pico_status_t picoos_read_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 * val) |
| { |
| picoos_uint8 * by = data + *pos; |
| |
| /* little-endian */ |
| *val = (picoos_uint16) by[1] << 8 | (picoos_uint16) by[0]; |
| (*pos) += 2; |
| return PICO_OK; |
| } |
| |
| pico_status_t picoos_read_mem_pi_uint32 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint32 * val) |
| { |
| picoos_uint8 * by = data + *pos; |
| |
| /* little-endian */ |
| *val = (((picoos_uint32) by[3] << 8 | (picoos_uint32) by[2]) << 8 | (picoos_uint32) by[1]) << 8 | (picoos_uint32) by[0]; |
| (*pos) += 4; |
| return PICO_OK; |
| } |
| |
| /* **************************************************************************/ |
| /* Write little-endian / platform-independent integers into file or memory */ |
| /* **************************************************************************/ |
| /* write little-endian */ |
| pico_status_t picoos_write_le_uint16 (picoos_File file, picoos_uint16 val) |
| { |
| picoos_int32 len = 2; |
| picoos_uint8 by[2]; |
| |
| by[0] = (picoos_uint8)((val) & 0x00FF); |
| by[1] = (picoos_uint8)(((val) & 0xFF00)>>8); |
| return (picoos_WriteBytes(file,by,&len) && (2 == len)); |
| } |
| pico_status_t picoos_write_le_uint32 (picoos_File file, picoos_uint32 val) |
| { |
| picoos_int32 len = 4; |
| picoos_uint8 by[4]; |
| |
| by[0] = (picoos_uint8)(val & 0x000000FF); |
| by[1] = (picoos_uint8)((val & 0x0000FF00)>>8); |
| by[2] = (picoos_uint8)((val & 0x00FF0000)>>16); |
| by[3] = (picoos_uint8)((val & 0xFF000000)>>24); |
| return (picoos_WriteBytes(file,by,&len) && (4 == len)); |
| } |
| |
| /* write pi to mem */ |
| pico_status_t picoos_write_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 val) |
| { |
| picoos_uint8 * by = data + *pos; |
| /* little-endian */ |
| by[0] = (picoos_uint8)((val) & 0x00FF); |
| by[1] = (picoos_uint8)(((val) & 0xFF00)>>8); |
| (*pos) += 2; |
| return PICO_OK; |
| } |
| |
| /* *****************************************************************/ |
| /* String search and compare operations */ |
| /* *****************************************************************/ |
| |
| /* this function is case-sensitive */ |
| picoos_uint8 picoos_has_extension(const picoos_char *str, const picoos_char *suf) |
| { |
| picoos_int32 istr = picoos_strlen(str)-1; |
| picoos_int32 isuf = picoos_strlen(suf)-1; |
| while ((istr >= 0) && (isuf >=0) && (str[istr] == suf[isuf])) { |
| istr--; |
| isuf--; |
| } |
| return (isuf < 0); |
| } |
| |
| |
| /* *****************************************************************/ |
| /* String/Number Conversions (may be moved to picopal) */ |
| /* *****************************************************************/ |
| |
| pico_status_t picoos_string_to_int32(picoos_char str[], |
| picoos_int32 * res) |
| { |
| /* syntax: [+|-] dig {dig} */ |
| |
| int i; |
| int neg; |
| int val; |
| int err; |
| |
| err = 0; |
| i = 0; |
| while ((str[i] <= ' ') && (str[i] != '\0')) { |
| i++; |
| } |
| neg = 0; |
| if (str[i] == '-') { |
| neg = 1; |
| i++; |
| } else if (str[i] == '+') { |
| i++; |
| } |
| val = 0; |
| if ((str[i] < '0') || (str[i]> '9')) { |
| err = 1; |
| } |
| while ((str[i] >= '0') && (str[i] <= '9')) { |
| val = val * 10 + (str[i] - '0'); |
| i++; |
| } |
| while ((str[i] <= ' ') && (str[i] != '\0')) { |
| i++; |
| } |
| if (neg == 1) { |
| val = -val; |
| } |
| if ((err == 0) && (str[i] == '\0')) { |
| (*res) = val; |
| return PICO_OK; |
| } else { |
| (*res) = 0; |
| return PICO_EXC_NUMBER_FORMAT; |
| } |
| } |
| |
| pico_status_t picoos_string_to_uint32(picoos_char str[], |
| picoos_uint32 * res) |
| { |
| /* syntax: [+] dig {dig} */ |
| |
| int i; |
| int val; |
| int err; |
| |
| err = 0; |
| i = 0; |
| while ((str[i] <= ' ') && (str[i] != '\0')) { |
| i++; |
| } |
| if (str[i] == '+') { |
| i++; |
| } |
| val = 0; |
| if ((str[i] < '0') || (str[i]> '9')) { |
| err = 1; |
| } |
| while ((str[i] >= '0') && (str[i] <= '9')) { |
| val = val * 10 + (str[i] - '0'); |
| i++; |
| } |
| while ((str[i] <= ' ') && (str[i] != '\0')) { |
| i++; |
| } |
| if ((err == 0) && (str[i] == '\0')) { |
| (*res) = val; |
| return PICO_OK; |
| } else { |
| (*res) = 0; |
| return PICO_EXC_NUMBER_FORMAT; |
| } |
| } |
| |
| /* 'stringlen' is the part of input string to be considered, |
| * possibly not containing NULLC (e.g. result of strlen). |
| * 'maxsize' is the maximal size of 'part' including a byte |
| * for the terminating NULLC! */ |
| void picoos_get_sep_part_str(picoos_char string[], |
| picoos_int32 stringlen, picoos_int32 * ind, picoos_char sepCh, |
| picoos_char part[], picoos_int32 maxsize, picoos_uint8 * done) |
| { |
| |
| picoos_int32 j; |
| picoos_uint8 done1; |
| |
| if (((*ind) >= stringlen)) { |
| (*done) = 0; |
| part[0] = (picoos_char) NULLC; |
| } else { |
| done1 = 1; |
| j = 0; |
| while ((((*ind) < stringlen) && (string[(*ind)] != sepCh)) && (string[((*ind))] != (picoos_char)NULLC)) { |
| if ((j < maxsize-1)) { |
| part[(j)] = string[(*ind)]; |
| j++; |
| } else { |
| done1 = 0; |
| } |
| (*ind)++; |
| } |
| part[j] = (picoos_char)NULLC; |
| if ((*ind) < stringlen) { |
| if ((string[(*ind)] == sepCh)) { |
| (*ind)++; /* skip separator character */ |
| } else if (string[(*ind)] == (picoos_char)NULLC) { |
| /* reached end of input; set ind to stringlen so that no |
| more (empty) partial strings will be found */ |
| (*ind) = stringlen; |
| } |
| } |
| (*done) = done1; |
| } |
| } |
| |
| /* *****************************************************************/ |
| /* timer function */ |
| /* *****************************************************************/ |
| |
| extern void picoos_get_timer(picopal_uint32 * sec, picopal_uint32 * usec) |
| { |
| picopal_get_timer(sec, usec); |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| |
| /* end */ |