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) (uintptr_t) (res)) ^ MAGIC_MASK
79 
80 #define CHECK_MAGIC_NUMBER(res) \
81     ((res)->magic == (((picoos_uint32) (uintptr_t) (res)) ^ MAGIC_MASK))
82 
83 
84 
85 /**
86  * Returns non-zero if 'this' is a valid resource handle, zero otherwise.
87  */
picoctrl_isValidResourceHandle(picorsrc_Resource this)88 picoos_int16 picoctrl_isValidResourceHandle(picorsrc_Resource this)
89 {
90     return (this != NULL) && CHECK_MAGIC_NUMBER(this);
91 }
92 
93 
picorsrc_newResource(picoos_MemoryManager mm)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 
picorsrc_disposeResource(picoos_MemoryManager mm,picorsrc_Resource * this)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 
picorsrc_initializeVoice(picorsrc_Voice this)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 
picorsrc_newVoice(picoos_MemoryManager mm)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 
picorsrc_newVoiceDefinition(picoos_MemoryManager mm)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 
picorsrc_newResourceManager(picoos_MemoryManager mm,picoos_Common common)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 
picorsrc_disposeResourceManager(picoos_MemoryManager mm,picorsrc_ResourceManager * this)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 
findResource(picorsrc_ResourceManager this,picoos_char * resourceName,picorsrc_Resource * rsrc)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 
isResourceLoaded(picorsrc_ResourceManager this,picoos_char * resourceName)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 
parse_resource_name(picoos_char * fileName)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 
readHeader(picorsrc_ResourceManager this,picoos_FileHeader header,picoos_uint32 * headerlen,picoos_File file)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 
picorsrc_createKnowledgeBase(picorsrc_ResourceManager this,picoos_uint8 * data,picoos_uint32 size,picoknow_kb_id_t kbid,picoknow_KnowledgeBase * kb)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 
picorsrc_releaseKnowledgeBase(picorsrc_ResourceManager this,picoknow_KnowledgeBase * kb)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 
picorsrc_getKbList(picorsrc_ResourceManager this,picoos_uint8 * data,picoos_uint32 datalen,picoknow_KnowledgeBase * kbList)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 
picorsrc_loadResource(picorsrc_ResourceManager this,picoos_char * fileName,picorsrc_Resource * resource)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 = (uintptr_t) 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 
picorsrc_releaseKbList(picorsrc_ResourceManager this,picoknow_KnowledgeBase * kbList)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) */
picorsrc_unloadResource(picorsrc_ResourceManager this,picorsrc_Resource * resource)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 
picorsrc_createDefaultResource(picorsrc_ResourceManager this)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 
picorsrc_rsrcGetName(picorsrc_Resource this,picoos_char * name,picoos_uint32 maxlen)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 
findVoiceDefinition(picorsrc_ResourceManager this,const picoos_char * voiceName,picorsrc_VoiceDefinition * vdef)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 
picorsrc_addResourceToVoiceDefinition(picorsrc_ResourceManager this,picoos_char * voiceName,picoos_char * resourceName)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 
picorsrc_createVoiceDefinition(picorsrc_ResourceManager this,picoos_char * voiceName)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 
picorsrc_releaseVoiceDefinition(picorsrc_ResourceManager this,picoos_char * voiceName)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 
picorsrc_createVoice(picorsrc_ResourceManager this,const picoos_char * voiceName,picorsrc_Voice * voice)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 
picorsrc_releaseVoice(picorsrc_ResourceManager this,picorsrc_Voice * voice)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