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 picorsrc.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 "picodefs.h" 28 #include "picoos.h" 29 #include "picodbg.h" 30 31 /* knowledge layer */ 32 #include "picoknow.h" 33 34 #include "picokdt.h" 35 #include "picoklex.h" 36 #include "picokfst.h" 37 #include "picokpdf.h" 38 #include "picoktab.h" 39 #include "picokpr.h" 40 41 #include "picorsrc.h" 42 43 #ifdef __cplusplus 44 extern "C" { 45 #endif 46 #if 0 47 } 48 #endif 49 50 51 #if defined(PICO_DEBUG) 52 #include "picokdbg.h" 53 #endif 54 55 56 /** object : Resource 57 * shortcut : rsrc 58 * 59 */ 60 typedef struct picorsrc_resource { 61 picoos_uint32 magic; /* magic number used to validate handles */ 62 /* next connects all active resources of a resource manager and the garbaged resources of the manager's free list */ 63 picorsrc_Resource next; 64 picorsrc_resource_type_t type; 65 picorsrc_resource_name_t name; 66 picoos_int8 lockCount; /* count of current subscribers of this resource */ 67 picoos_File file; 68 picoos_uint8 * raw_mem; /* pointer to allocated memory. NULL if preallocated. */ 69 /* picoos_uint32 size; */ 70 picoos_uint8 * start; /* start of content (after header) */ 71 picoknow_KnowledgeBase kbList; 72 } picorsrc_resource_t; 73 74 75 #define MAGIC_MASK 0x7049634F /* pIcO */ 76 77 #define SET_MAGIC_NUMBER(res) \ 78 (res)->magic = ((picoos_uint32) (res)) ^ MAGIC_MASK 79 80 #define CHECK_MAGIC_NUMBER(res) \ 81 ((res)->magic == (((picoos_uint32) (res)) ^ MAGIC_MASK)) 82 83 84 85 /** 86 * Returns non-zero if 'this' is a valid resource handle, zero otherwise. 87 */ 88 picoos_int16 picoctrl_isValidResourceHandle(picorsrc_Resource this) 89 { 90 return (this != NULL) && CHECK_MAGIC_NUMBER(this); 91 } 92 93 94 static picorsrc_Resource picorsrc_newResource(picoos_MemoryManager mm) 95 { 96 picorsrc_Resource this = picoos_allocate(mm, sizeof(*this)); 97 if (NULL != this) { 98 SET_MAGIC_NUMBER(this); 99 /* initialize */ 100 this->name[0] = NULLC; 101 /* picoos_strlcpy(this->name, name,PICORSRC_MAX_RSRC_NAME_SIZ); */ 102 this->next = NULL; 103 this->type = PICORSRC_TYPE_NULL; 104 this->lockCount = 0; 105 this->file = NULL; 106 this->raw_mem = NULL; 107 this->start = NULL; 108 this->kbList = NULL; 109 /* this->size=0; */ 110 } 111 return this; 112 } 113 114 static void picorsrc_disposeResource(picoos_MemoryManager mm, picorsrc_Resource * this) 115 { 116 if (NULL != (*this)) { 117 (*this)->magic ^= 0xFFFEFDFC; 118 /* we have to explicitly free 'raw_mem' here because in testing 119 scenarios (where memory protection functionality is enabled) 120 it might be allocated aside from normal memory */ 121 if ((*this)->raw_mem != NULL) { 122 picoos_deallocProtMem(mm, (void *) &(*this)->raw_mem); 123 } 124 picoos_deallocate(mm,(void * *)this); 125 } 126 } 127 128 129 130 131 static void picorsrc_initializeVoice(picorsrc_Voice this) 132 { 133 picoos_uint16 i; 134 if (NULL != this) { 135 /* initialize */ 136 for (i=0; i<PICORSRC_KB_ARRAY_SIZE; i++) { 137 this->kbArray[i] = NULL; 138 } 139 this->numResources = 0; 140 this->next = NULL; 141 } 142 } 143 144 static picorsrc_Voice picorsrc_newVoice(picoos_MemoryManager mm) 145 { 146 picorsrc_Voice this = (picorsrc_Voice) picoos_allocate(mm,sizeof(*this)); 147 picorsrc_initializeVoice(this); 148 return this; 149 } 150 151 /* 152 static void picorsrc_disposeVoice(picoos_MemoryManager mm, picorsrc_Voice * this) 153 { 154 if (NULL != (*this)) { 155 156 picoos_deallocate(mm,(void *)this); 157 } 158 } 159 */ 160 161 162 /** object : VoiceDefinition 163 * shortcut : vdef 164 * 165 */ 166 167 typedef struct picorsrc_voice_definition * picorsrc_VoiceDefinition; 168 169 typedef struct picorsrc_voice_definition { 170 picoos_char voiceName[PICO_MAX_VOICE_NAME_SIZE]; 171 picoos_uint8 numResources; 172 picorsrc_resource_name_t resourceName[PICO_MAX_NUM_RSRC_PER_VOICE]; 173 picorsrc_VoiceDefinition next; 174 } picorsrc_voice_definition_t; 175 176 177 static picorsrc_VoiceDefinition picorsrc_newVoiceDefinition(picoos_MemoryManager mm) 178 { 179 /* picoos_uint8 i; */ 180 picorsrc_VoiceDefinition this = (picorsrc_VoiceDefinition) picoos_allocate(mm,sizeof(*this)); 181 if (NULL != this) { 182 /* initialize */ 183 this->voiceName[0] = NULLC; 184 this->numResources = 0; 185 /* 186 for (i=0; i < PICO_MAX_NUM_RSRC_PER_VOICE; i++) { 187 this->resourceName[i][0] = NULLC; 188 } 189 */ 190 this->next = NULL; 191 } 192 return this; 193 } 194 195 /* 196 static void picorsrc_disposeVoiceDefinition(picoos_MemoryManager mm, picorsrc_VoiceDefinition * this) 197 { 198 if (NULL != (*this)) { 199 200 picoos_deallocate(mm,(void *)this); 201 } 202 } 203 */ 204 205 206 207 /** object : ResourceManager 208 * shortcut : rm 209 * 210 */ 211 typedef struct picorsrc_resource_manager { 212 picoos_Common common; 213 picoos_uint16 numResources; 214 picorsrc_Resource resources, freeResources; 215 picoos_uint16 numVoices; 216 picorsrc_Voice voices, freeVoices; 217 picoos_uint16 numVdefs; 218 picorsrc_VoiceDefinition vdefs, freeVdefs; 219 picoos_uint16 numKbs; 220 picoknow_KnowledgeBase freeKbs; 221 picoos_header_string_t tmpHeader; 222 } picorsrc_resource_manager_t; 223 224 pico_status_t picorsrc_createDefaultResource(picorsrc_ResourceManager this /*, 225 picorsrc_Resource * resource */); 226 227 228 picorsrc_ResourceManager picorsrc_newResourceManager(picoos_MemoryManager mm, picoos_Common common /* , picoos_char * configFile */) 229 { 230 picorsrc_ResourceManager this = picoos_allocate(mm,sizeof(*this)); 231 if (NULL != this) { 232 /* initialize */ 233 this->common = common; 234 this->numResources = 0; 235 this->resources = NULL; 236 this->freeResources = NULL; 237 this->numVoices = 0; 238 this->voices = NULL; 239 this->freeVoices = NULL; 240 this->numVdefs = 0; 241 this->vdefs = NULL; 242 this->freeVdefs = NULL; 243 } 244 return this; 245 } 246 247 void picorsrc_disposeResourceManager(picoos_MemoryManager mm, picorsrc_ResourceManager * this) 248 { 249 if (NULL != (*this)) { 250 /* terminate */ 251 picoos_deallocate(mm,(void *)this); 252 } 253 } 254 255 256 /* ******* accessing resources **************************************/ 257 258 259 static pico_status_t findResource(picorsrc_ResourceManager this, picoos_char * resourceName, picorsrc_Resource * rsrc) { 260 picorsrc_Resource r; 261 if (NULL == this) { 262 return PICO_ERR_NULLPTR_ACCESS; 263 } 264 r = this->resources; 265 while (NULL != r && (0 != picoos_strcmp(r->name,resourceName))) { 266 r = r->next; 267 } 268 *rsrc = r; 269 return PICO_OK; 270 } 271 272 static picoos_uint8 isResourceLoaded(picorsrc_ResourceManager this, picoos_char * resourceName) { 273 picorsrc_Resource res; 274 275 if (PICO_OK == findResource(this, resourceName,&res)){ 276 return (NULL != res); 277 } else { 278 return FALSE; 279 } 280 } 281 282 static pico_status_t parse_resource_name(picoos_char * fileName) 283 { 284 PICODBG_DEBUG(("analysing file name %s",fileName)); 285 if (picoos_has_extension(fileName, 286 (picoos_char *)PICO_BIN_EXTENSION)) { 287 return PICO_OK; 288 } else { 289 return PICO_EXC_UNEXPECTED_FILE_TYPE; 290 } 291 } 292 293 294 295 static pico_status_t readHeader(picorsrc_ResourceManager this, 296 picoos_FileHeader header, picoos_uint32 * headerlen, picoos_File file) 297 { 298 299 picoos_uint16 hdrlen1; 300 picoos_uint32 n; 301 pico_status_t status; 302 303 304 /* read PICO header */ 305 status = picoos_readPicoHeader(file, headerlen); 306 if (PICO_OK == status) { 307 308 } else { 309 return picoos_emRaiseException(this->common->em,status,NULL,(picoos_char *)"problem reading file header"); 310 } 311 /* read header length (excluding length itself) */ 312 status = picoos_read_pi_uint16(file,&hdrlen1); 313 PICODBG_DEBUG(("got header size %d",hdrlen1)); 314 315 if (PICO_OK == status) { 316 *headerlen += 2; 317 status = (hdrlen1 <= PICOOS_MAX_HEADER_STRING_LEN-1) ? PICO_OK : PICO_ERR_OTHER; 318 if (PICO_OK == status) { 319 n = hdrlen1; 320 if (picoos_ReadBytes(file, (picoos_uint8 *) this->tmpHeader, &n) && hdrlen1 == n) { 321 this->tmpHeader[hdrlen1] = NULLC; 322 *headerlen += hdrlen1; 323 PICODBG_DEBUG(("got header <%s>",this->tmpHeader)); 324 325 status = PICO_OK; 326 } else { 327 status = PICO_ERR_OTHER; 328 } 329 } 330 if (PICO_OK == status) { 331 status = picoos_hdrParseHeader(header, this->tmpHeader); 332 } 333 } 334 return status; 335 } 336 337 static pico_status_t picorsrc_createKnowledgeBase( 338 picorsrc_ResourceManager this, 339 picoos_uint8 * data, 340 picoos_uint32 size, 341 picoknow_kb_id_t kbid, 342 picoknow_KnowledgeBase * kb) 343 { 344 (*kb) = picoknow_newKnowledgeBase(this->common->mm); 345 if (NULL == (*kb)) { 346 return PICO_EXC_OUT_OF_MEM; 347 } 348 (*kb)->base = data; 349 (*kb)->size = size; 350 (*kb)->id = kbid; 351 switch (kbid) { 352 case PICOKNOW_KBID_TPP_MAIN: 353 case PICOKNOW_KBID_TPP_USER_1: 354 case PICOKNOW_KBID_TPP_USER_2: 355 return picokpr_specializePreprocKnowledgeBase(*kb, this->common); 356 break; 357 case PICOKNOW_KBID_TAB_GRAPHS: 358 return picoktab_specializeGraphsKnowledgeBase(*kb, this->common); 359 break; 360 case PICOKNOW_KBID_TAB_PHONES: 361 return picoktab_specializePhonesKnowledgeBase(*kb, this->common); 362 break; 363 case PICOKNOW_KBID_TAB_POS: 364 return picoktab_specializePosKnowledgeBase(*kb, this->common); 365 break; 366 case PICOKNOW_KBID_FIXED_IDS: 367 return picoktab_specializeIdsKnowledgeBase(*kb, this->common); 368 break; 369 case PICOKNOW_KBID_LEX_MAIN: 370 case PICOKNOW_KBID_LEX_USER_1: 371 case PICOKNOW_KBID_LEX_USER_2: 372 return picoklex_specializeLexKnowledgeBase(*kb, this->common); 373 break; 374 case PICOKNOW_KBID_DT_POSP: 375 return picokdt_specializeDtKnowledgeBase(*kb, this->common, 376 PICOKDT_KDTTYPE_POSP); 377 break; 378 case PICOKNOW_KBID_DT_POSD: 379 return picokdt_specializeDtKnowledgeBase(*kb, this->common, 380 PICOKDT_KDTTYPE_POSD); 381 break; 382 case PICOKNOW_KBID_DT_G2P: 383 return picokdt_specializeDtKnowledgeBase(*kb, this->common, 384 PICOKDT_KDTTYPE_G2P); 385 break; 386 case PICOKNOW_KBID_DT_PHR: 387 return picokdt_specializeDtKnowledgeBase(*kb, this->common, 388 PICOKDT_KDTTYPE_PHR); 389 break; 390 case PICOKNOW_KBID_DT_ACC: 391 return picokdt_specializeDtKnowledgeBase(*kb, this->common, 392 PICOKDT_KDTTYPE_ACC); 393 break; 394 case PICOKNOW_KBID_FST_SPHO_1: 395 case PICOKNOW_KBID_FST_SPHO_2: 396 case PICOKNOW_KBID_FST_SPHO_3: 397 case PICOKNOW_KBID_FST_SPHO_4: 398 case PICOKNOW_KBID_FST_SPHO_5: 399 case PICOKNOW_KBID_FST_SPHO_6: 400 case PICOKNOW_KBID_FST_SPHO_7: 401 case PICOKNOW_KBID_FST_SPHO_8: 402 case PICOKNOW_KBID_FST_SPHO_9: 403 case PICOKNOW_KBID_FST_SPHO_10: 404 case PICOKNOW_KBID_FST_WPHO_1: 405 case PICOKNOW_KBID_FST_WPHO_2: 406 case PICOKNOW_KBID_FST_WPHO_3: 407 case PICOKNOW_KBID_FST_WPHO_4: 408 case PICOKNOW_KBID_FST_WPHO_5: 409 case PICOKNOW_KBID_FST_SVOXPA_PARSE: 410 case PICOKNOW_KBID_FST_XSAMPA_PARSE: 411 case PICOKNOW_KBID_FST_XSAMPA2SVOXPA: 412 413 return picokfst_specializeFSTKnowledgeBase(*kb, this->common); 414 break; 415 416 case PICOKNOW_KBID_DT_DUR: 417 case PICOKNOW_KBID_DT_LFZ1: 418 case PICOKNOW_KBID_DT_LFZ2: 419 case PICOKNOW_KBID_DT_LFZ3: 420 case PICOKNOW_KBID_DT_LFZ4: 421 case PICOKNOW_KBID_DT_LFZ5: 422 case PICOKNOW_KBID_DT_MGC1: 423 case PICOKNOW_KBID_DT_MGC2: 424 case PICOKNOW_KBID_DT_MGC3: 425 case PICOKNOW_KBID_DT_MGC4: 426 case PICOKNOW_KBID_DT_MGC5: 427 return picokdt_specializeDtKnowledgeBase(*kb, this->common, 428 PICOKDT_KDTTYPE_PAM); 429 break; 430 case PICOKNOW_KBID_PDF_DUR: 431 return picokpdf_specializePdfKnowledgeBase(*kb, this->common, 432 PICOKPDF_KPDFTYPE_DUR); 433 434 break; 435 case PICOKNOW_KBID_PDF_LFZ: 436 return picokpdf_specializePdfKnowledgeBase(*kb, this->common, 437 PICOKPDF_KPDFTYPE_MUL); 438 break; 439 case PICOKNOW_KBID_PDF_MGC: 440 return picokpdf_specializePdfKnowledgeBase(*kb, this->common, 441 PICOKPDF_KPDFTYPE_MUL); 442 break; 443 case PICOKNOW_KBID_PDF_PHS: 444 return picokpdf_specializePdfKnowledgeBase(*kb, this->common, 445 PICOKPDF_KPDFTYPE_PHS); 446 break; 447 448 449 450 #if defined(PICO_DEBUG) 451 case PICOKNOW_KBID_DBG: 452 return picokdbg_specializeDbgKnowledgeBase(*kb, this->common); 453 break; 454 #endif 455 456 default: 457 break; 458 } 459 return PICO_OK; 460 } 461 462 463 static pico_status_t picorsrc_releaseKnowledgeBase( 464 picorsrc_ResourceManager this, 465 picoknow_KnowledgeBase * kb) 466 { 467 (*kb) = NULL; 468 return PICO_OK; 469 } 470 471 static pico_status_t picorsrc_getKbList(picorsrc_ResourceManager this, 472 picoos_uint8 * data, 473 picoos_uint32 datalen, 474 picoknow_KnowledgeBase * kbList) 475 { 476 477 pico_status_t status = PICO_OK; 478 picoos_uint32 curpos = 0, offset, size; 479 picoos_uint8 i, numKbs, kbid; 480 picoos_char str[PICOKNOW_MAX_KB_NAME_SIZ]; 481 picoknow_KnowledgeBase kb; 482 483 *kbList = NULL; 484 datalen = datalen; 485 /* read number of fields */ 486 numKbs = data[curpos++]; 487 PICODBG_DEBUG(("number of kbs (unrestricted) = %i",numKbs)); 488 status = (numKbs <= PICOKNOW_MAX_NUM_RESOURCE_KBS) ? PICO_OK : PICO_EXC_FILE_CORRUPT; 489 /* read in all kb names */ 490 PICODBG_DEBUG(("number of kbs = %i",numKbs)); 491 i = 0; 492 while ((PICO_OK == status) && (i++ < numKbs)) { 493 status = (picoos_get_str((picoos_char *)data,&curpos,str,PICOOS_MAX_FIELD_STRING_LEN)) ? PICO_OK : PICO_EXC_FILE_CORRUPT; 494 PICODBG_DEBUG(("contains knowledge base %s (status: %i)",str, status)); 495 } 496 /* consume termination of last str */ 497 curpos++; 498 i = 0; 499 while ((PICO_OK == status) && (i++ < numKbs)) { 500 kbid = data[curpos++]; 501 PICODBG_DEBUG(("got kb id %i, curpos now %i",kbid, curpos)); 502 status = picoos_read_mem_pi_uint32(data,&curpos,&offset); 503 PICODBG_DEBUG(("got kb offset %i, curpos now %i",offset, curpos)); 504 status = picoos_read_mem_pi_uint32(data,&curpos,&size); 505 PICODBG_DEBUG(("got kb size %i, curpos now %i",size, curpos)); 506 if (PICO_OK == status) { 507 if (0 == offset) { 508 /* currently we consider a kb mentioned in resource but with offset 0 (no knowledge) as 509 * different form a kb not mentioned at all. We might reconsider that later. */ 510 PICODBG_DEBUG((" kb (id %i) is mentioned but empty (base:%i, size:%i)",kb->id, kb->base, kb->size)); 511 status = picorsrc_createKnowledgeBase(this, NULL, size, (picoknow_kb_id_t)kbid, &kb); 512 } else { 513 status = picorsrc_createKnowledgeBase(this, data+offset, size, (picoknow_kb_id_t)kbid, &kb); 514 } 515 PICODBG_DEBUG(("found kb (id %i) starting at %i with size %i",kb->id, kb->base, kb->size)); 516 if (PICO_OK == status) { 517 kb->next = *kbList; 518 *kbList = kb; 519 } 520 } 521 } 522 if (PICO_OK != status) { 523 kb = *kbList; 524 while (NULL != kb) { 525 picorsrc_releaseKnowledgeBase(this,&kb); 526 } 527 } 528 529 return status; 530 531 } 532 533 /* load resource file. the type of resource file etc. are in the header, 534 * then follows the directory, then the knowledge bases themselves (as byte streams) */ 535 536 pico_status_t picorsrc_loadResource(picorsrc_ResourceManager this, 537 picoos_char * fileName, picorsrc_Resource * resource) 538 { 539 picorsrc_Resource res; 540 picoos_uint32 headerlen, len,maxlen; 541 picoos_file_header_t header; 542 picoos_uint8 rem; 543 pico_status_t status = PICO_OK; 544 545 if (resource == NULL) { 546 return PICO_ERR_NULLPTR_ACCESS; 547 } else { 548 *resource = NULL; 549 } 550 551 res = picorsrc_newResource(this->common->mm); 552 553 if (NULL == res) { 554 return picoos_emRaiseException(this->common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); 555 } 556 557 if (PICO_MAX_NUM_RESOURCES <= this->numResources) { 558 picoos_deallocate(this->common->mm, (void *) &res); 559 return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i resources",PICO_MAX_NUM_RESOURCES); 560 } 561 562 /* ***************** parse file name for file type and parameters */ 563 564 if (PICO_OK != parse_resource_name(fileName)) { 565 picoos_deallocate(this->common->mm, (void *) &res); 566 return PICO_EXC_UNEXPECTED_FILE_TYPE; 567 } 568 569 /* ***************** get header info */ 570 571 /* open binary file for reading (no key, nrOfBufs, bufSize) */ 572 PICODBG_DEBUG(("trying to open file %s",fileName)); 573 if (!picoos_OpenBinary(this->common, &res->file, fileName)) { 574 /* open didn't succeed */ 575 status = PICO_EXC_CANT_OPEN_FILE; 576 PICODBG_ERROR(("can't open file %s",fileName)); 577 picoos_emRaiseException(this->common->em, PICO_EXC_CANT_OPEN_FILE, 578 NULL, (picoos_char *) "%s", fileName); 579 } 580 if (PICO_OK == status) { 581 status = readHeader(this, &header, &headerlen, res->file); 582 /* res->file now positioned at first pos after header */ 583 } 584 585 /* ***************** check header values */ 586 if (PICO_OK == status && isResourceLoaded(this, header.field[PICOOS_HEADER_NAME].value)) { 587 /* lingware is allready loaded, do nothing */ 588 PICODBG_WARN((">>> lingware '%s' allready loaded",header.field[PICOOS_HEADER_NAME].value)); 589 picoos_emRaiseWarning(this->common->em,PICO_WARN_RESOURCE_DOUBLE_LOAD,NULL,(picoos_char *)"%s",header.field[PICOOS_HEADER_NAME].value); 590 status = PICO_WARN_RESOURCE_DOUBLE_LOAD; 591 } 592 593 if (PICO_OK == status) { 594 /* get data length */ 595 status = picoos_read_pi_uint32(res->file, &len); 596 PICODBG_DEBUG(("found net resource len of %i",len)); 597 /* allocate memory */ 598 if (PICO_OK == status) { 599 PICODBG_TRACE((">>> 2")); 600 maxlen = len + PICOOS_ALIGN_SIZE; /* once would be sufficient? */ 601 res->raw_mem = picoos_allocProtMem(this->common->mm, maxlen); 602 /* res->size = maxlen; */ 603 status = (NULL == res->raw_mem) ? PICO_EXC_OUT_OF_MEM : PICO_OK; 604 } 605 if (PICO_OK == status) { 606 rem = (picoos_uint32) res->raw_mem % PICOOS_ALIGN_SIZE; 607 if (rem > 0) { 608 res->start = res->raw_mem + (PICOOS_ALIGN_SIZE - rem); 609 } else { 610 res->start = res->raw_mem; 611 } 612 613 /* read file contents into memory */ 614 status = (picoos_ReadBytes(res->file, res->start, &len)) ? PICO_OK 615 : PICO_ERR_OTHER; 616 /* resources are read-only; the following write protection 617 has an effect in test configurations only */ 618 picoos_protectMem(this->common->mm, res->start, len, /*enable*/TRUE); 619 } 620 /* note resource unique name */ 621 if (PICO_OK == status) { 622 if (picoos_strlcpy(res->name,header.field[PICOOS_HEADER_NAME].value,PICORSRC_MAX_RSRC_NAME_SIZ) < PICORSRC_MAX_RSRC_NAME_SIZ) { 623 PICODBG_DEBUG(("assigned name %s to resource",res->name)); 624 status = PICO_OK; 625 } else { 626 status = PICO_ERR_INDEX_OUT_OF_RANGE; 627 PICODBG_ERROR(("failed assigning name %s to resource", 628 res->name)); 629 picoos_emRaiseException(this->common->em, 630 PICO_ERR_INDEX_OUT_OF_RANGE, NULL, 631 (picoos_char *)"resource %s",res->name); 632 } 633 } 634 635 /* get resource type */ 636 if (PICO_OK == status) { 637 if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_TEXTANA)) { 638 res->type = PICORSRC_TYPE_TEXTANA; 639 } else if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_SIGGEN)) { 640 res->type = PICORSRC_TYPE_SIGGEN; 641 } else if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_SIGGEN)) { 642 res->type = PICORSRC_TYPE_USER_LEX; 643 } else if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_SIGGEN)) { 644 res->type = PICORSRC_TYPE_USER_PREPROC; 645 } else { 646 res->type = PICORSRC_TYPE_OTHER; 647 } 648 } 649 650 if (PICO_OK == status) { 651 /* create kb list from resource */ 652 status = picorsrc_getKbList(this, res->start, len, &res->kbList); 653 } 654 } 655 656 if (status == PICO_OK) { 657 /* add resource to rm */ 658 res->next = this->resources; 659 this->resources = res; 660 this->numResources++; 661 *resource = res; 662 PICODBG_DEBUG(("done loading resource %s from %s", res->name, fileName)); 663 } else { 664 picorsrc_disposeResource(this->common->mm, &res); 665 PICODBG_ERROR(("failed to load resource")); 666 } 667 668 if (status < 0) { 669 return status; 670 } else { 671 return PICO_OK; 672 } 673 } 674 675 static pico_status_t picorsrc_releaseKbList(picorsrc_ResourceManager this, picoknow_KnowledgeBase * kbList) 676 { 677 picoknow_KnowledgeBase kbprev, kb; 678 kb = *kbList; 679 while (NULL != kb) { 680 kbprev = kb; 681 kb = kb->next; 682 picoknow_disposeKnowledgeBase(this->common->mm,&kbprev); 683 } 684 *kbList = NULL; 685 return PICO_OK; 686 } 687 688 /* unload resource file. (if resource file is busy, warn and don't unload) */ 689 pico_status_t picorsrc_unloadResource(picorsrc_ResourceManager this, picorsrc_Resource * resource) { 690 691 picorsrc_Resource r1, r2, rsrc; 692 693 if (resource == NULL) { 694 return PICO_ERR_NULLPTR_ACCESS; 695 } else { 696 rsrc = *resource; 697 } 698 699 if (rsrc->lockCount > 0) { 700 return PICO_EXC_RESOURCE_BUSY; 701 } 702 /* terminate */ 703 if (rsrc->file != NULL) { 704 picoos_CloseBinary(this->common, &rsrc->file); 705 } 706 if (NULL != rsrc->raw_mem) { 707 picoos_deallocProtMem(this->common->mm, (void *) &rsrc->raw_mem); 708 PICODBG_DEBUG(("deallocated raw mem")); 709 } 710 711 r1 = NULL; 712 r2 = this->resources; 713 while (r2 != NULL && r2 != rsrc) { 714 r1 = r2; 715 r2 = r2->next; 716 } 717 if (NULL == r1) { 718 this->resources = rsrc->next; 719 } else if (NULL == r2) { 720 /* didn't find resource in rm! */ 721 return PICO_ERR_OTHER; 722 } else { 723 r1->next = rsrc->next; 724 } 725 726 if (NULL != rsrc->kbList) { 727 picorsrc_releaseKbList(this, &rsrc->kbList); 728 } 729 730 picoos_deallocate(this->common->mm,(void **)resource); 731 this->numResources--; 732 733 return PICO_OK; 734 } 735 736 737 pico_status_t picorsrc_createDefaultResource(picorsrc_ResourceManager this 738 /*, picorsrc_Resource * resource */) 739 { 740 picorsrc_Resource res; 741 pico_status_t status = PICO_OK; 742 743 744 /* *resource = NULL; */ 745 746 if (PICO_MAX_NUM_RESOURCES <= this->numResources) { 747 return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i resources",PICO_MAX_NUM_RESOURCES); 748 } 749 750 res = picorsrc_newResource(this->common->mm); 751 752 if (NULL == res) { 753 return picoos_emRaiseException(this->common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); 754 } 755 756 if (picoos_strlcpy(res->name,PICOKNOW_DEFAULT_RESOURCE_NAME,PICORSRC_MAX_RSRC_NAME_SIZ) < PICORSRC_MAX_RSRC_NAME_SIZ) { 757 PICODBG_DEBUG(("assigned name %s to default resource",res->name)); 758 status = PICO_OK; 759 } else { 760 PICODBG_ERROR(("failed assigning name %s to default resource",res->name)); 761 status = PICO_ERR_INDEX_OUT_OF_RANGE; 762 } 763 status = picorsrc_createKnowledgeBase(this, NULL, 0, (picoknow_kb_id_t)PICOKNOW_KBID_FIXED_IDS, &res->kbList); 764 765 if (PICO_OK == status) { 766 res->next = this->resources; 767 this->resources = res; 768 this->numResources++; 769 /* *resource = res; */ 770 771 } 772 773 774 return status; 775 776 } 777 778 pico_status_t picorsrc_rsrcGetName(picorsrc_Resource this, 779 picoos_char * name, picoos_uint32 maxlen) { 780 if (!picoctrl_isValidResourceHandle(this)) { 781 return PICO_ERR_INVALID_ARGUMENT; 782 } 783 picoos_strlcpy(name, this->name,maxlen); 784 return PICO_OK; 785 } 786 787 788 /* ******* accessing voice definitions **************************************/ 789 790 791 static pico_status_t findVoiceDefinition(picorsrc_ResourceManager this, 792 const picoos_char * voiceName, picorsrc_VoiceDefinition * vdef) 793 { 794 picorsrc_VoiceDefinition v; 795 PICODBG_DEBUG(("finding voice name %s",voiceName)); 796 if (NULL == this) { 797 return PICO_ERR_NULLPTR_ACCESS; 798 } 799 v = this->vdefs; 800 while (NULL != v && (0 != picoos_strcmp(v->voiceName,voiceName))) { 801 PICODBG_DEBUG(("%s doesnt match",v->voiceName)); 802 v = v->next; 803 } 804 *vdef = v; 805 if (v == NULL) { 806 PICODBG_DEBUG(("didnt find voice name %s",voiceName)); 807 } else { 808 PICODBG_DEBUG(("found voice name %s",voiceName)); 809 } 810 return PICO_OK; 811 } 812 813 814 pico_status_t picorsrc_addResourceToVoiceDefinition(picorsrc_ResourceManager this, 815 picoos_char * voiceName, picoos_char * resourceName) 816 { 817 picorsrc_VoiceDefinition vdef; 818 819 if (NULL == this) { 820 PICODBG_ERROR(("this is NULL")); 821 return PICO_ERR_NULLPTR_ACCESS; 822 } 823 if ((PICO_OK == findVoiceDefinition(this,voiceName,&vdef)) && (NULL != vdef)) { 824 if (PICO_MAX_NUM_RSRC_PER_VOICE <= vdef->numResources) { 825 return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i resources per voice",PICO_MAX_NUM_RSRC_PER_VOICE); 826 } 827 if (picoos_strlcpy(vdef->resourceName[vdef->numResources++], resourceName, 828 PICORSRC_MAX_RSRC_NAME_SIZ) < PICORSRC_MAX_RSRC_NAME_SIZ) { 829 PICODBG_DEBUG(("vdef added resource '%s' to voice '%s'",resourceName,voiceName)); 830 return PICO_OK; 831 } else { 832 PICODBG_ERROR(("illegal name (%s)",resourceName)); 833 return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_ILLEGAL,NULL,(picoos_char *)"%s",resourceName); 834 } 835 836 } else { 837 return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_UNDEFINED,NULL,(picoos_char *)"%s",voiceName); 838 } 839 } 840 841 842 pico_status_t picorsrc_createVoiceDefinition(picorsrc_ResourceManager this, 843 picoos_char * voiceName) 844 { 845 picorsrc_VoiceDefinition vdef; 846 847 if (NULL == this) { 848 PICODBG_ERROR(("this is NULL")); 849 return PICO_ERR_NULLPTR_ACCESS; 850 } 851 if ((PICO_OK == findVoiceDefinition(this,voiceName,&vdef)) && (NULL != vdef)) { 852 PICODBG_ERROR(("voice %s allready defined",voiceName)); 853 return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_CONFLICT,NULL,NULL); 854 } 855 if (PICO_MAX_NUM_VOICE_DEFINITIONS <= this->numVdefs) { 856 PICODBG_ERROR(("max number of vdefs exceeded (%i)",this->numVdefs)); 857 return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i voice definitions",PICO_MAX_NUM_VOICE_DEFINITIONS); 858 } 859 if (NULL == this->freeVdefs) { 860 vdef = picorsrc_newVoiceDefinition(this->common->mm); 861 } else { 862 vdef = this->freeVdefs; 863 this->freeVdefs = vdef->next; 864 vdef->voiceName[0] = NULLC; 865 vdef->numResources = 0; 866 vdef->next = NULL; 867 } 868 if (NULL == vdef) { 869 return picoos_emRaiseException(this->common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); 870 } 871 if (picoos_strlcpy(vdef->voiceName, voiceName, 872 PICO_MAX_VOICE_NAME_SIZE) < PICO_MAX_VOICE_NAME_SIZE) { 873 vdef->next = this->vdefs; 874 this->vdefs = vdef; 875 this->numVdefs++; 876 if (PICO_OK != picorsrc_addResourceToVoiceDefinition(this,voiceName,PICOKNOW_DEFAULT_RESOURCE_NAME)) { 877 return picoos_emRaiseException(this->common->em,PICO_ERR_OTHER,NULL,(picoos_char *)"problem loading default resource %s",voiceName); 878 } 879 PICODBG_DEBUG(("vdef created (%s)",voiceName)); 880 return PICO_OK; 881 } else { 882 PICODBG_ERROR(("illegal name (%s)",voiceName)); 883 return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_ILLEGAL,NULL,(picoos_char *)"%s",voiceName); 884 } 885 } 886 887 888 pico_status_t picorsrc_releaseVoiceDefinition(picorsrc_ResourceManager this, 889 picoos_char *voiceName) 890 { 891 picorsrc_VoiceDefinition v, l; 892 893 if (this == NULL) { 894 return PICO_ERR_NULLPTR_ACCESS; 895 } 896 897 l = NULL; 898 v = this->vdefs; 899 while ((v != NULL) && (picoos_strcmp(v->voiceName, voiceName) != 0)) { 900 l = v; 901 v = v->next; 902 } 903 if (v != NULL) { 904 /* remove v from vdefs list */ 905 if (l != NULL) { 906 l->next = v->next; 907 } else { 908 this->vdefs = v->next; 909 } 910 /* insert v at head of freeVdefs list */ 911 v->next = this->freeVdefs; 912 this->freeVdefs = v; 913 this->numVdefs--; 914 return PICO_OK; 915 } else { 916 /* we should rather return a warning, here */ 917 /* return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_UNDEFINED,"%s", NULL); */ 918 return PICO_OK; 919 } 920 } 921 922 923 924 /* ******* accessing voices **************************************/ 925 926 927 /* create voice, given a voice name. the corresponding lock counts are incremented */ 928 929 pico_status_t picorsrc_createVoice(picorsrc_ResourceManager this, const picoos_char * voiceName, picorsrc_Voice * voice) { 930 931 picorsrc_VoiceDefinition vdef; 932 picorsrc_Resource rsrc; 933 picoos_uint8 i, required; 934 picoknow_KnowledgeBase kb; 935 /* pico_status_t status = PICO_OK; */ 936 937 PICODBG_DEBUG(("creating voice %s",voiceName)); 938 939 if (NULL == this) { 940 PICODBG_ERROR(("this is NULL")); 941 return PICO_ERR_NULLPTR_ACCESS; 942 943 } 944 /* check number of voices */ 945 if (PICORSRC_MAX_NUM_VOICES <= this->numVoices) { 946 PICODBG_ERROR(("PICORSRC_MAX_NUM_VOICES exceeded")); 947 return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i voices",PICORSRC_MAX_NUM_VOICES); 948 } 949 950 /* find voice definition for that name */ 951 if (!(PICO_OK == findVoiceDefinition(this,voiceName,&vdef)) || (NULL == vdef)) { 952 PICODBG_ERROR(("no voice definition for %s",voiceName)); 953 return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_UNDEFINED,NULL,(picoos_char *)"voice definition %s",voiceName); 954 955 } 956 PICODBG_DEBUG(("found voice definition for %s",voiceName)); 957 958 /* check that resources are loaded */ 959 for (i = 0; i < vdef->numResources; i++) { 960 required = (NULLC != vdef->resourceName[i][0]); 961 if (required && !isResourceLoaded(this,vdef->resourceName[i])) { 962 PICODBG_ERROR(("resource missing")); 963 return picoos_emRaiseException(this->common->em,PICO_EXC_RESOURCE_MISSING,NULL,(picoos_char *)"resource %s for voice %s",vdef->resourceName[i],voiceName); 964 } 965 } 966 967 /* allocate new voice */ 968 if (NULL == this->freeVoices) { 969 *voice = picorsrc_newVoice(this->common->mm); 970 } else { 971 *voice = this->freeVoices; 972 this->freeVoices = (*voice)->next; 973 picorsrc_initializeVoice(*voice); 974 } 975 if (*voice == NULL) { 976 return picoos_emRaiseException(this->common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); 977 } 978 this->numVoices++; 979 980 /* copy resource kb pointers into kb array of voice */ 981 for (i = 0; i < vdef->numResources; i++) { 982 required = (NULLC != vdef->resourceName[i][0]); 983 if (required) { 984 findResource(this,vdef->resourceName[i],&rsrc); 985 (*voice)->resourceArray[(*voice)->numResources++] = rsrc; 986 rsrc->lockCount++; 987 kb = rsrc->kbList; 988 while (NULL != kb) { 989 if (NULL != (*voice)->kbArray[kb->id]) { 990 picoos_emRaiseWarning(this->common->em,PICO_WARN_KB_OVERWRITE,NULL, (picoos_char *)"%i", kb->id); 991 PICODBG_WARN(("overwriting knowledge base of id %i", kb->id)); 992 993 } 994 PICODBG_DEBUG(("setting knowledge base of id %i", kb->id)); 995 996 (*voice)->kbArray[kb->id] = kb; 997 kb = kb->next; 998 } 999 } 1000 } /* for */ 1001 1002 return PICO_OK; 1003 } 1004 1005 /* dispose voice. the corresponding lock counts are decremented. */ 1006 1007 pico_status_t picorsrc_releaseVoice(picorsrc_ResourceManager this, picorsrc_Voice * voice) 1008 { 1009 picoos_uint16 i; 1010 picorsrc_Voice v = *voice; 1011 if (NULL == this || NULL == v) { 1012 return PICO_ERR_NULLPTR_ACCESS; 1013 } 1014 for (i = 0; i < v->numResources; i++) { 1015 v->resourceArray[i]->lockCount--; 1016 } 1017 v->next = this->freeVoices; 1018 this->freeVoices = v; 1019 this->numVoices--; 1020 1021 return PICO_OK; 1022 } 1023 1024 #ifdef __cplusplus 1025 } 1026 #endif 1027 1028 /* end picorsrc.c */ 1029