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 */
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 = (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
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