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 
picoos_atoi(const picoos_char * s)112 picoos_int32 picoos_atoi(const picoos_char *s)
113 {
114     return (picoos_int32)picopal_atoi((const picoos_char *)s);
115 }
116 
117 
picoos_strcmp(const picoos_char * a,const picoos_char * b)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 }
picoos_strncmp(const picoos_char * a,const picoos_char * b,picoos_objsize_t siz)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 
picoos_strlen(const picoos_char * s)131 picoos_uint32 picoos_strlen(const picoos_char *s)
132 {
133     return (picoos_uint32)picopal_strlen((const picopal_char *)s);
134 }
135 
picoos_strchr(const picoos_char * s,picoos_char c)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 
picoos_strstr(const picoos_char * s,const picoos_char * substr)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 
picoos_slprintf(picoos_char * b,picoos_uint32 bsize,const picoos_char * f,...)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 
picoos_strcpy(picoos_char * d,const picoos_char * s)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 
picoos_strcat(picoos_char * d,const picoos_char * s)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 
picoos_strlcpy(picoos_char * dst,const picoos_char * src,picoos_objsize_t siz)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! */
picoos_mem_copy(const void * src,void * dst,picoos_objsize_t length)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' */
picoos_mem_set(void * dest,picoos_uint8 byte_val,picoos_objsize_t length)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 
picoos_cos(const picoos_double cos_arg)188 picoos_double picoos_cos (const picoos_double cos_arg)
189 {
190     return (picoos_double) picopal_cos ((picopal_double) cos_arg);
191 }
192 
193 
picoos_sin(const picoos_double sin_arg)194 picoos_double picoos_sin (const picoos_double sin_arg)
195 {
196     return (picoos_double) picopal_sin((picopal_double) sin_arg);
197 }
picoos_fabs(const picoos_double fabs_arg)198 picoos_double picoos_fabs (const picoos_double fabs_arg)
199 {
200     return (picoos_double) picopal_fabs((picopal_double) fabs_arg);
201 }
202 
picoos_quick_exp(const picoos_double y)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 
picoos_newCommon(picoos_MemoryManager mm)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 
picoos_disposeCommon(picoos_MemoryManager mm,picoos_Common * this)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  */
picoos_raw_malloc(byte_ptr_t raw_mem,picoos_objsize_t raw_mem_size,picoos_objsize_t alloc_size,byte_ptr_t * rest_mem,picoos_objsize_t * rest_mem_size)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 */
os_init_mem_block(picoos_MemoryManager this)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 
picoos_newMemoryManager(void * raw_memory,picoos_objsize_t size,picoos_bool enableMemProt)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 
picoos_disposeMemoryManager(picoos_MemoryManager * mm)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 
picoos_allocProtMem(picoos_MemoryManager mm,picoos_objsize_t byteSize)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 
picoos_deallocProtMem(picoos_MemoryManager mm,void ** addr)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 
picoos_protectMem(picoos_MemoryManager mm,void * addr,picoos_objsize_t len,picoos_bool enable)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 
picoos_getMemUsage(picoos_MemoryManager this,picoos_bool resetIncremental,picoos_int32 * usedBytes,picoos_int32 * incrUsedBytes,picoos_int32 * maxUsedBytes)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 
picoos_showMemUsage(picoos_MemoryManager this,picoos_bool incremental,picoos_bool resetIncremental)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 
picoos_allocate(picoos_MemoryManager this,picoos_objsize_t byteSize)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 
picoos_deallocate(picoos_MemoryManager this,void ** adr)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 
picoos_emReset(picoos_ExceptionManager this)631 void picoos_emReset(picoos_ExceptionManager this)
632 {
633     this->curExceptionCode = PICO_OK;
634     this->curExceptionMessage[0] = '\0';
635     this->curNumWarnings = 0;
636 }
637 
picoos_newExceptionManager(picoos_MemoryManager mm)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 
picoos_disposeExceptionManager(picoos_MemoryManager mm,picoos_ExceptionManager * this)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 
picoos_vSetErrorMsg(picoos_char * dst,picoos_objsize_t siz,picoos_int16 code,picoos_char * base,const picoos_char * fmt,va_list args)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 
picoos_setErrorMsg(picoos_char * dst,picoos_objsize_t siz,picoos_int16 code,picoos_char * base,const picoos_char * fmt,...)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! */
picoos_emRaiseException(picoos_ExceptionManager this,pico_status_t exceptionCode,picoos_char * baseMessage,picoos_char * fmt,...)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 
picoos_emGetExceptionCode(picoos_ExceptionManager this)839 pico_status_t picoos_emGetExceptionCode(picoos_ExceptionManager this)
840 {
841     return this->curExceptionCode;
842 }
843 
picoos_emGetExceptionMessage(picoos_ExceptionManager this,picoos_char * msg,picoos_uint16 maxsize)844 void picoos_emGetExceptionMessage(picoos_ExceptionManager this, picoos_char * msg, picoos_uint16 maxsize)
845 {
846         picoos_strlcpy(msg,this->curExceptionMessage,maxsize);
847 }
848 
picoos_emRaiseWarning(picoos_ExceptionManager this,pico_status_t warningCode,picoos_char * baseMessage,picoos_char * fmt,...)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 
picoos_emGetNumOfWarnings(picoos_ExceptionManager this)872 picoos_uint8 picoos_emGetNumOfWarnings(picoos_ExceptionManager this)
873 {
874     return this->curNumWarnings;
875 }
876 
picoos_emGetWarningCode(picoos_ExceptionManager this,picoos_uint8 index)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 
picoos_emGetWarningMessage(picoos_ExceptionManager this,picoos_uint8 index,picoos_char * msg,picoos_uint16 maxsize)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 
picoos_newFile(picoos_MemoryManager mm)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 
picoos_disposeFile(picoos_MemoryManager mm,picoos_File * this)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 
os_min(const picoos_int32 x,const picoos_int32 y)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 
LOpen(picoos_Common g,picoos_File * f,picoos_char fileName[],picopal_access_mode mode)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 
LClose(picoos_Common g,picoos_File * f)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 */
LReadBytes(picoos_File f,picoos_uint8 bytes[],picoos_uint32 * len)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 
LWriteBytes(picoos_File f,const picoos_char bytes[],int * len)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 
LSetPos(picoos_File f,unsigned int pos)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 
LGetPos(picoos_File f,picoos_uint32 * pos)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 
LEof(picoos_File f)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 */
picoos_StrRead(picoos_File f,picoos_char str[])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 */
picoos_WriteStr(picoos_File f,picoos_char str[])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  */
picoos_OpenBinary(picoos_Common g,picoos_File * f,picoos_char fileName[])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'. */
picoos_ReadByte(picoos_File f,picoos_uint8 * by)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 */
picoos_ReadBytes(picoos_File f,picoos_uint8 bytes[],picoos_uint32 * len)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'. */
picoos_CreateBinary(picoos_Common g,picoos_File * f,picoos_char fileName[])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 
picoos_WriteByte(picoos_File f,picoos_char by)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. */
picoos_WriteBytes(picoos_File f,const picoos_char bytes[],picoos_int32 * len)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. */
picoos_CloseBinary(picoos_Common g,picoos_File * f)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. */
picoos_Eof(picoos_File f)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. */
picoos_SetPos(picoos_File f,picoos_int32 pos)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'. */
picoos_GetPos(picoos_File f,picoos_uint32 * pos)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. */
picoos_FileLength(picoos_File f,picoos_uint32 * len)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 */
picoos_Name(picoos_File f,picoos_char name[],picoos_uint32 maxsize)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. */
picoos_FileExists(picoos_Common g,picoos_char name[])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 
arr_conv_le_int16(picoos_uint8 src[],picoos_uint32 srcShortStartInd,picoos_uint32 nrElems,picoos_int16 dst[],picoos_uint32 dstStartInd)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 */
arr_conv_int16_le(picoos_int16 src[],picoos_uint32 srcStartInd,picoos_uint32 nrElems,picoos_uint8 dst[],picoos_uint32 dstShortStartInd)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. */
picoos_readWavHeader(picoos_File f,picoos_uint32 * sf,picoos_encoding_t * enc,picoos_uint32 * nrSamples,picoos_uint32 * hdrSize)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 
picoos_sdfOpenIn(picoos_Common g,picoos_SDFile * sdFile,picoos_char fileName[],picoos_uint32 * sf,picoos_encoding_t * enc,picoos_uint32 * numSamples)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 
picoos_sdfLoadSamples(picoos_SDFile sdFile,picoos_uint32 * nrSamples)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 
picoos_sdfGetSamples(picoos_SDFile sdFile,picoos_uint32 start,picoos_uint32 * nrSamples,picoos_int16 samples[])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 
picoos_sdfCloseIn(picoos_Common g,picoos_SDFile * sdFile)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 
picoos_writeWavHeader(picoos_File f,picoos_uint32 sf,picoos_encoding_t enc,picoos_uint32 nrSamples,picoos_uint32 * hdrSize)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 
picoos_sdfOpenOut(picoos_Common g,picoos_SDFile * sdFile,picoos_char fileName[],int sf,picoos_encoding_t enc)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 
picoos_sdfFlushOutBuf(picoos_SDFile sdFile)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 
picoos_sdfFlushOutput(picoos_SDFile sdFile)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 
picoos_sdfPutSamples(picoos_SDFile sdFile,picoos_uint32 nrSamples,picoos_int16 samples[])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 
picoos_sdfCloseOut(picoos_Common g,picoos_SDFile * sdFile)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 
picoos_clearHeader(picoos_FileHeader header)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 
picoos_setHeaderField(picoos_FileHeader header,picoos_uint8 index,picoos_char * key,picoos_char * value,picoos_compare_op_t op)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 */
picoos_getHeaderField(picoos_FileHeader header,picoos_uint8 index,picoos_field_string_t key,picoos_field_string_t value,picoos_compare_op_t * op)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. */
os_matched(picoos_char * str,picoos_uint32 strlen,picoos_char * buf,picoos_int32 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 
picoos_getSVOXHeaderString(picoos_char * str,picoos_uint8 * len,picoos_uint32 maxlen)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 
picoos_readPicoHeader(picoos_File f,picoos_uint32 * headerlen)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 
picoos_get_str(picoos_char * fromStr,picoos_uint32 * pos,picoos_char * toStr,picoos_objsize_t maxsize)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 
picoos_hdrParseHeader(picoos_FileHeader header,picoos_header_string_t str)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 */
picoos_read_le_uint16(picoos_File file,picoos_uint16 * val)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 
picoos_read_le_int16(picoos_File file,picoos_int16 * val)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 
picoos_read_le_uint32(picoos_File file,picoos_uint32 * val)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 
picoos_read_pi_uint16(picoos_File file,picoos_uint16 * val)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 
picoos_read_pi_uint32(picoos_File file,picoos_uint32 * val)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 
picoos_read_pi_int32(picoos_File file,picoos_int32 * val)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 
picoos_read_mem_pi_uint16(picoos_uint8 * data,picoos_uint32 * pos,picoos_uint16 * val)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 
picoos_read_mem_pi_uint32(picoos_uint8 * data,picoos_uint32 * pos,picoos_uint32 * val)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 */
picoos_write_le_uint16(picoos_File file,picoos_uint16 val)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 }
picoos_write_le_uint32(picoos_File file,picoos_uint32 val)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 */
picoos_write_mem_pi_uint16(picoos_uint8 * data,picoos_uint32 * pos,picoos_uint16 val)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 */
picoos_has_extension(const picoos_char * str,const picoos_char * suf)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 
picoos_string_to_int32(picoos_char str[],picoos_int32 * res)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 
picoos_string_to_uint32(picoos_char str[],picoos_uint32 * res)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! */
picoos_get_sep_part_str(picoos_char string[],picoos_int32 stringlen,picoos_int32 * ind,picoos_char sepCh,picoos_char part[],picoos_int32 maxsize,picoos_uint8 * done)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 
picoos_get_timer(picopal_uint32 * sec,picopal_uint32 * usec)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