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