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 44extern "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 */ 60typedef 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 */ 88picoos_int16 picoctrl_isValidResourceHandle(picorsrc_Resource this) 89{ 90 return (this != NULL) && CHECK_MAGIC_NUMBER(this); 91} 92 93 94static 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 114static 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 131static 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 144static 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/* 152static 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 167typedef struct picorsrc_voice_definition * picorsrc_VoiceDefinition; 168 169typedef 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 177static 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/* 196static 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 */ 211typedef 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 224pico_status_t picorsrc_createDefaultResource(picorsrc_ResourceManager this /*, 225 picorsrc_Resource * resource */); 226 227 228picorsrc_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 247void 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 259static 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 272static 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 282static 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 295static 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 337static 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 463static pico_status_t picorsrc_releaseKnowledgeBase( 464 picorsrc_ResourceManager this, 465 picoknow_KnowledgeBase * kb) 466{ 467 (*kb) = NULL; 468 return PICO_OK; 469} 470 471static 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 536pico_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 675static 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) */ 689pico_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 737pico_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 778pico_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 791static 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 814pico_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 842pico_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 888pico_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 929pico_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 1007pico_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