Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /**
     17  * @file picoos.c
     18  *
     19  * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
     20  * All rights reserved.
     21  *
     22  * History:
     23  * - 2009-04-20 -- initial version
     24  *
     25  */
     26 
     27 #include <stdarg.h>
     28 #include "picodefs.h"
     29 #include "picopal.h"
     30 #include "picoos.h"
     31 #include "picodbg.h"
     32 
     33 #ifdef __cplusplus
     34 extern "C" {
     35 #endif
     36 #if 0
     37 }
     38 #endif
     39 
     40 
     41 #define picoos_SVOXFileHeader (picoos_char *)" (C) SVOX AG "
     42 
     43 /* **********************************************
     44  * default error and warning messages
     45  * **********************************************/
     46 
     47 
     48 #define PICOOS_MSG_EXC_NUMBER_FORMAT  (picoos_char *)  "wrong number format"
     49 #define PICOOS_MSG_EXC_MAX_NUM_EXCEED (picoos_char *)  "number exceeded"
     50 #define PICOOS_MSG_EXC_NAME_CONFLICT  (picoos_char *)  "name conflict"
     51 #define PICOOS_MSG_EXC_NAME_UNDEFINED (picoos_char *)  "name undefined"
     52 #define PICOOS_MSG_EXC_NAME_ILLEGAL   (picoos_char *)  "illegal name"
     53 
     54 /* buffer interaction */
     55 #define PICOOS_MSG_EXC_BUF_OVERFLOW   (picoos_char *)   "buffer overflow"
     56 #define PICOOS_MSG_EXC_BUF_UNDERFLOW  (picoos_char *)   "buffer underflow"
     57 #define PICOOS_MSG_EXC_BUF_IGNORE     (picoos_char *)   "buffer error"
     58 
     59 /* memory allocation */
     60 #define PICOOS_MSG_EXC_OUT_OF_MEM     (picoos_char *)   "out of memory"
     61 
     62 /* files */
     63 #define PICOOS_MSG_EXC_CANT_OPEN_FILE       (picoos_char *) "cannot open file"
     64 #define PICOOS_MSG_EXC_UNEXPECTED_FILE_TYPE (picoos_char *) "unexpected file type"
     65 #define PICOOS_MSG_EXC_FILE_CORRUPT         (picoos_char *) "corrupt file"
     66 #define PICOOS_MSG_EXC_FILE_NOT_FOUND       (picoos_char *) "file not found"
     67 
     68 /* resources */
     69 #define PICOOS_MSG_EXC_RESOURCE_BUSY         (picoos_char *)  "resource is busy"
     70 #define PICOOS_MSG_EXC_RESOURCE_MISSING      (picoos_char *)  "cannot find resource"
     71 
     72 /* knowledge bases */
     73 #define PICOOS_MSG_EXC_KB_MISSING     (picoos_char *)  "knowledge base missing"
     74 
     75 /* runtime exceptions (programming problems, usually a bug. E.g. trying to access null pointer) */
     76 #define PICOOS_MSG_ERR_NULLPTR_ACCESS     (picoos_char *)   "access violation"
     77 #define PICOOS_MSG_ERR_INVALID_HANDLE     (picoos_char *)   "invalid handle value"
     78 #define PICOOS_MSG_ERR_INVALID_ARGUMENT   (picoos_char *)   "invalid argument supplied"
     79 #define PICOOS_MSG_ERR_INDEX_OUT_OF_RANGE (picoos_char *)   "index out of range"
     80 
     81 
     82 /* errors ("external" errors, e.g. hardware failure. Usually cannot be dealt with from inside pico.) */
     83 #define PICOOS_MSG_ERR_OTHER         (picoos_char *) "other error"
     84 
     85 #define PICOOS_MSG_ERR_PU            (picoos_char *) "error in processing unit"
     86 
     87 /* WARNINGS */
     88 
     89 /* general */
     90 #define PICOOS_MSG_WARN_INCOMPLETE    (picoos_char *)  "incomplete output"
     91 #define PICOOS_MSG_WARN_FALLBACK      (picoos_char *)  "using fall-back"
     92 #define PICOOS_MSG_WARN_OTHER         (picoos_char *)  "other warning"
     93 
     94 /* resources */
     95 #define PICOOS_MSG_WARN_KB_OVERWRITE          (picoos_char *)  "overwriting knowledge base"
     96 #define PICOOS_MSG_WARN_RESOURCE_DOUBLE_LOAD  (picoos_char *)  "resource already loaded"
     97 
     98 /* decision trees */
     99 #define PICOOS_MSG_WARN_INVECTOR        (picoos_char *)  "input vector not constructed"
    100 #define PICOOS_MSG_WARN_CLASSIFICATION  (picoos_char *)  "output not classified"
    101 #define PICOOS_MSG_WARN_OUTVECTOR       (picoos_char *)  "output vector not decomposed"
    102 
    103 /* processing units */
    104 #define PICOOS_MSG_WARN_PU_IRREG_ITEM   (picoos_char *)  "irregular item in processing unit"
    105 #define PICOOS_MSG_WARN_PU_DISCARD_BUF  (picoos_char *)  "discarding processing unit buffer"
    106 
    107 
    108 /* **********************************************
    109  * wrappers for picopal functions
    110  * **********************************************/
    111 
    112 picoos_int32 picoos_atoi(const picoos_char *s)
    113 {
    114     return (picoos_int32)picopal_atoi((const picoos_char *)s);
    115 }
    116 
    117 
    118 picoos_int8 picoos_strcmp(const picoos_char *a, const picoos_char *b)
    119 {
    120     picopal_int32 res = picopal_strcmp((const picopal_char *)a,
    121             (const picopal_char *)b);
    122     return (picoos_int8) ((res < 0) ? -1 : (res > 0) ? 1 : 0);
    123 }
    124 picoos_int8 picoos_strncmp(const picoos_char *a, const picoos_char *b, picoos_objsize_t siz)
    125 {
    126     picopal_int32 res = picopal_strncmp((const picopal_char *)a,
    127             (const picopal_char *)b, siz);
    128     return (picoos_int8) ((res < 0) ? -1 : (res > 0) ? 1 : 0);
    129 }
    130 
    131 picoos_uint32 picoos_strlen(const picoos_char *s)
    132 {
    133     return (picoos_uint32)picopal_strlen((const picopal_char *)s);
    134 }
    135 
    136 picoos_char *picoos_strchr(const picoos_char *s, picoos_char c)
    137 {
    138     return (picoos_char *)picopal_strchr((const picopal_char *)s,
    139             (picopal_char)c);
    140 }
    141 
    142 picoos_char *picoos_strstr(const picoos_char *s, const picoos_char * substr)
    143 {
    144     return (picoos_char *)picopal_strstr((const picopal_char *)s,
    145             (const picopal_char *)substr);
    146 }
    147 
    148 picoos_int16 picoos_slprintf(picoos_char * b, picoos_uint32 bsize, const picoos_char *f, ...)
    149 {
    150     picopal_int16 i;
    151     va_list args;
    152 
    153     va_start(args, (char *)f);
    154     i = (picoos_int16)picopal_vslprintf((picoos_char *) b, bsize, (const picoos_char *)f, args);
    155     va_end(args);
    156     return i;
    157 }
    158 
    159 picoos_char *picoos_strcpy(picoos_char *d, const picoos_char *s)
    160 {
    161     return (picoos_char *)picopal_strcpy((picopal_char *)d,
    162             (const picopal_char *)s);
    163 }
    164 
    165 picoos_char *picoos_strcat(picoos_char *d, const picoos_char *s)
    166 {
    167     return (picoos_char *)picopal_strcat((picopal_char *)d,
    168             (const picopal_char *)s);
    169 }
    170 
    171 picoos_objsize_t picoos_strlcpy(picoos_char *dst, const picoos_char *src, picoos_objsize_t siz)
    172 {
    173     return (picoos_objsize_t) picopal_strlcpy((picopal_char *) dst, (const picopal_char *) src, (picopal_objsize_t) siz);
    174 }
    175 
    176 /* copies 'length' bytes from 'src' to 'dest'. (regions may be overlapping) no error checks! */
    177 void * picoos_mem_copy(const void * src, void * dst,  picoos_objsize_t length)
    178 {
    179     return picopal_mem_copy(src,dst,(picopal_objsize_t) length);
    180 }
    181 
    182 /* sets 'length' bytes starting at dest[0] to 'byte_val' */
    183 void * picoos_mem_set(void * dest, picoos_uint8 byte_val, picoos_objsize_t length) {
    184           return picopal_mem_set(dest,(picopal_uint8)byte_val, (picopal_objsize_t)length);
    185 }
    186 
    187 
    188 picoos_double picoos_cos (const picoos_double cos_arg)
    189 {
    190     return (picoos_double) picopal_cos ((picopal_double) cos_arg);
    191 }
    192 
    193 
    194 picoos_double picoos_sin (const picoos_double sin_arg)
    195 {
    196     return (picoos_double) picopal_sin((picopal_double) sin_arg);
    197 }
    198 picoos_double picoos_fabs (const picoos_double fabs_arg)
    199 {
    200     return (picoos_double) picopal_fabs((picopal_double) fabs_arg);
    201 }
    202 
    203 picoos_double picoos_quick_exp(const picoos_double y) {
    204     return (picoos_double) picopal_quick_exp ((picopal_double)y);
    205 }
    206 
    207 
    208 /* *****************************************************************/
    209 /* "Common"                                                        */
    210 /* *****************************************************************/
    211 /* picoos_common is a collection of basic functionalities that must be globally
    212  * accessible from every "big" function. It includes pointers to the MemoryManasger,
    213  * ExceptionManager and a system-wide list of open files. */
    214 
    215 picoos_Common picoos_newCommon(picoos_MemoryManager mm)
    216 {
    217     picoos_Common this = (picoos_Common) picoos_allocate(mm,sizeof(*this));
    218     if (NULL != this) {
    219         /* initialize */
    220         this->em = NULL;
    221         this->mm = NULL;
    222         this->fileList = NULL;
    223     }
    224     return this;
    225 }
    226 
    227 void picoos_disposeCommon(picoos_MemoryManager mm, picoos_Common * this)
    228 {
    229     if (NULL != (*this)) {
    230         /* terminate */
    231         picoos_deallocate(mm,(void *)this);
    232     }
    233 }
    234 
    235 
    236 /* *****************************************************************/
    237 /* Memory Management                                               */
    238 /* *****************************************************************/
    239 
    240 typedef struct mem_block_hdr * MemBlockHdr;
    241 typedef struct mem_block_hdr
    242 {
    243     MemBlockHdr next;
    244     byte_ptr_t data;
    245     picoos_objsize_t size;
    246 } mem_block_hdr_t;
    247 
    248 typedef struct mem_cell_hdr * MemCellHdr;
    249 typedef struct mem_cell_hdr
    250 {
    251     /* size may be <0 if used */
    252     picoos_ptrdiff_t size;
    253     MemCellHdr leftCell;
    254     MemCellHdr prevFree, nextFree;
    255 } mem_cell_hdr_t;
    256 
    257 typedef struct memory_manager
    258 {
    259     MemBlockHdr firstBlock, lastBlock; /* memory blockList */
    260     MemCellHdr freeCells, lastFree; /* free memory cells (first/last sentinel */
    261     /* "constants" */
    262     picoos_objsize_t fullCellHdrSize; /* aligned size of full cell header, including free-links */
    263     picoos_objsize_t usedCellHdrSize; /* aligned size of header part without free-links */
    264     picoos_objsize_t minContSize; /* minimum requestable application content size for allocation;
    265      must hold free-list info; = fullCellHdrSize-usedCellHdrSize */
    266     picoos_objsize_t minCellSize; /* minimum remaining cell size when a free cell is split */
    267     picoos_bool protMem;  /* true if memory protection is enabled */
    268     picoos_ptrdiff_t usedSize;
    269     picoos_ptrdiff_t prevUsedSize;
    270     picoos_ptrdiff_t maxUsedSize;
    271 } memory_manager_t;
    272 
    273 /** allocates 'alloc_size' bytes at start of raw memory block ('raw_mem',raw_mem_size)
    274  *  and returns pointer to allocated region. Returns remaining (correctly aligned) raw memory block
    275  *  in ('rest_mem','rest_mem_size').
    276  *  The allocated memory is not subject to memory management, so that it can never be freed again!
    277  *
    278  */
    279 void * picoos_raw_malloc(byte_ptr_t raw_mem,
    280         picoos_objsize_t raw_mem_size, picoos_objsize_t alloc_size,
    281         byte_ptr_t * rest_mem, picoos_objsize_t * rest_mem_size)
    282 {
    283     picoos_ptrdiff_t rest;
    284     if (raw_mem == NULL) {
    285         return NULL;
    286     } else {
    287         if (alloc_size < 1) {
    288             alloc_size = 1;
    289         }
    290         alloc_size = ((alloc_size + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE)
    291                 * PICOOS_ALIGN_SIZE;
    292 
    293         rest = raw_mem_size - alloc_size;
    294         if (rest < 0) {
    295             return NULL;
    296         } else {
    297             *rest_mem_size = rest;
    298             *rest_mem = raw_mem + alloc_size;
    299             return (void *) raw_mem;
    300         }
    301     }
    302 }
    303 
    304 /** initializes the last block of mm */
    305 static int os_init_mem_block(picoos_MemoryManager this)
    306 {
    307     int isFirstBlock;
    308     void * newBlockAddr;
    309     picoos_objsize_t size;
    310     MemCellHdr cbeg, cmid, cend;
    311 
    312     isFirstBlock = (this->freeCells == NULL);
    313     newBlockAddr = (void *) this->lastBlock->data;
    314     size = this->lastBlock->size;
    315     cbeg = (MemCellHdr) newBlockAddr;
    316     cmid = (MemCellHdr)((picoos_objsize_t)newBlockAddr + this->fullCellHdrSize);
    317     cend = (MemCellHdr)((picoos_objsize_t)newBlockAddr + size
    318             - this->fullCellHdrSize);
    319     cbeg->size = 0;
    320 
    321     cbeg->leftCell = NULL;
    322     cmid->size = size - 2 * this->fullCellHdrSize;
    323     cmid->leftCell = cbeg;
    324     cend->size = 0;
    325     cend->leftCell = cmid;
    326     if (isFirstBlock) {
    327         cbeg->nextFree = cmid;
    328         cbeg->prevFree = NULL;
    329         cmid->nextFree = cend;
    330         cmid->prevFree = cbeg;
    331         cend->nextFree = NULL;
    332         cend->prevFree = cmid;
    333         this->freeCells = cbeg;
    334         this->lastFree = cend;
    335     } else {
    336         /* add cmid to free cell list */
    337         cbeg->nextFree = NULL;
    338         cbeg->prevFree = NULL;
    339         cmid->nextFree = this->freeCells->nextFree;
    340         cmid->prevFree = this->freeCells;
    341         cmid->nextFree->prevFree = cmid;
    342         cmid->prevFree->nextFree = cmid;
    343         cend->nextFree = NULL;
    344         cbeg->prevFree = NULL;
    345     }
    346     return PICO_OK;
    347 }
    348 
    349 
    350 picoos_MemoryManager picoos_newMemoryManager(
    351         void *raw_memory,
    352         picoos_objsize_t size,
    353         picoos_bool enableMemProt)
    354 {
    355     byte_ptr_t rest_mem;
    356     picoos_objsize_t rest_mem_size;
    357     picoos_MemoryManager this;
    358     picoos_objsize_t size2;
    359     mem_cell_hdr_t test_cell;
    360 
    361     this = picoos_raw_malloc(raw_memory, size, sizeof(memory_manager_t),
    362             &rest_mem, &rest_mem_size);
    363     if (this == NULL) {
    364         return NULL;
    365     }
    366 
    367     /* test if memory protection functionality is available on the current
    368        platform (if not, picopal_mpr_alloc() always returns NULL) */
    369     if (enableMemProt) {
    370         void *addr = picopal_mpr_alloc(100);
    371         if (addr == NULL) {
    372             enableMemProt = FALSE;
    373         } else {
    374             picopal_mpr_free(&addr);
    375         }
    376     }
    377 
    378     this->firstBlock = NULL;
    379     this->lastBlock = NULL;
    380     this->freeCells = NULL;
    381     this->lastFree = NULL;
    382 
    383     this->protMem = enableMemProt;
    384     this->usedSize = 0;
    385     this->prevUsedSize = 0;
    386     this->maxUsedSize = 0;
    387 
    388     /* get aligned full header size */
    389     this->fullCellHdrSize = ((sizeof(mem_cell_hdr_t) + PICOOS_ALIGN_SIZE - 1)
    390             / PICOOS_ALIGN_SIZE) * PICOOS_ALIGN_SIZE;
    391     /* get aligned size of header without free-list fields; the result may be compiler-dependent;
    392      the size is therefore computed by inspecting the end addresses of the fields 'size' and 'leftCell';
    393      the higher of the ending addresses is used to get the (aligned) starting address
    394      of the application contents */
    395     this->usedCellHdrSize = (picoos_objsize_t) &test_cell.size
    396             - (picoos_objsize_t) &test_cell + sizeof(picoos_objsize_t);
    397     size2 = (picoos_objsize_t) &test_cell.leftCell - (picoos_objsize_t)
    398             &test_cell + sizeof(MemCellHdr);
    399     if (size2 > this->usedCellHdrSize) {
    400         this->usedCellHdrSize = size2;
    401     }
    402     /* get minimum application-usable size; must be large enough to hold remainder of
    403      cell header (free-list links) when in free-list */
    404     this->minContSize = this->fullCellHdrSize - this->usedCellHdrSize;
    405     /* get minimum required size of a cell remaining after a cell split */
    406     this->minCellSize = this->fullCellHdrSize + PICOOS_ALIGN_SIZE;
    407 
    408     /* install remainder of raw memory block as first block */
    409     raw_memory = rest_mem;
    410     size = rest_mem_size;
    411     this->firstBlock = this->lastBlock = picoos_raw_malloc(raw_memory, size,
    412             sizeof(mem_block_hdr_t), &rest_mem, &rest_mem_size);
    413     if (this->lastBlock == NULL) {
    414         return NULL;
    415     }
    416     this->lastBlock->next = NULL;
    417     this->lastBlock->data = rest_mem;
    418     this->lastBlock->size = rest_mem_size;
    419 
    420     os_init_mem_block(this);
    421 
    422     return this;
    423 }
    424 
    425 void picoos_disposeMemoryManager(picoos_MemoryManager * mm)
    426 {
    427     *mm = NULL;
    428 }
    429 
    430 
    431 /* the following memory manager routines are for testing and
    432    debugging purposes */
    433 
    434 
    435 void *picoos_allocProtMem(picoos_MemoryManager mm, picoos_objsize_t byteSize)
    436 {
    437     if (mm->protMem) {
    438         return picopal_mpr_alloc(byteSize);
    439     } else {
    440         return picoos_allocate(mm, byteSize);
    441     }
    442 }
    443 
    444 
    445 void picoos_deallocProtMem(picoos_MemoryManager mm, void **addr)
    446 {
    447     if (mm->protMem) {
    448         picopal_mpr_free(addr);
    449     } else {
    450         picoos_deallocate(mm, addr);
    451     }
    452 }
    453 
    454 
    455 void picoos_protectMem(
    456         picoos_MemoryManager mm,
    457         void *addr,
    458         picoos_objsize_t len,
    459         picoos_bool enable)
    460 {
    461     if (mm->protMem) {
    462         int prot = PICOPAL_PROT_READ;
    463         if (!enable) {
    464             prot |= PICOPAL_PROT_WRITE;
    465         }
    466         picopal_mpr_protect(addr, len, prot);
    467     } else {
    468         /* memory protection disabled; nothing to do */
    469     }
    470 }
    471 
    472 #define PICOPAL_PROT_NONE   0   /* the memory cannot be accessed at all */
    473 #define PICOPAL_PROT_READ   1   /* the memory can be read */
    474 #define PICOPAL_PROT_WRITE  2   /* the memory can be written to */
    475 
    476 void picoos_getMemUsage(
    477         picoos_MemoryManager this,
    478         picoos_bool resetIncremental,
    479         picoos_int32 *usedBytes,
    480         picoos_int32 *incrUsedBytes,
    481         picoos_int32 *maxUsedBytes)
    482 {
    483     *usedBytes = (picoos_int32) this->usedSize;
    484     *incrUsedBytes = (picoos_int32) (this->usedSize - this->prevUsedSize);
    485     *maxUsedBytes = (picoos_int32) this->maxUsedSize;
    486     if (resetIncremental) {
    487         this->prevUsedSize = this->usedSize;
    488     }
    489 }
    490 
    491 
    492 void picoos_showMemUsage(picoos_MemoryManager this, picoos_bool incremental,
    493         picoos_bool resetIncremental)
    494 {
    495     picoos_int32 usedBytes, incrUsedBytes, maxUsedBytes;
    496 
    497     picoos_getMemUsage(this, resetIncremental, &usedBytes, &incrUsedBytes,
    498             &maxUsedBytes);
    499     if (incremental) {
    500         PICODBG_DEBUG(("additional memory used: %d", incrUsedBytes));
    501     } else {
    502         PICODBG_DEBUG(("memory used: %d, maximally used: %d", usedBytes, maxUsedBytes));
    503     }
    504 }
    505 
    506 
    507 void * picoos_allocate(picoos_MemoryManager this,
    508         picoos_objsize_t byteSize)
    509 {
    510 
    511     picoos_objsize_t cellSize;
    512     MemCellHdr c, c2, c2r;
    513     void * adr;
    514 
    515     if (byteSize < this->minContSize) {
    516         byteSize = this->minContSize;
    517     }
    518     byteSize = ((byteSize + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE)
    519             * PICOOS_ALIGN_SIZE;
    520 
    521     cellSize = byteSize + this->usedCellHdrSize;
    522     /*PICODBG_TRACE(("allocating %d", cellSize));*/
    523     c = this->freeCells->nextFree;
    524     while (
    525             (c != NULL) &&
    526             (c->size != (picoos_ptrdiff_t) cellSize) &&
    527             (c->size < (picoos_ptrdiff_t)(cellSize+ this->minCellSize))) {
    528         c = c->nextFree;
    529     }
    530     if (c == NULL) {
    531         return NULL;
    532     }
    533     if ((c->size == (picoos_ptrdiff_t) cellSize)) {
    534         c->prevFree->nextFree = c->nextFree;
    535         c->nextFree->prevFree = c->prevFree;
    536     } else {
    537         c2 = (MemCellHdr)((picoos_objsize_t)c + cellSize);
    538         c2->size = c->size - cellSize;
    539         c->size = cellSize;
    540         c2->leftCell = c;
    541         c2r = (MemCellHdr)((picoos_objsize_t)c2 + c2->size);
    542         c2r->leftCell = c2;
    543         c2->nextFree = c->nextFree;
    544         c2->nextFree->prevFree = c2;
    545         c2->prevFree = c->prevFree;
    546         c2->prevFree->nextFree = c2;
    547     }
    548 
    549     /* statistics */
    550     this->usedSize += cellSize;
    551     if (this->usedSize > this->maxUsedSize) {
    552         this->maxUsedSize = this->usedSize;
    553     }
    554 
    555     c->size = -(c->size);
    556     adr = (void *)((picoos_objsize_t)c + this->usedCellHdrSize);
    557     return adr;
    558 }
    559 
    560 void picoos_deallocate(picoos_MemoryManager this, void * * adr)
    561 {
    562     MemCellHdr c;
    563     MemCellHdr cr;
    564     MemCellHdr cl;
    565     MemCellHdr crr;
    566 
    567 
    568     if ((*adr) != NULL) {
    569         c = (MemCellHdr)((picoos_objsize_t)(*adr) - this->usedCellHdrSize);
    570         c->size = -(c->size);
    571 
    572         /*PICODBG_TRACE(("deallocating %d", c->size));*/
    573         /* statistics */
    574         this->usedSize -= c->size;
    575 
    576         cr = (MemCellHdr)((picoos_objsize_t)c + c->size);
    577         cl = c->leftCell;
    578         if (cl->size > 0) {
    579             if (cr->size > 0) {
    580                 crr = (MemCellHdr)((picoos_objsize_t)cr + cr->size);
    581                 crr->leftCell = cl;
    582                 cl->size = ((cl->size + c->size) + cr->size);
    583                 cr->nextFree->prevFree = cr->prevFree;
    584                 cr->prevFree->nextFree = cr->nextFree;
    585             } else {
    586                 cl->size = (cl->size + c->size);
    587                 cr->leftCell = cl;
    588             }
    589         } else {
    590             if ((cr->size > 0)) {
    591                 crr = (MemCellHdr)((picoos_objsize_t)cr + cr->size);
    592                 crr->leftCell = c;
    593                 c->size = (c->size + cr->size);
    594                 c->nextFree = cr->nextFree;
    595                 c->prevFree = cr->prevFree;
    596                 c->nextFree->prevFree = c;
    597                 c->prevFree->nextFree = c;
    598             } else {
    599                 c->nextFree = this->freeCells->nextFree;
    600                 c->prevFree = this->freeCells;
    601                 c->nextFree->prevFree = c;
    602                 c->prevFree->nextFree = c;
    603             }
    604         }
    605     }
    606     *adr = NULL;
    607 }
    608 
    609 /* *****************************************************************/
    610 /* Exception Management                                                */
    611 /* *****************************************************************/
    612 /**  object   : exceptionManager
    613  *   shortcut : em
    614  *
    615  */
    616 
    617 typedef picoos_char picoos_exc_msg[PICOOS_MAX_EXC_MSG_LEN];
    618 typedef picoos_char picoos_warn_msg[PICOOS_MAX_WARN_MSG_LEN];
    619 
    620 typedef struct picoos_exception_manager
    621 {
    622     picoos_int32 curExceptionCode;
    623     picoos_exc_msg curExceptionMessage;
    624 
    625     picoos_uint8 curNumWarnings;
    626     picoos_int32 curWarningCode[PICOOS_MAX_NUM_WARNINGS];
    627     picoos_warn_msg curWarningMessage[PICOOS_MAX_NUM_WARNINGS];
    628 
    629 } picoos_exception_manager_t;
    630 
    631 void picoos_emReset(picoos_ExceptionManager this)
    632 {
    633     this->curExceptionCode = PICO_OK;
    634     this->curExceptionMessage[0] = '\0';
    635     this->curNumWarnings = 0;
    636 }
    637 
    638 picoos_ExceptionManager picoos_newExceptionManager(picoos_MemoryManager mm)
    639 {
    640     picoos_ExceptionManager this = (picoos_ExceptionManager) picoos_allocate(
    641             mm, sizeof(*this));
    642     if (NULL != this) {
    643         /* initialize */
    644         picoos_emReset(this);
    645     }
    646     return this;
    647 }
    648 
    649 void picoos_disposeExceptionManager(picoos_MemoryManager mm,
    650         picoos_ExceptionManager * this)
    651 {
    652     if (NULL != (*this)) {
    653         /* terminate */
    654         picoos_deallocate(mm, (void *)this);
    655     }
    656 }
    657 
    658 static void picoos_vSetErrorMsg(picoos_char * dst, picoos_objsize_t siz,
    659         picoos_int16 code, picoos_char * base, const picoos_char *fmt, va_list args)
    660 {
    661     picoos_uint16 bsize;
    662 
    663     if (NULL == base) {
    664         switch (code) {
    665             case PICO_EXC_NUMBER_FORMAT:
    666                 base = PICOOS_MSG_EXC_NUMBER_FORMAT;
    667                 break;
    668             case PICO_EXC_MAX_NUM_EXCEED:
    669                 base = PICOOS_MSG_EXC_MAX_NUM_EXCEED;
    670                 break;
    671             case PICO_EXC_NAME_CONFLICT:
    672                 base = PICOOS_MSG_EXC_NAME_CONFLICT;
    673                 break;
    674             case PICO_EXC_NAME_UNDEFINED:
    675                 base = PICOOS_MSG_EXC_NAME_UNDEFINED;
    676                 break;
    677             case PICO_EXC_NAME_ILLEGAL:
    678                 base = PICOOS_MSG_EXC_NAME_ILLEGAL;
    679                 break;
    680 
    681                 /* buffer interaction */
    682             case PICO_EXC_BUF_OVERFLOW:
    683                 base = PICOOS_MSG_EXC_BUF_OVERFLOW;
    684                 break;
    685             case PICO_EXC_BUF_UNDERFLOW:
    686                 base = PICOOS_MSG_EXC_BUF_UNDERFLOW;
    687                 break;
    688             case PICO_EXC_BUF_IGNORE:
    689                 base = PICOOS_MSG_EXC_BUF_IGNORE;
    690                 break;
    691 
    692                 /* memory allocation */
    693             case PICO_EXC_OUT_OF_MEM:
    694                 base = PICOOS_MSG_EXC_OUT_OF_MEM;
    695                 break;
    696 
    697                 /* files */
    698             case PICO_EXC_CANT_OPEN_FILE:
    699                 base = PICOOS_MSG_EXC_CANT_OPEN_FILE;
    700                 break;
    701             case PICO_EXC_UNEXPECTED_FILE_TYPE:
    702                 base = PICOOS_MSG_EXC_UNEXPECTED_FILE_TYPE;
    703                 break;
    704             case PICO_EXC_FILE_CORRUPT:
    705                 base = PICOOS_MSG_EXC_FILE_CORRUPT;
    706                 break;
    707 
    708             case PICO_EXC_FILE_NOT_FOUND:
    709                 base = PICOOS_MSG_EXC_FILE_NOT_FOUND;
    710                 break;
    711 
    712                 /* resources */
    713             case PICO_EXC_RESOURCE_BUSY:
    714                 base = PICOOS_MSG_EXC_RESOURCE_BUSY;
    715                 break;
    716             case PICO_EXC_RESOURCE_MISSING:
    717                 base = PICOOS_MSG_EXC_RESOURCE_MISSING;
    718                 break;
    719 
    720                 /* knowledge bases */
    721             case PICO_EXC_KB_MISSING:
    722                 fmt = PICOOS_MSG_EXC_KB_MISSING;
    723                 break;
    724 
    725                 /* runtime exceptions (programming problems, usually a bug. E.g. trying to access null pointer) */
    726             case PICO_ERR_NULLPTR_ACCESS:
    727                 base = PICOOS_MSG_ERR_NULLPTR_ACCESS;
    728                 break;
    729             case PICO_ERR_INVALID_HANDLE:
    730                 base = PICOOS_MSG_ERR_INVALID_HANDLE;
    731                 break;
    732             case PICO_ERR_INVALID_ARGUMENT:
    733                 base = PICOOS_MSG_ERR_INVALID_ARGUMENT;
    734                 break;
    735             case PICO_ERR_INDEX_OUT_OF_RANGE:
    736                 base = PICOOS_MSG_ERR_INDEX_OUT_OF_RANGE;
    737                 break;
    738 
    739                 /* errors ("external" errors, e.g. hardware failure. Usually cannot be dealt with from inside pico.) */
    740             case PICO_ERR_OTHER:
    741                 base = PICOOS_MSG_ERR_OTHER;
    742                 break;
    743 
    744                 /* other error inside pu */
    745             case PICO_STEP_ERROR:
    746                 base = PICOOS_MSG_ERR_PU;
    747                 break;
    748 
    749                 /* WARNINGS */
    750 
    751                 /* general */
    752             case PICO_WARN_INCOMPLETE:
    753                 base = PICOOS_MSG_WARN_INCOMPLETE;
    754                 break;
    755             case PICO_WARN_FALLBACK:
    756                 base = PICOOS_MSG_WARN_FALLBACK;
    757                 break;
    758 
    759             case PICO_WARN_OTHER:
    760                 base = PICOOS_MSG_WARN_OTHER;
    761                 break;
    762 
    763                 /* resources */
    764             case PICO_WARN_KB_OVERWRITE:
    765                 base = PICOOS_MSG_WARN_KB_OVERWRITE;
    766                 break;
    767             case PICO_WARN_RESOURCE_DOUBLE_LOAD:
    768                 base = PICOOS_MSG_WARN_RESOURCE_DOUBLE_LOAD;
    769                 break;
    770 
    771                 /* decision trees */
    772             case PICO_WARN_INVECTOR:
    773                 base = PICOOS_MSG_WARN_INVECTOR;
    774                 break;
    775             case PICO_WARN_CLASSIFICATION:
    776                 base = PICOOS_MSG_WARN_CLASSIFICATION;
    777                 break;
    778             case PICO_WARN_OUTVECTOR:
    779                 base = PICOOS_MSG_WARN_OUTVECTOR;
    780                 break;
    781 
    782                 /* processing units */
    783             case PICO_WARN_PU_IRREG_ITEM:
    784                 base = PICOOS_MSG_WARN_PU_IRREG_ITEM;
    785                 break;
    786             case PICO_WARN_PU_DISCARD_BUF:
    787                 base = PICOOS_MSG_WARN_PU_DISCARD_BUF;
    788                 break;
    789 
    790             default:
    791                 base = (picoos_char *) "unknown error";
    792                 break;
    793         }
    794     }
    795     bsize = picoos_strlcpy(dst,base,siz);
    796     if ((NULL != fmt) && (bsize < siz)) { /* there is something to add and more space to add it */
    797         if (bsize > 0) {
    798             dst += bsize;
    799             siz -= bsize;
    800             bsize = picoos_strlcpy(dst,(picoos_char *)": ",siz);
    801         }
    802         if (bsize < siz) {
    803             picopal_vslprintf((picopal_char *) dst + bsize, siz - bsize, (picopal_char *)fmt, args);
    804         }
    805     }
    806 }
    807 
    808 void picoos_setErrorMsg(picoos_char * dst, picoos_objsize_t siz,
    809         picoos_int16 code, picoos_char * base, const picoos_char *fmt, ...)
    810 {
    811     va_list args;
    812     va_start(args, (char *)fmt);
    813     picoos_vSetErrorMsg(dst,siz, code, base, fmt,args);
    814     va_end(args);
    815 }
    816 
    817 /* For convenience, this function returns the resulting current exception code. The return value therefore is NOT the status of raising
    818  * the error! */
    819 pico_status_t picoos_emRaiseException(picoos_ExceptionManager this,
    820         pico_status_t exceptionCode, picoos_char * baseMessage, picoos_char * fmt, ...)
    821 {
    822     va_list args;
    823 
    824 
    825     if (PICO_OK == this->curExceptionCode && PICO_OK != exceptionCode) {
    826         this->curExceptionCode = exceptionCode;
    827         va_start(args, (char *)fmt);
    828         picoos_vSetErrorMsg(this->curExceptionMessage,PICOOS_MAX_EXC_MSG_LEN, exceptionCode, baseMessage, fmt,args);
    829         PICODBG_DEBUG((
    830             "exit with exception code=%i, exception message='%s'",
    831             this->curExceptionCode, this->curExceptionMessage));
    832 
    833         va_end(args);
    834 
    835     }
    836     return this->curExceptionCode;
    837 }
    838 
    839 pico_status_t picoos_emGetExceptionCode(picoos_ExceptionManager this)
    840 {
    841     return this->curExceptionCode;
    842 }
    843 
    844 void picoos_emGetExceptionMessage(picoos_ExceptionManager this, picoos_char * msg, picoos_uint16 maxsize)
    845 {
    846         picoos_strlcpy(msg,this->curExceptionMessage,maxsize);
    847 }
    848 
    849 void picoos_emRaiseWarning(picoos_ExceptionManager this,
    850         pico_status_t warningCode, picoos_char * baseMessage, picoos_char * fmt, ...)
    851 {
    852     va_list args;
    853     if ((this->curNumWarnings < PICOOS_MAX_NUM_WARNINGS) && (PICO_OK != warningCode)) {
    854         if (PICOOS_MAX_NUM_WARNINGS-1 == this->curNumWarnings) {
    855             this->curWarningCode[this->curNumWarnings] = PICO_EXC_MAX_NUM_EXCEED;
    856             picoos_strlcpy(this->curWarningMessage[this->curNumWarnings],(picoos_char *) "too many warnings",PICOOS_MAX_WARN_MSG_LEN);
    857         } else {
    858             this->curWarningCode[this->curNumWarnings] = warningCode;
    859             va_start(args, (char *)fmt);
    860             picoos_vSetErrorMsg(this->curWarningMessage[this->curNumWarnings],PICOOS_MAX_WARN_MSG_LEN, warningCode, baseMessage, fmt,args);
    861             va_end(args);
    862         }
    863         this->curNumWarnings++;
    864     }
    865     PICODBG_DEBUG((
    866         "exit with code=%i and message='%s', resulting in #warnings=%i",
    867         this->curWarningCode[this->curNumWarnings-1],
    868         this->curWarningMessage[this->curNumWarnings-1],
    869         this->curNumWarnings));
    870 }
    871 
    872 picoos_uint8 picoos_emGetNumOfWarnings(picoos_ExceptionManager this)
    873 {
    874     return this->curNumWarnings;
    875 }
    876 
    877 pico_status_t picoos_emGetWarningCode(picoos_ExceptionManager this, picoos_uint8 index)
    878 {
    879     if (index < this->curNumWarnings) {
    880       return this->curWarningCode[index];
    881     } else {
    882         return PICO_OK;
    883     }
    884 }
    885 
    886 void picoos_emGetWarningMessage(picoos_ExceptionManager this, picoos_uint8 index, picoos_char * msg, picoos_uint16 maxsize)
    887 {
    888         if (index < this->curNumWarnings) {
    889             picoos_strlcpy(msg,this->curWarningMessage[index],maxsize);
    890         } else {
    891             msg[0] = NULLC;
    892         }
    893 }
    894 
    895 
    896 
    897 
    898 /* *****************************************************************/
    899 /* File Access                                                     */
    900 /* *****************************************************************/
    901 
    902 #define picoos_MagicNumber 192837465
    903 #define picoos_MaxBufSize 1000000
    904 #define picoos_MaxNrOfBuffers 1000000
    905 #define picoos_MaxBufLen 8192
    906 #define picoos_HashFuncId0 0
    907 #define picoos_HashTableSize0 101
    908 #define picoos_HashTableSize1 1731
    909 #define picoos_MaxHashTableSize HashTableSize1
    910 
    911 #define cardinal_ptr_t picoos_uint32 *
    912 
    913 typedef struct picoos_buffer
    914 {
    915     picoos_char * data;
    916     int start; /* denotes the file position of the buffer beginning */
    917     int len; /* denotes the length of the buffer; -1 means invalid buffer */
    918     int pos; /* denotes the position in the buffer */
    919 } picoos_buffer_t;
    920 
    921 typedef picoos_buffer_t picoos_buffer_array_t[picoos_MaxNrOfBuffers];
    922 typedef picoos_int32 picoos_buffer_index_array_t[picoos_MaxNrOfBuffers];
    923 
    924 /**  object   : File
    925  *   shortcut : f
    926  *
    927  */
    928 typedef struct picoos_file
    929 {
    930     picoos_FileName name;
    931     picoos_uint8 binary;
    932     picoos_uint8 write;
    933 
    934     picopal_File nf;
    935 
    936     picoos_uint32 lFileLen;
    937     picoos_uint32 lPos;
    938 
    939     picoos_File next;
    940     picoos_File prev;
    941 
    942 } picoos_file_t;
    943 
    944 picoos_File picoos_newFile(picoos_MemoryManager mm)
    945 {
    946     picoos_File this = (picoos_File) picoos_allocate(mm, sizeof(*this));
    947     if (NULL != this) {
    948         /* initialize */
    949     }
    950     return this;
    951 }
    952 
    953 void picoos_disposeFile(picoos_MemoryManager mm, picoos_File * this)
    954 {
    955     if (NULL != (*this)) {
    956         /* terminate */
    957         picoos_deallocate(mm, (void *)this);
    958     }
    959 }
    960 
    961 
    962 /* ************************************************************
    963  * low-level file operations
    964  **************************************************************/
    965 
    966 static picoos_int32 os_min(const picoos_int32 x, const picoos_int32 y)
    967 {
    968     return (x < y) ? x : y;
    969 }
    970 
    971 /*
    972  static picoos_uint8 LReadChar (picoos_File f, picoos_char * ch);
    973 
    974 
    975  static picoos_uint8 LSetPos (picoos_File f, unsigned int pos);
    976 
    977 
    978  static picoos_uint8 LGetPos (picoos_File f, picoos_uint32 * pos);
    979 
    980 
    981  static picoos_uint8 LEof (picoos_File f);
    982  */
    983 
    984 static picoos_bool LOpen(picoos_Common g, picoos_File * f,
    985         picoos_char fileName[], picopal_access_mode mode)
    986 {
    987     picoos_bool done = TRUE;
    988 
    989     *f = picoos_newFile(g->mm);
    990     picopal_strcpy((*f)->name, fileName);
    991     (*f)->write = ((mode == PICOPAL_TEXT_WRITE) || (mode
    992             == PICOPAL_BINARY_WRITE));
    993     (*f)->binary = (mode
    994             == PICOPAL_BINARY_WRITE);
    995     (*f)->next = NULL;
    996     (*f)->prev = NULL;
    997     (*f)->nf = picopal_get_fnil();
    998     (*f)->lFileLen = 0;
    999     (*f)->lPos = 0;
   1000     if (picopal_strlen((*f)->name)) {
   1001        (*f)->nf = picopal_fopen((*f)->name, mode);
   1002         done = !(picopal_is_fnil((*f)->nf));
   1003         if (done) {
   1004             (*f)->lFileLen = picopal_flength((*f)->nf);
   1005         }
   1006     }
   1007     if (done) {
   1008         (*f)->next = g->fileList;
   1009         if (g->fileList != NULL) {
   1010             g->fileList->prev = (*f);
   1011         }
   1012         g->fileList = (*f);
   1013     } else {
   1014         picoos_disposeFile(g->mm, f);
   1015         (*f) = NULL;
   1016     }
   1017     return done;
   1018 }
   1019 
   1020 static picoos_bool LClose(picoos_Common g, picoos_File * f)
   1021 {
   1022 
   1023     picoos_bool done;
   1024 
   1025     if (((*f) != NULL)) {
   1026         done = (PICO_OK == picopal_fclose((*f)->nf));
   1027         if (((*f)->next != NULL)) {
   1028             (*f)->next->prev = (*f)->prev;
   1029         }
   1030         if (((*f)->prev != NULL)) {
   1031             (*f)->prev->next = (*f)->next;
   1032         } else {
   1033             g->fileList = (*f)->next;
   1034         }
   1035         picoos_disposeFile(g->mm, f);
   1036 
   1037         done = TRUE;
   1038     } else {
   1039         done = FALSE;
   1040     }
   1041     return done;
   1042 
   1043 }
   1044 
   1045 /* caller must ensure that bytes[] has at least len allocated bytes */
   1046 static picoos_bool LReadBytes(picoos_File f, picoos_uint8 bytes[],
   1047         picoos_uint32 * len)
   1048 {
   1049     picoos_bool done;
   1050     picoos_int32 res;
   1051 
   1052     PICODBG_TRACE(("trying to read %i bytes",*len));
   1053     if ((f != NULL)) {
   1054         res = picopal_fread_bytes(f->nf, (void *) &bytes[(0)], 1, (*len));
   1055         PICODBG_TRACE(("res = %i",res));
   1056         if (res < 0) { /* non-ansi */
   1057             (*len) = 0;
   1058             done = FALSE;
   1059         } else if (((picoos_uint32)res != (*len))) {
   1060             (*len) = res;
   1061             done = FALSE;
   1062         } else {
   1063             done = TRUE;
   1064         }
   1065         f->lPos = (f->lPos + (*len));
   1066     } else {
   1067         (*len) = 0;
   1068         done = FALSE;
   1069     }
   1070     return done;
   1071 }
   1072 
   1073  static picoos_bool LWriteBytes(picoos_File f, const picoos_char bytes[], int * len) {
   1074     picoos_bool done;
   1075     int res;
   1076     /*int n;
   1077     void * bptr; */
   1078 
   1079     if (f != NULL) {
   1080         res = picopal_fwrite_bytes(f->nf, (void *) bytes, 1, *len);
   1081         if ((res < 0)) {
   1082             (*len) = 0;
   1083             done = FALSE;
   1084         } else if ((res != (*len))) {
   1085             (*len) = res;
   1086             done = FALSE;
   1087         } else {
   1088             done = TRUE;
   1089         }
   1090         f->lPos = (f->lPos + (unsigned int) (*len));
   1091         if ((f->lPos > f->lFileLen)) {
   1092             f->lFileLen = f->lPos;
   1093         }
   1094     } else {
   1095         (*len) = 0;
   1096         done = FALSE;
   1097     }
   1098     return done;
   1099 }
   1100 
   1101 
   1102 static picoos_bool LSetPos(picoos_File f, unsigned int pos)
   1103 {
   1104 
   1105     picoos_bool done;
   1106 
   1107     if ((f != NULL)) {
   1108         if ((pos == f->lPos)) {
   1109             done = TRUE;
   1110         } else {
   1111             done = (PICO_OK == picopal_fseek(f->nf, pos, PICOPAL_SEEK_SET));
   1112             if (done) {
   1113                 f->lPos = pos;
   1114             }
   1115         }
   1116     } else {
   1117         done = FALSE;
   1118     }
   1119     return done;
   1120 }
   1121 
   1122 static picoos_bool LGetPos(picoos_File f, picoos_uint32 * pos)
   1123 {
   1124     picoos_bool done = TRUE;
   1125     if ((f != NULL)) {
   1126         (*pos) = f->lPos;
   1127     } else {
   1128         done = FALSE;
   1129         (*pos) = 0;
   1130     }
   1131     return done;
   1132 
   1133 }
   1134 
   1135 static picoos_bool LEof(picoos_File f)
   1136 {
   1137     picoos_bool isEof;
   1138 
   1139     if ((f != NULL)) {
   1140         isEof = picopal_feof(f->nf);
   1141     } else {
   1142         isEof = TRUE;
   1143     }
   1144     return isEof;
   1145 
   1146 }
   1147 
   1148 /* **************************************************************************************/
   1149 
   1150 
   1151 
   1152 /* read a given string 'str' from file. If no match was found, the read position is advanced until and including the first
   1153  * non-matching character */
   1154 static picoos_bool picoos_StrRead (picoos_File f, picoos_char str[])
   1155 {
   1156     picoos_uint32 i = 0;
   1157     picoos_bool done = TRUE;
   1158     picoos_char b;
   1159 
   1160     while (done && (str[i] != NULLC)) {
   1161         done = done && picoos_ReadByte(f,(picoos_char *)&b);
   1162         done = done && (b == str[i]);
   1163         i++;
   1164     }
   1165     return done;
   1166 }
   1167 
   1168 /* write 'str' to file */
   1169 static picoos_bool picoos_WriteStr (picoos_File f, picoos_char str[])
   1170 {
   1171     picoos_uint32 i = 0;
   1172     picoos_bool done = TRUE;
   1173 
   1174     while (done && (str[i] != NULLC)) {
   1175         done = done && picoos_WriteByte(f,str[i]);
   1176         i++;
   1177     }
   1178     return done;
   1179 }
   1180 
   1181 
   1182 
   1183 /* **** Sequential binary file access ******/
   1184 
   1185 /* Remark: 'ReadByte', 'ReadBytes' and 'ReadVar' may be mixed;
   1186  'WriteByte', 'WriteBytes' and 'WriteVar' may be mixed. */
   1187 
   1188 /* Open existing binary file for read access. Reading is buffered
   1189  * with 'nrOfBufs' buffers of size 'bufSize'. If 'nrOfBufs' or
   1190  * 'bufSize' is 0 reading is not buffered.
   1191  * If 'key' is not empty, the file is decrypted with 'key'.
   1192  * If the opened file is in an encrypted archive file, it
   1193  */
   1194 picoos_uint8 picoos_OpenBinary(picoos_Common g, picoos_File * f,
   1195         picoos_char fileName[])
   1196 {
   1197     return LOpen(g, f, fileName, PICOPAL_BINARY_READ);
   1198 }
   1199 
   1200 
   1201 /* Read next byte from file 'f'. */
   1202 picoos_bool picoos_ReadByte(picoos_File f, picoos_uint8 * by)
   1203 {
   1204     picoos_uint32 n = 1;
   1205 
   1206     return picoos_ReadBytes(f, by, &n) && (n == 1);
   1207 
   1208 }
   1209 
   1210 /* Read next 'len' bytes from 'f' into 'bytes'; 'len' returns the
   1211  number of bytes actually read (may be smaller than requested
   1212  length if at end of file). bytes[] must be big enough to hold at least len bytes.
   1213 */
   1214 picoos_bool picoos_ReadBytes(picoos_File f, picoos_uint8 bytes[],
   1215         picoos_uint32 * len)
   1216 {
   1217     picoos_bool done = TRUE;
   1218     /* unsigned int origPos; */
   1219 
   1220     if ((f != NULL)) {
   1221         done = LReadBytes(f, bytes, len);
   1222         /*if ((f->keyLen > 0)) {
   1223          DecryptBytes(f->key,picoos_MaxKeyLen,f->keyLen,origPos,bytes,(*len));
   1224          }*/
   1225     }
   1226 
   1227     return done;
   1228 }
   1229 
   1230 
   1231 /* Create new binary file.
   1232  If 'key' is not empty, the file is encrypted with 'key'. */
   1233 picoos_bool picoos_CreateBinary(picoos_Common g, picoos_File * f,
   1234         picoos_char fileName[])
   1235 {
   1236     return LOpen(g, f, fileName, PICOPAL_BINARY_WRITE);
   1237 
   1238 }
   1239 
   1240 
   1241 picoos_uint8 picoos_WriteByte(picoos_File f, picoos_char by)
   1242 {
   1243     int n = 1;
   1244 
   1245     return picoos_WriteBytes(f, (picoos_char *) &by, &n);
   1246 }
   1247 
   1248 
   1249 /* Writes 'len' bytes from 'bytes' onto file 'f'; 'len' returns
   1250  the number of bytes actually written. */
   1251 picoos_bool picoos_WriteBytes(picoos_File f, const picoos_char bytes[],        picoos_int32 * len) {
   1252     picoos_bool done = FALSE;
   1253 
   1254     if (f != NULL) {
   1255         done = LWriteBytes(f, bytes, len);
   1256     }
   1257 
   1258     return done;
   1259 }
   1260 
   1261 
   1262 
   1263 /* Close previously opened binary file. */
   1264 picoos_uint8 picoos_CloseBinary(picoos_Common g, picoos_File * f)
   1265 {
   1266     return LClose(g, f);
   1267 
   1268 }
   1269 
   1270 /* **************************************************************************************/
   1271 /* *** general routines *****/
   1272 
   1273 
   1274 /* Returns whether end of file was encountered in previous
   1275  read operation. */
   1276 picoos_bool picoos_Eof(picoos_File f)
   1277 {
   1278     if ((NULL != f)) {
   1279         return LEof(f);
   1280     } else {
   1281         return TRUE;
   1282     }
   1283 
   1284 }
   1285 
   1286 /* sets the file pointer to
   1287  'pos' bytes from beginning (first byte = byte 0). This
   1288  routine should only be used for binary files. */
   1289 picoos_bool picoos_SetPos(picoos_File f, picoos_int32 pos)
   1290 {
   1291     picoos_bool done = TRUE;
   1292     if ((NULL != f)) {
   1293         done = LSetPos(f, pos);
   1294     } else {
   1295         done = FALSE;
   1296     }
   1297     return done;
   1298 
   1299 }
   1300 
   1301 /* Get position from file 'f'. */
   1302 picoos_bool picoos_GetPos(picoos_File f, picoos_uint32 * pos)
   1303 {
   1304     if (NULL != f) {
   1305         /* if (f->bFile) {
   1306          (*pos) =  BGetPos(f);
   1307          } else { */
   1308         (*pos) =  LGetPos(f, pos);
   1309         /* } */
   1310         return TRUE;
   1311     } else {
   1312         (*pos) = 0;
   1313         return FALSE;
   1314     }
   1315 }
   1316 
   1317 /* Returns the length of the file in bytes. */
   1318 picoos_bool picoos_FileLength(picoos_File f, picoos_uint32 * len)
   1319 {
   1320 
   1321     if (NULL != f) {
   1322         *len = f->lFileLen;
   1323         return TRUE;
   1324     } else {
   1325         *len = 0;
   1326         return FALSE;
   1327     }
   1328 }
   1329 
   1330 /* Return full name of file 'f'. maxsize is the size of 'name[]' in bytes */
   1331 picoos_bool picoos_Name(picoos_File f, picoos_char name[], picoos_uint32 maxsize)
   1332 {
   1333     picoos_bool done = TRUE;
   1334 
   1335     if (NULL != f) {
   1336         done = (picoos_strlcpy(name, f->name,maxsize) < maxsize);
   1337     } else {
   1338         name[0] = (picoos_char)NULLC;
   1339         done = FALSE;
   1340     }
   1341 
   1342     return done;
   1343 }
   1344 
   1345 /* Returns whether file 'name' exists or not. */
   1346 picoos_bool picoos_FileExists(picoos_Common g, picoos_char name[])
   1347 {
   1348     picoos_File f;
   1349 
   1350     if (picoos_OpenBinary(g, & f,name)) {
   1351         picoos_CloseBinary(g, & f);
   1352         return TRUE;
   1353     } else {
   1354         return FALSE;
   1355     }
   1356 }
   1357 
   1358 
   1359 /* ******************************************************************/
   1360 /* Array conversion operations: all procedures convert 'nrElems' values from
   1361    'src' starting with index 'srcStartInd' into corresponding (possibly
   1362    rounded) values in 'dst' starting at 'dstStartInd'. */
   1363 
   1364 /* taking pi to be le, these are just the array versions of read_mem_pi_*int16 */
   1365 typedef picoos_uint8 two_byte_t[2];
   1366 
   1367 static void arr_conv_le_int16 (picoos_uint8 src[], picoos_uint32 srcShortStartInd, picoos_uint32 nrElems, picoos_int16 dst[], picoos_uint32 dstStartInd)
   1368 {
   1369     two_byte_t * src_p = (two_byte_t *) (src + (srcShortStartInd * 2));
   1370     picoos_int16 * dst_p = dst + dstStartInd;
   1371     picoos_uint32 i;
   1372 
   1373     for (i=0; i<nrElems; i++) {
   1374         *(dst_p++) = (*src_p)[0] + (((*src_p)[1] & 0x7F) << 8) - (((*src_p)[1] & 0x80) ? 0x8000 : 0);
   1375         src_p++;
   1376     }
   1377 }
   1378 
   1379 
   1380 
   1381 /* convert array of int16 into little-endian format */
   1382 static void arr_conv_int16_le (picoos_int16 src[], picoos_uint32 srcStartInd, picoos_uint32 nrElems, picoos_uint8 dst[], picoos_uint32 dstShortStartInd)
   1383 {
   1384     two_byte_t * dst_p = (two_byte_t *) (dst + (dstShortStartInd * 2));
   1385     picoos_int16 * src_p = src + srcStartInd;
   1386     picoos_uint32 i;
   1387     picoos_uint16 val;
   1388 
   1389     for (i=0; i<nrElems; i++) {
   1390         val = (picoos_uint16) *(src_p++);
   1391         (*dst_p)[0] = (picoos_uint8)(val & 0x00FF);
   1392         (*dst_p)[1] = (picoos_uint8)((val & 0xFF00)>>8);
   1393         dst_p++;
   1394     }
   1395 }
   1396 
   1397 /* *****************************************************************/
   1398 /* Sampled Data Files                                                    */
   1399 /* *****************************************************************/
   1400 
   1401 #define PICOOS_SDF_BUF_LEN 1024
   1402 
   1403 #define PICOOS_INT16_MIN   -32768
   1404 #define PICOOS_INT16_MAX   32767
   1405 #define PICOOS_UINT16_MAX  0xffff
   1406 #define PICOOS_INT32_MIN   -2147483648
   1407 #define PICOOS_INT32_MAX   2147483647
   1408 #define PICOOS_UINT32_MAX  0xffffffff
   1409 
   1410 /**  object   : SDFile
   1411  *   shortcut : sdf
   1412  *
   1413  */
   1414 /* typedef struct picoos_sd_file * picoos_SDFile */
   1415 typedef struct picoos_sd_file
   1416 {
   1417     picoos_uint32 sf;
   1418     wave_file_type_t fileType; /* (acoustic) wav, au, raw, other */
   1419     picoos_uint32 hdrSize;
   1420     picoos_encoding_t enc;
   1421     picoos_File file;
   1422     picoos_uint32 nrFileSamples;
   1423     picoos_int16 buf[PICOOS_SDF_BUF_LEN];
   1424     picoos_int32 bufPos;
   1425     picoos_uint8 bBuf[2*PICOOS_SDF_BUF_LEN];
   1426     picoos_bool aborted;
   1427 } picoos_sd_file_t;
   1428 
   1429 
   1430 /* Tries to read wav header at beginning of file 'f';
   1431    returns sampling rate 'sf', encoding type 'enc',
   1432    nr of samples in file 'nrSamples', header size 'hdrSize',
   1433    and byte order 'bOrder'; returns whether a supported
   1434    wav header and format was found. */
   1435 static picoos_bool picoos_readWavHeader(picoos_File f, picoos_uint32 * sf,
   1436         picoos_encoding_t * enc, picoos_uint32 * nrSamples,
   1437         picoos_uint32 * hdrSize) {
   1438     picoos_uint16 n16;
   1439     picoos_uint32 n32;
   1440     picoos_uint16 formatTag;
   1441     picoos_uint32 sampleRate;
   1442     picoos_uint32 bytesPerSec;
   1443     picoos_uint16 blockAlign;
   1444     picoos_uint16 sampleSize;
   1445     picoos_uint32 dataLength;
   1446     picoos_uint32 fileLen;
   1447     picoos_uint32 nrFileSamples;
   1448     picoos_bool done;
   1449 
   1450 
   1451     picoos_SetPos(f, 0);
   1452     picoos_FileLength(f, &fileLen);
   1453     done = picoos_StrRead(f, (picoos_char *) "RIFF");
   1454     done = done && (PICO_OK == picoos_read_le_uint32(f, &n32)); /* length of riff chunk, unused */
   1455     done = done && picoos_StrRead(f, (picoos_char *) "WAVE");
   1456     done = done && picoos_StrRead(f, (picoos_char *) "fmt ");
   1457     done = done && (PICO_OK == picoos_read_le_uint32(f, &n32)); /* length of fmt chunk in bytes; must be 16 */
   1458     done = done && (n32 == 16);
   1459     done = done && (PICO_OK == picoos_read_le_uint16(f, &formatTag));
   1460     done = done && (PICO_OK == picoos_read_le_uint16(f, &n16)); /* number of channels; must be mono */
   1461     done = done && (n16 == 1);
   1462     done = done && (PICO_OK == picoos_read_le_uint32(f, &sampleRate));
   1463     done = done && (PICO_OK == picoos_read_le_uint32(f, &bytesPerSec));
   1464     done = done && (PICO_OK == picoos_read_le_uint16(f, &blockAlign));
   1465     done = done && (PICO_OK == picoos_read_le_uint16(f, &sampleSize));
   1466     done = done && picoos_StrRead(f, (picoos_char *) "data");
   1467     done = done && (PICO_OK == picoos_read_le_uint32(f, &dataLength)); /* length of data chunk in bytes */
   1468     (*hdrSize) = 44;
   1469     if (done) {
   1470         (*sf) = sampleRate;
   1471         (*nrSamples) = 0;
   1472         switch (formatTag) {
   1473         case FORMAT_TAG_LIN:
   1474             (*enc) = PICOOS_ENC_LIN;
   1475             done = ((blockAlign == 2) && (sampleSize == 16));
   1476             (*nrSamples) = (dataLength / 2);
   1477             nrFileSamples = ((fileLen - (*hdrSize)) / 2);
   1478             break;
   1479         case FORMAT_TAG_ULAW:
   1480             (*enc) = PICOOS_ENC_ULAW;
   1481             done = ((blockAlign == 1) && (sampleSize == 8));
   1482             (*nrSamples) = dataLength;
   1483             nrFileSamples = (fileLen - (*hdrSize));
   1484             break;
   1485         case FORMAT_TAG_ALAW:
   1486             (*enc) = PICOOS_ENC_ALAW;
   1487             done = ((blockAlign == 1) && (sampleSize == 8));
   1488             (*nrSamples) = dataLength;
   1489             nrFileSamples = (fileLen - (*hdrSize));
   1490             break;
   1491         default:
   1492             done = FALSE;
   1493             break;
   1494         }
   1495         if (!done) {
   1496             /* communicate "unsupported format" */
   1497             PICODBG_WARN(("unsupported wav format"));
   1498         } else {
   1499             if (nrFileSamples != (*nrSamples)) {
   1500                 /* warn "inconsistent number of samples" */
   1501                 PICODBG_WARN(("inconsistent number of samples in wav file: %d vs. %d",nrFileSamples,(*nrSamples)));
   1502                 (*nrSamples) = nrFileSamples;
   1503             }
   1504         }
   1505     }
   1506     return done;
   1507 }
   1508 
   1509 
   1510 
   1511 extern picoos_bool picoos_sdfOpenIn(picoos_Common g, picoos_SDFile * sdFile,
   1512         picoos_char fileName[], picoos_uint32 * sf, picoos_encoding_t * enc,
   1513         picoos_uint32 * numSamples)
   1514 {
   1515     picoos_bool done = FALSE;
   1516     picoos_sd_file_t * sdf = NULL;
   1517     wave_file_type_t fileType = FILE_TYPE_OTHER;
   1518 
   1519     (*sf) = 0;
   1520     (*numSamples) = 0;
   1521     (*enc) = PICOOS_ENC_LIN;
   1522     (*sdFile) = NULL;
   1523 
   1524     sdf = picoos_allocate(g->mm,sizeof(picoos_sd_file_t));
   1525     if (NULL == sdf) {
   1526         picoos_emRaiseWarning(g->em,PICO_EXC_OUT_OF_MEM,NULL,NULL);
   1527         return FALSE;
   1528     }
   1529 
   1530     /* buffered access not supported, yet */
   1531     if (picoos_OpenBinary(g,&(sdf->file),fileName)) {
   1532         if (picoos_has_extension(fileName,(picoos_char *) ".wav")) {
   1533             fileType = FILE_TYPE_WAV;
   1534             done = picoos_readWavHeader(sdf->file,&(sdf->sf),&(sdf->enc),&(sdf->nrFileSamples),&(sdf->hdrSize));
   1535         } else {
   1536             /* we prefer not to treat other formats, rather than treat it as raw */
   1537             /* fileType = FILE_TYPE_RAW; */
   1538             fileType = FILE_TYPE_OTHER;
   1539             done = FALSE;
   1540         }
   1541 
   1542         if (FILE_TYPE_OTHER == fileType) {
   1543             picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,(picoos_char *)"unsupported filename suffix",NULL);
   1544         } else if (!done) {
   1545             picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,(picoos_char *)"non-conforming header",NULL);
   1546         } else {
   1547             (*numSamples) = sdf->nrFileSamples;
   1548             (*sf) = sdf->sf;
   1549             (*enc) = sdf->enc;
   1550             /* check whether sd file properties are supported */
   1551             if (PICOOS_ENC_LIN != sdf->enc) {
   1552                 done = FALSE;
   1553                 picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,NULL,(picoos_char *)"encoding not supported");
   1554             }
   1555             if (SAMPLE_FREQ_16KHZ != sdf->sf) {
   1556                 done = FALSE;
   1557                 picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,NULL,(picoos_char *)"sample frequency not supported");
   1558             }
   1559             (*sdFile) = sdf;
   1560         }
   1561         if (!done){
   1562             picoos_CloseBinary(g,&(sdf->file));
   1563         }
   1564     } else {
   1565         picoos_emRaiseException(g->em,PICO_EXC_CANT_OPEN_FILE,NULL,NULL);
   1566     }
   1567     if (!done) {
   1568         picoos_deallocate(g->mm,(void *)&sdf);
   1569         (*sdFile) = NULL;
   1570     }
   1571     return done;
   1572 }
   1573 
   1574 
   1575 static void picoos_sdfLoadSamples(picoos_SDFile sdFile,
   1576         picoos_uint32 * nrSamples) {
   1577     picoos_uint32 len;
   1578     picoos_sd_file_t * sdf = sdFile;
   1579 
   1580     switch (sdFile->enc) {
   1581     case PICOOS_ENC_LIN:
   1582         if ((*nrSamples) > PICOOS_SDF_BUF_LEN) {
   1583             (*nrSamples) = PICOOS_SDF_BUF_LEN;
   1584         }
   1585         len = 2 * (*nrSamples);
   1586         picoos_ReadBytes(sdf->file, sdf->bBuf, &len);
   1587         (*nrSamples) = len / 2;
   1588         arr_conv_le_int16(sdf->bBuf, 0, (*nrSamples), sdf->buf, 0);
   1589         break;
   1590         /* @todo : may be useful */
   1591     case PICOOS_ENC_ULAW:
   1592     case PICOOS_ENC_ALAW:
   1593     default:
   1594         (*nrSamples) = 0;
   1595     }
   1596 
   1597 }
   1598 
   1599 extern picoos_bool picoos_sdfGetSamples (
   1600         picoos_SDFile sdFile,
   1601         picoos_uint32 start,
   1602         picoos_uint32 * nrSamples,
   1603         picoos_int16 samples[])
   1604 {
   1605     picoos_uint32 b;
   1606     picoos_uint32 rem;
   1607     picoos_uint32 n;
   1608     picoos_uint32 i;
   1609     picoos_uint32 j;
   1610     picoos_bool done = FALSE;
   1611 
   1612     if (NULL == sdFile) {
   1613         (*nrSamples) = 0;
   1614     } else {
   1615             if (start >= sdFile->nrFileSamples) {
   1616                 if (start > sdFile->nrFileSamples) {
   1617                     PICODBG_WARN(("start has to be <= sdFile->nrFileSamples"));
   1618                 }
   1619                 (*nrSamples) = 0;
   1620             } else {
   1621                 if (((start + (*nrSamples)) > sdFile->nrFileSamples)) {
   1622                     (*nrSamples) = (sdFile->nrFileSamples - start);
   1623                 }
   1624                 if ((sdFile->enc == PICOOS_ENC_LIN)) {
   1625                     b = 2;
   1626                 } else {
   1627                     b = 1;
   1628                 }
   1629                 picoos_SetPos(sdFile->file,(sdFile->hdrSize + (b * start)));
   1630                 j = 0;
   1631                 rem = (*nrSamples);
   1632                 n = rem;
   1633                 while ((rem > 0) && (n > 0)) {
   1634                     /* set n=min(rem,buffer_length) and try loading next n samples */
   1635                     n = (rem < PICOOS_SDF_BUF_LEN) ? rem : PICOOS_SDF_BUF_LEN;
   1636                     picoos_sdfLoadSamples(sdFile, &n);
   1637                     /* n may be smaller now */
   1638                     for (i = 0; i < n; i++) {
   1639                         samples[j] = sdFile->buf[i];
   1640                         j++;
   1641                     }
   1642                     rem -= n;
   1643                     start += n;
   1644                 }
   1645                 (*nrSamples) = j;
   1646                 done = ((*nrSamples) > 0);
   1647             }
   1648     }
   1649     return done;
   1650 }
   1651 
   1652 
   1653 extern picoos_bool picoos_sdfCloseIn (picoos_Common g, picoos_SDFile * sdFile)
   1654 {
   1655     if (NULL != (*sdFile)) {
   1656         picoos_CloseBinary(g,&((*sdFile)->file));
   1657         picoos_deallocate(g->mm,(void *)sdFile);
   1658     }
   1659     return TRUE;
   1660 }
   1661 
   1662 
   1663 static picoos_bool picoos_writeWavHeader(picoos_File f, picoos_uint32 sf,
   1664         picoos_encoding_t enc, picoos_uint32 nrSamples,
   1665         picoos_uint32 * hdrSize) {
   1666     picoos_uint16 formatTag = FORMAT_TAG_LIN;
   1667     picoos_uint32 sampleRate;
   1668     picoos_uint32 bytesPerSec;
   1669     picoos_uint32 bytesPerSample = 2;
   1670     picoos_uint16 blockAlign;
   1671     picoos_uint16 sampleSize = 16;
   1672     picoos_uint32 dataLength;
   1673     picoos_bool done = TRUE;
   1674 
   1675     picoos_SetPos(f, 0);
   1676 
   1677     switch (enc) {
   1678         case PICOOS_ENC_LIN:
   1679             formatTag = FORMAT_TAG_LIN;
   1680             bytesPerSample = 2;
   1681             sampleSize = 16;
   1682             break;
   1683         case PICOOS_ENC_ULAW:
   1684             formatTag = FORMAT_TAG_ULAW;
   1685             bytesPerSample = 1;
   1686             sampleSize = 8;
   1687             break;
   1688         case PICOOS_ENC_ALAW:
   1689             formatTag = FORMAT_TAG_ALAW;
   1690             bytesPerSample = 1;
   1691             sampleSize = 8;
   1692             break;
   1693         default:
   1694             done = FALSE;
   1695             break;
   1696     }
   1697 
   1698     bytesPerSec = (sf * bytesPerSample);
   1699     blockAlign = bytesPerSample;
   1700     sampleRate = sf;
   1701     dataLength = (bytesPerSample * nrSamples);
   1702     done = done && picoos_WriteStr(f,(picoos_char *)"RIFF");
   1703     done = done && picoos_write_le_uint32(f,dataLength + 36);
   1704     done = done && picoos_WriteStr(f,(picoos_char *)"WAVE");
   1705     done = done && picoos_WriteStr(f,(picoos_char *)"fmt ");
   1706     done = done && picoos_write_le_uint32(f,16);
   1707     done = done && picoos_write_le_uint16(f,formatTag);
   1708     done = done && picoos_write_le_uint16(f,1);
   1709     done = done && picoos_write_le_uint32(f,sampleRate);
   1710     done = done && picoos_write_le_uint32(f,bytesPerSec);
   1711     done = done && picoos_write_le_uint16(f,blockAlign);
   1712     done = done && picoos_write_le_uint16(f,sampleSize);
   1713     done = done && picoos_WriteStr(f,(picoos_char *)"data");
   1714     done = done && picoos_write_le_uint32(f,dataLength);
   1715     (*hdrSize) = 44;
   1716     return done;
   1717 }
   1718 
   1719 
   1720 #define DummyLen 100000000
   1721 
   1722 extern picoos_bool picoos_sdfOpenOut(picoos_Common g, picoos_SDFile * sdFile,
   1723         picoos_char fileName[], int sf, picoos_encoding_t enc)
   1724 {
   1725     picoos_bool done = TRUE;
   1726     picoos_sd_file_t * sdf = NULL;
   1727 
   1728     (*sdFile) = NULL;
   1729     sdf = picoos_allocate(g->mm, sizeof(picoos_sd_file_t));
   1730     if (NULL == sdf) {
   1731         picoos_emRaiseWarning(g->em, PICO_EXC_OUT_OF_MEM, NULL, NULL);
   1732         return FALSE;
   1733     }
   1734     sdf->sf = sf;
   1735     sdf->enc = enc;
   1736     /* check whether sd file properties are supported */
   1737     if (PICOOS_ENC_LIN != sdf->enc) {
   1738         done = FALSE;
   1739         picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, NULL,
   1740                 (picoos_char *) "encoding not supported");
   1741     }
   1742     if (SAMPLE_FREQ_16KHZ != sdf->sf) {
   1743         done = FALSE;
   1744         picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, NULL,
   1745                 (picoos_char *) "sample frequency not supported");
   1746     }
   1747     if (done) {
   1748         sdf->nrFileSamples = 0;
   1749         sdf->bufPos = 0;
   1750         sdf->aborted = FALSE;
   1751         if (picoos_CreateBinary(g, &(sdf->file), fileName)) {
   1752             if (picoos_has_extension(fileName, (picoos_char *) ".wav")) {
   1753                 sdf->fileType = FILE_TYPE_WAV;
   1754                 done = picoos_writeWavHeader(sdf->file, sdf->sf, sdf->enc,
   1755                         DummyLen, &(sdf->hdrSize));
   1756             } else {
   1757                 /* we prefer not to treat other formats, rather than treat it as raw */
   1758                 /* fileType = FILE_TYPE_RAW; */
   1759                 sdf->fileType = FILE_TYPE_OTHER;
   1760                 done = FALSE;
   1761             }
   1762 
   1763             if (FILE_TYPE_OTHER == sdf->fileType) {
   1764                 picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE,
   1765                         (picoos_char *) "unsupported filename suffix", NULL);
   1766             } else if (!done) {
   1767                 picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE,
   1768                         (picoos_char *) "non-conforming header", NULL);
   1769             } else {
   1770                 (*sdFile) = sdf;
   1771             }
   1772             if (!done) {
   1773                 picoos_CloseBinary(g, &(sdf->file));
   1774             }
   1775         } else {
   1776             picoos_emRaiseException(g->em, PICO_EXC_CANT_OPEN_FILE, NULL, NULL);
   1777         }
   1778     }
   1779     if (!done) {
   1780         picoos_deallocate(g->mm, (void *) &sdf);
   1781         (*sdFile) = NULL;
   1782     }
   1783     return done;
   1784 }
   1785 
   1786 static picoos_bool picoos_sdfFlushOutBuf(picoos_SDFile sdFile)
   1787 {
   1788     picoos_bool done = FALSE;
   1789     picoos_int32 len;
   1790     picoos_int32 nrSamples;
   1791 
   1792     if (!(sdFile->aborted)) {
   1793         nrSamples = sdFile->bufPos;
   1794         switch (sdFile->enc) {
   1795             case PICOOS_ENC_LIN:
   1796                 arr_conv_int16_le(sdFile->buf, 0, nrSamples, sdFile->bBuf, 0);
   1797                 len = (nrSamples * 2);
   1798                 done = picoos_WriteBytes(sdFile->file, sdFile->bBuf, &len)
   1799                         && ((nrSamples * 2) == len);
   1800                 break;
   1801             case PICOOS_ENC_ULAW:
   1802             case PICOOS_ENC_ALAW:
   1803             default:
   1804                 nrSamples = 0;
   1805                 break;
   1806         }
   1807         sdFile->nrFileSamples = (sdFile->nrFileSamples + nrSamples);
   1808     }
   1809 
   1810     sdFile->bufPos = 0;
   1811     return done;
   1812 }
   1813 
   1814 extern picoos_bool picoos_sdfFlushOutput(picoos_SDFile sdFile)
   1815 {
   1816     if ((sdFile != NULL) &&  !(sdFile->aborted) && (sdFile->bufPos > 0)) {
   1817         return picoos_sdfFlushOutBuf(sdFile);
   1818     }
   1819     return TRUE;
   1820 }
   1821 
   1822 
   1823 
   1824 extern picoos_bool picoos_sdfPutSamples (picoos_SDFile sdFile, picoos_uint32 nrSamples, picoos_int16 samples[])
   1825 {
   1826     picoos_uint32 i;
   1827     picoos_int32 s;
   1828     picoos_bool done = FALSE;
   1829 
   1830     if ((sdFile != NULL) &&  !(sdFile->aborted)) {
   1831         done = TRUE;
   1832         for (i = 0; i < nrSamples; i++) {
   1833             s = samples[i];
   1834             if ((s > PICOOS_INT16_MAX)) {
   1835                 s = PICOOS_INT16_MAX;
   1836             } else if (s < PICOOS_INT16_MIN) {
   1837                 s = PICOOS_INT16_MIN;
   1838             }
   1839             sdFile->buf[sdFile->bufPos++] = s;
   1840             if (sdFile->bufPos >= PICOOS_SDF_BUF_LEN) {
   1841                 done = picoos_sdfFlushOutBuf(sdFile);
   1842             }
   1843         }
   1844     } else {
   1845         done = FALSE;
   1846     }
   1847     return done;
   1848 }
   1849 
   1850 
   1851 extern picoos_bool picoos_sdfCloseOut (picoos_Common g, picoos_SDFile * sdFile)
   1852 {
   1853 
   1854     picoos_bool done = TRUE;
   1855     picoos_uint32 hdrSize;
   1856 
   1857     if (NULL != (*sdFile)) {
   1858         if (!((*sdFile)->aborted) && ((*sdFile)->bufPos > 0)) {
   1859             done = picoos_sdfFlushOutBuf(*sdFile);
   1860         }
   1861         if (FILE_TYPE_WAV == (*sdFile)->fileType) {
   1862             done = picoos_writeWavHeader((*sdFile)->file, (*sdFile)->sf,
   1863                     (*sdFile)->enc, (*sdFile)->nrFileSamples, &hdrSize);
   1864         }
   1865         done = picoos_CloseBinary(g, &((*sdFile)->file));
   1866         picoos_deallocate(g->mm, (void *) sdFile);
   1867     }
   1868     return done;
   1869 }
   1870 
   1871 
   1872 /* *****************************************************************/
   1873 /* FileHeader                                                      */
   1874 /* *****************************************************************/
   1875 
   1876 
   1877 
   1878 pico_status_t picoos_clearHeader(picoos_FileHeader header)
   1879 {
   1880     picoos_uint8 i;
   1881     for (i=0; i < PICOOS_MAX_NUM_HEADER_FIELDS; i++) {
   1882         header->field[i].key[0] = NULLC;
   1883         header->field[i].value[0] = NULLC;
   1884         header->field[i].op = PICOOS_FIELD_IGNORE;
   1885     }
   1886     header->numFields = 0;
   1887     return PICO_OK;
   1888 }
   1889 
   1890 pico_status_t picoos_setHeaderField(picoos_FileHeader header,
   1891         picoos_uint8 index, picoos_char * key, picoos_char * value,
   1892         picoos_compare_op_t op)
   1893 {
   1894     if (index >= header->numFields) {
   1895         return PICO_ERR_INDEX_OUT_OF_RANGE;
   1896     }
   1897     header->field[index].op = op;
   1898     if ((picoos_strlcpy(header->field[index].key, key,
   1899             PICOOS_MAX_FIELD_STRING_LEN) < PICOOS_MAX_FIELD_STRING_LEN)
   1900             && (picoos_strlcpy(header->field[index].value, value,
   1901                     PICOOS_MAX_FIELD_STRING_LEN)) < PICOOS_MAX_FIELD_STRING_LEN) {
   1902         return PICO_OK;
   1903     } else {
   1904         return PICO_ERR_INDEX_OUT_OF_RANGE;
   1905     }
   1906 }
   1907 
   1908 
   1909 /* caller has to make sure allocated space at key and value are large enough to hold a picoos_field_string */
   1910 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)
   1911 {
   1912     if (index >= header->numFields) {
   1913         return PICO_ERR_INDEX_OUT_OF_RANGE;
   1914     }
   1915     *op = header->field[index].op;
   1916     if ((picoos_strlcpy(key,header->field[index].key,
   1917             PICOOS_MAX_FIELD_STRING_LEN) < PICOOS_MAX_FIELD_STRING_LEN)
   1918             && (picoos_strlcpy(value,header->field[index].value,
   1919                     PICOOS_MAX_FIELD_STRING_LEN)) < PICOOS_MAX_FIELD_STRING_LEN) {
   1920         return PICO_OK;
   1921     } else {
   1922         return PICO_ERR_INDEX_OUT_OF_RANGE;
   1923     }
   1924     return PICO_OK;
   1925 }
   1926 
   1927 
   1928 /* check whether 'str' of length strlen matches contents in circular buffer buf, located in the first strlen bytes and ending
   1929  * position bufpos. */
   1930 static picoos_uint8 os_matched( picoos_char * str,  picoos_uint32 strlen, picoos_char * buf,  picoos_int32 bufpos) {
   1931     picoos_int32 i = strlen-1;
   1932     while (i >= 0 && buf[bufpos] == str[i]) {
   1933         i--;
   1934         bufpos--;
   1935         if (bufpos < 0) {
   1936             bufpos = strlen-1;
   1937         }
   1938     }
   1939     return (i<0);
   1940 }
   1941 
   1942 pico_status_t picoos_getSVOXHeaderString(picoos_char * str, picoos_uint8 * len, picoos_uint32 maxlen)
   1943 {
   1944     picoos_char * ch;
   1945     *len = picoos_strlcpy(str,picoos_SVOXFileHeader,maxlen);
   1946     if (*len < maxlen) {
   1947         ch = str;
   1948         /* SVOX header is made less readable */
   1949         while (*ch) {
   1950             *ch -= ' ';
   1951             ch++;
   1952         }
   1953         return PICO_OK;
   1954     } else {
   1955         return PICO_ERR_OTHER;
   1956     }
   1957 }
   1958 
   1959 pico_status_t picoos_readPicoHeader(picoos_File f, picoos_uint32 * headerlen)
   1960 {
   1961     picoos_char str[32];
   1962     picoos_char buf[32];
   1963     picoos_uint8 strlen, bufpos;
   1964     picoos_uint32 n;
   1965     picoos_uint8 done;
   1966 
   1967     picoos_getSVOXHeaderString(str,&strlen,32);
   1968     /* search for svox header somewhere near the file start. This allows for initial
   1969      * non-svox-header bytes for a customer-specific header and/or filling bytes for alignment */
   1970     *headerlen = 0;
   1971     /* read in initial chunk of length strlen */
   1972     n = strlen;
   1973     done = picoos_ReadBytes(f,(picoos_uint8 *)buf,&n) && (n == strlen);
   1974     if (done) {
   1975         *headerlen = n;
   1976         bufpos = strlen-1; /* last legal buf position */
   1977         done = os_matched(str,strlen,buf,bufpos);
   1978         while (!done && *headerlen < PICO_MAX_FOREIGN_HEADER_LEN) {
   1979             n = 1;
   1980             bufpos = (bufpos + 1) % strlen;
   1981             done = picoos_ReadBytes(f,(picoos_uint8 *)buf+bufpos,&n) && 1 == n;
   1982             done = done && os_matched(str,strlen,buf,bufpos);
   1983             headerlen++;
   1984         }
   1985     }
   1986     if (done) {
   1987         return PICO_OK;
   1988     } else {
   1989         return PICO_EXC_UNEXPECTED_FILE_TYPE;
   1990     }
   1991 }
   1992 
   1993 picoos_uint8 picoos_get_str (picoos_char * fromStr, picoos_uint32 * pos, picoos_char * toStr, picoos_objsize_t maxsize)
   1994 {
   1995     picoos_uint8 i = 0;
   1996     /* skip non-printables */
   1997 
   1998     while ((fromStr[*pos] != NULLC) && (fromStr[*pos] <= ' ')) {
   1999         (*pos)++;
   2000     }
   2001     /* copy printable portion */
   2002     while ((fromStr[*pos] != NULLC) && (fromStr[*pos] > ' ') && (i < maxsize-1)) {
   2003         toStr[i++] = fromStr[(*pos)++];
   2004     }
   2005     toStr[i] = NULLC;
   2006     return (i > 0) && (fromStr[*pos] <= ' ');
   2007 }
   2008 
   2009 pico_status_t picoos_hdrParseHeader(picoos_FileHeader header, picoos_header_string_t str)
   2010 {
   2011     picoos_uint32 curpos = 0;
   2012     picoos_uint8 i, numFields;
   2013 
   2014 
   2015     /* read number of fields */
   2016     numFields = str[curpos++];
   2017     numFields = os_min(numFields,PICOOS_MAX_NUM_HEADER_FIELDS);
   2018     /* read in all field pairs */
   2019     PICODBG_DEBUG(("number of fields = %i", numFields));
   2020     for (i = 0; i < numFields; i++) {
   2021         picoos_get_str(str,&curpos,header->field[i].key,PICOOS_MAX_FIELD_STRING_LEN);
   2022         picoos_get_str(str,&curpos,header->field[i].value,PICOOS_MAX_FIELD_STRING_LEN);
   2023     }
   2024     return PICO_OK;
   2025 }
   2026 
   2027 
   2028 
   2029 
   2030 
   2031 /* **************************************************************************/
   2032 /* Read  little-endian / platform-independent integers from file or memory  */
   2033 /* **************************************************************************/
   2034 
   2035 /* read little-endian */
   2036 pico_status_t picoos_read_le_uint16 (picoos_File file, picoos_uint16 * val)
   2037 {
   2038     picoos_uint8 by[2];
   2039     picoos_uint32 n = 2;
   2040     if (picoos_ReadBytes(file, by, &n) && 2 == n) {
   2041         /* little-endian */
   2042         *val = (picoos_uint16) by[1] << 8 | (picoos_uint16) by[0];
   2043         return PICO_OK;
   2044     } else {
   2045         *val = 0;
   2046         return PICO_ERR_OTHER;
   2047     }
   2048 }
   2049 
   2050 pico_status_t picoos_read_le_int16 (picoos_File file, picoos_int16 * val)
   2051 {
   2052     return picoos_read_le_uint16(file, (picoos_uint16 *)val);
   2053 }
   2054 
   2055 pico_status_t picoos_read_le_uint32 (picoos_File file, picoos_uint32 * val)
   2056 {
   2057     picoos_uint8 by[4];
   2058     picoos_uint32 n = 4;
   2059     if (picoos_ReadBytes(file, by, &n) && (4 == n)) {
   2060         /* little-endian */
   2061         PICODBG_TRACE(("reading uint 32:  %i %i %i %i",
   2062                        by[0], by[1], by[2], by[3]));
   2063         *val = (((picoos_uint32) by[3] << 8 | (picoos_uint32) by[2]) << 8 | (picoos_uint32) by[1]) << 8 | (picoos_uint32) by[0];
   2064         PICODBG_TRACE(("uint 32:  %i %i %i %i corresponds %i",
   2065                        by[0], by[1], by[2], by[3], *val));
   2066         return PICO_OK;
   2067     } else {
   2068         *val = 0;
   2069         return PICO_ERR_OTHER;
   2070     }
   2071 }
   2072 
   2073 /* platform-independent */
   2074 /* our convention is that pi is little-endian. */
   2075 
   2076 /** @todo : direct implementation if too slow */
   2077 
   2078 pico_status_t picoos_read_pi_uint16 (picoos_File file, picoos_uint16 * val)
   2079 {
   2080     return picoos_read_le_uint16(file,val);
   2081 }
   2082 
   2083 pico_status_t picoos_read_pi_uint32 (picoos_File file, picoos_uint32 * val)
   2084 {
   2085     return picoos_read_le_uint32(file, val);
   2086 }
   2087 
   2088 pico_status_t picoos_read_pi_int32 (picoos_File file, picoos_int32 * val)
   2089 {
   2090     return picoos_read_le_uint32(file, (picoos_uint32 *)val);
   2091 }
   2092 
   2093 /* read pi from memory */
   2094 
   2095 pico_status_t picoos_read_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 * val)
   2096 {
   2097     picoos_uint8 * by = data + *pos;
   2098 
   2099     /* little-endian */
   2100     *val = (picoos_uint16) by[1] << 8 | (picoos_uint16) by[0];
   2101     (*pos) += 2;
   2102     return PICO_OK;
   2103 }
   2104 
   2105 pico_status_t picoos_read_mem_pi_uint32 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint32 * val)
   2106 {
   2107         picoos_uint8 * by = data + *pos;
   2108 
   2109         /* little-endian */
   2110         *val = (((picoos_uint32) by[3] << 8 | (picoos_uint32) by[2]) << 8 | (picoos_uint32) by[1]) << 8 | (picoos_uint32) by[0];
   2111         (*pos) += 4;
   2112         return PICO_OK;
   2113 }
   2114 
   2115 /* **************************************************************************/
   2116 /* Write little-endian / platform-independent integers into file or memory  */
   2117 /* **************************************************************************/
   2118 /* write little-endian */
   2119 pico_status_t picoos_write_le_uint16 (picoos_File file, picoos_uint16 val)
   2120 {
   2121     picoos_int32 len = 2;
   2122     picoos_uint8 by[2];
   2123 
   2124     by[0]  = (picoos_uint8)((val) & 0x00FF);
   2125     by[1]  = (picoos_uint8)(((val) & 0xFF00)>>8);
   2126     return (picoos_WriteBytes(file,by,&len) && (2 == len));
   2127 }
   2128 pico_status_t picoos_write_le_uint32 (picoos_File file, picoos_uint32 val)
   2129 {
   2130     picoos_int32 len = 4;
   2131     picoos_uint8 by[4];
   2132 
   2133     by[0]  = (picoos_uint8)(val & 0x000000FF);
   2134     by[1]  = (picoos_uint8)((val & 0x0000FF00)>>8);
   2135     by[2]  = (picoos_uint8)((val & 0x00FF0000)>>16);
   2136     by[3]  = (picoos_uint8)((val & 0xFF000000)>>24);
   2137     return (picoos_WriteBytes(file,by,&len) && (4 == len));
   2138 }
   2139 
   2140 /* write pi to mem */
   2141 pico_status_t picoos_write_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 val)
   2142 {
   2143     picoos_uint8 * by = data + *pos;
   2144     /* little-endian */
   2145     by[0]  = (picoos_uint8)((val) & 0x00FF);
   2146     by[1]  = (picoos_uint8)(((val) & 0xFF00)>>8);
   2147     (*pos) += 2;
   2148     return PICO_OK;
   2149 }
   2150 
   2151 /* *****************************************************************/
   2152 /* String search and compare operations                            */
   2153 /* *****************************************************************/
   2154 
   2155 /* this function is case-sensitive */
   2156 picoos_uint8 picoos_has_extension(const picoos_char *str, const picoos_char *suf)
   2157 {
   2158     picoos_int32 istr = picoos_strlen(str)-1;
   2159     picoos_int32 isuf = picoos_strlen(suf)-1;
   2160     while ((istr >= 0) && (isuf >=0) && (str[istr] == suf[isuf])) {
   2161         istr--;
   2162         isuf--;
   2163     }
   2164     return (isuf < 0);
   2165 }
   2166 
   2167 
   2168 /* *****************************************************************/
   2169 /* String/Number Conversions  (may be moved to picopal)            */
   2170 /* *****************************************************************/
   2171 
   2172 pico_status_t picoos_string_to_int32(picoos_char str[],
   2173         picoos_int32 * res)
   2174 {
   2175     /* syntax: [+|-] dig {dig} */
   2176 
   2177     int i;
   2178     int neg;
   2179     int val;
   2180     int err;
   2181 
   2182     err = 0;
   2183     i = 0;
   2184     while ((str[i] <= ' ') && (str[i] != '\0')) {
   2185         i++;
   2186     }
   2187     neg = 0;
   2188     if (str[i] == '-') {
   2189         neg = 1;
   2190         i++;
   2191     } else if (str[i] == '+') {
   2192         i++;
   2193     }
   2194     val = 0;
   2195     if ((str[i] < '0') || (str[i]> '9')) {
   2196         err = 1;
   2197     }
   2198     while ((str[i] >= '0') && (str[i] <= '9')) {
   2199         val = val * 10 + (str[i] - '0');
   2200         i++;
   2201     }
   2202     while ((str[i] <= ' ') && (str[i] != '\0')) {
   2203         i++;
   2204     }
   2205     if (neg == 1) {
   2206         val = -val;
   2207     }
   2208     if ((err == 0) && (str[i] == '\0')) {
   2209         (*res) = val;
   2210         return PICO_OK;
   2211     } else {
   2212         (*res) = 0;
   2213         return PICO_EXC_NUMBER_FORMAT;
   2214     }
   2215 }
   2216 
   2217 pico_status_t picoos_string_to_uint32(picoos_char str[],
   2218         picoos_uint32 * res)
   2219 {
   2220     /* syntax: [+] dig {dig} */
   2221 
   2222     int i;
   2223     int val;
   2224     int err;
   2225 
   2226     err = 0;
   2227     i = 0;
   2228     while ((str[i] <= ' ') && (str[i] != '\0')) {
   2229         i++;
   2230     }
   2231     if (str[i] == '+') {
   2232         i++;
   2233     }
   2234     val = 0;
   2235     if ((str[i] < '0') || (str[i]> '9')) {
   2236         err = 1;
   2237     }
   2238     while ((str[i] >= '0') && (str[i] <= '9')) {
   2239         val = val * 10 + (str[i] - '0');
   2240         i++;
   2241     }
   2242     while ((str[i] <= ' ') && (str[i] != '\0')) {
   2243         i++;
   2244     }
   2245     if ((err == 0) && (str[i] == '\0')) {
   2246         (*res) = val;
   2247         return PICO_OK;
   2248     } else {
   2249         (*res) = 0;
   2250         return PICO_EXC_NUMBER_FORMAT;
   2251     }
   2252 }
   2253 
   2254 /* 'stringlen' is the part of input string to be considered,
   2255  * possibly not containing NULLC (e.g. result of strlen).
   2256  * 'maxsize' is the maximal size of 'part' including a byte
   2257  * for the terminating NULLC! */
   2258 void picoos_get_sep_part_str(picoos_char string[],
   2259         picoos_int32 stringlen, picoos_int32 * ind, picoos_char sepCh,
   2260         picoos_char part[], picoos_int32 maxsize, picoos_uint8 * done)
   2261 {
   2262 
   2263     picoos_int32 j;
   2264     picoos_uint8 done1;
   2265 
   2266     if (((*ind) >= stringlen)) {
   2267         (*done) = 0;
   2268         part[0] = (picoos_char) NULLC;
   2269     } else {
   2270         done1 = 1;
   2271         j = 0;
   2272         while ((((*ind) < stringlen) && (string[(*ind)] != sepCh)) && (string[((*ind))] != (picoos_char)NULLC)) {
   2273             if ((j < maxsize-1)) {
   2274                 part[(j)] = string[(*ind)];
   2275                 j++;
   2276             } else {
   2277                 done1 = 0;
   2278             }
   2279             (*ind)++;
   2280         }
   2281         part[j] = (picoos_char)NULLC;
   2282         if ((*ind) < stringlen) {
   2283             if ((string[(*ind)] == sepCh)) {
   2284                 (*ind)++; /* skip separator character */
   2285             } else if (string[(*ind)] == (picoos_char)NULLC) {
   2286                 /* reached end of input; set ind to stringlen so that no
   2287                  more (empty) partial strings will be found */
   2288                 (*ind) = stringlen;
   2289             }
   2290         }
   2291         (*done) = done1;
   2292     }
   2293 }
   2294 
   2295 /* *****************************************************************/
   2296 /* timer function                                                  */
   2297 /* *****************************************************************/
   2298 
   2299 extern void picoos_get_timer(picopal_uint32 * sec, picopal_uint32 * usec)
   2300 {
   2301     picopal_get_timer(sec, usec);
   2302 }
   2303 
   2304 #ifdef __cplusplus
   2305 }
   2306 #endif
   2307 
   2308 
   2309 /* end */
   2310