Home | History | Annotate | Download | only in lib
      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