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