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
34extern "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
112picoos_int32 picoos_atoi(const picoos_char *s)
113{
114    return (picoos_int32)picopal_atoi((const picoos_char *)s);
115}
116
117
118picoos_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}
124picoos_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
131picoos_uint32 picoos_strlen(const picoos_char *s)
132{
133    return (picoos_uint32)picopal_strlen((const picopal_char *)s);
134}
135
136picoos_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
142picoos_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
148picoos_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
159picoos_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
165picoos_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
171picoos_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! */
177void * 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' */
183void * 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
188picoos_double picoos_cos (const picoos_double cos_arg)
189{
190    return (picoos_double) picopal_cos ((picopal_double) cos_arg);
191}
192
193
194picoos_double picoos_sin (const picoos_double sin_arg)
195{
196    return (picoos_double) picopal_sin((picopal_double) sin_arg);
197}
198picoos_double picoos_fabs (const picoos_double fabs_arg)
199{
200    return (picoos_double) picopal_fabs((picopal_double) fabs_arg);
201}
202
203picoos_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
215picoos_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
227void 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
240typedef struct mem_block_hdr * MemBlockHdr;
241typedef struct mem_block_hdr
242{
243    MemBlockHdr next;
244    byte_ptr_t data;
245    picoos_objsize_t size;
246} mem_block_hdr_t;
247
248typedef struct mem_cell_hdr * MemCellHdr;
249typedef 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
257typedef 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 */
279void * 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 */
305static 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
350picoos_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
425void 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
435void *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
445void 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
455void 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
476void 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
492void 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
507void * 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
560void 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
617typedef picoos_char picoos_exc_msg[PICOOS_MAX_EXC_MSG_LEN];
618typedef picoos_char picoos_warn_msg[PICOOS_MAX_WARN_MSG_LEN];
619
620typedef 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
631void picoos_emReset(picoos_ExceptionManager this)
632{
633    this->curExceptionCode = PICO_OK;
634    this->curExceptionMessage[0] = '\0';
635    this->curNumWarnings = 0;
636}
637
638picoos_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
649void 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
658static 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
808void 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! */
819pico_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
839pico_status_t picoos_emGetExceptionCode(picoos_ExceptionManager this)
840{
841    return this->curExceptionCode;
842}
843
844void picoos_emGetExceptionMessage(picoos_ExceptionManager this, picoos_char * msg, picoos_uint16 maxsize)
845{
846        picoos_strlcpy(msg,this->curExceptionMessage,maxsize);
847}
848
849void 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
872picoos_uint8 picoos_emGetNumOfWarnings(picoos_ExceptionManager this)
873{
874    return this->curNumWarnings;
875}
876
877pico_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
886void 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
913typedef 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
921typedef picoos_buffer_t picoos_buffer_array_t[picoos_MaxNrOfBuffers];
922typedef picoos_int32 picoos_buffer_index_array_t[picoos_MaxNrOfBuffers];
923
924/**  object   : File
925 *   shortcut : f
926 *
927 */
928typedef 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
944picoos_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
953void 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
966static 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
984static 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
1020static 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 */
1046static 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
1102static 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
1122static 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
1135static 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 */
1154static 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 */
1169static 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 */
1194picoos_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'. */
1202picoos_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*/
1214picoos_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'. */
1233picoos_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
1241picoos_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. */
1251picoos_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. */
1264picoos_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. */
1276picoos_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. */
1289picoos_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'. */
1302picoos_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. */
1318picoos_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 */
1331picoos_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. */
1346picoos_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 */
1365typedef picoos_uint8 two_byte_t[2];
1366
1367static 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 */
1382static 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 */
1415typedef 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. */
1435static 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
1511extern 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
1575static 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
1599extern 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
1653extern 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
1663static 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
1722extern 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
1786static 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
1814extern 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
1824extern 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
1851extern 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
1878pico_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
1890pico_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 */
1910pico_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. */
1930static 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
1942pico_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
1959pico_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
1993picoos_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
2009pico_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 */
2036pico_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
2050pico_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
2055pico_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
2078pico_status_t picoos_read_pi_uint16 (picoos_File file, picoos_uint16 * val)
2079{
2080    return picoos_read_le_uint16(file,val);
2081}
2082
2083pico_status_t picoos_read_pi_uint32 (picoos_File file, picoos_uint32 * val)
2084{
2085    return picoos_read_le_uint32(file, val);
2086}
2087
2088pico_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
2095pico_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
2105pico_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 */
2119pico_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}
2128pico_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 */
2141pico_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 */
2156picoos_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
2172pico_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
2217pico_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! */
2258void 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
2299extern 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