diff options
author | Charles Chen <clchen@google.com> | 2009-06-22 16:25:25 -0700 |
---|---|---|
committer | Charles Chen <clchen@google.com> | 2009-06-22 17:14:37 -0700 |
commit | 1284d937084a20b457c280259fff59391129509a (patch) | |
tree | 5630028284c450b56a56b187d9c99cf7ebcee9cc /pico/lib/picoos.c | |
parent | f605ee98e5e03144c25a92af7e5d2a3ec33d375f (diff) | |
download | external_svox-1284d937084a20b457c280259fff59391129509a.zip external_svox-1284d937084a20b457c280259fff59391129509a.tar.gz external_svox-1284d937084a20b457c280259fff59391129509a.tar.bz2 |
Moving PicoTts plugin under the pico directory of external/svox
Diffstat (limited to 'pico/lib/picoos.c')
-rw-r--r-- | pico/lib/picoos.c | 2309 |
1 files changed, 2309 insertions, 0 deletions
diff --git a/pico/lib/picoos.c b/pico/lib/picoos.c new file mode 100644 index 0000000..4e2b439 --- /dev/null +++ b/pico/lib/picoos.c @@ -0,0 +1,2309 @@ +/* + * 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 */ |