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 
18 #include "svox_ssml_parser.h"
19 #include <utils/Log.h>
20 #include <cutils/jstring.h>
21 #include <string.h>
22 #include <utils/String16.h>
23 
24 #define SSML_PITCH_XLOW     "50"
25 #define SSML_PITCH_LOW      "75"
26 #define SSML_PITCH_MEDIUM   "100"
27 #define SSML_PITCH_HIGH     "150"
28 #define SSML_PITCH_XHIGH    "200"
29 #define SSML_RATE_XSLOW     "30"
30 #define SSML_RATE_SLOW      "60"
31 #define SSML_RATE_MEDIUM    "100"
32 #define SSML_RATE_FAST      "250"
33 #define SSML_RATE_XFAST     "500"
34 #define SSML_VOLUME_SILENT  "0"
35 #define SSML_VOLUME_XLOW    "25"
36 #define SSML_VOLUME_LOW     "70"
37 #define SSML_VOLUME_MEDIUM  "120"
38 #define SSML_VOLUME_LOUD    "300"
39 #define SSML_VOLUME_XLOUD   "450"
40 #define SSML_BREAK_NONE     "0ms"
41 #define SSML_BREAK_XWEAK    "100ms"
42 #define SSML_BREAK_WEAK     "300ms"
43 #define SSML_BREAK_MEDIUM   "600ms"
44 #define SSML_BREAK_STRONG   "1s"
45 #define SSML_BREAK_XSTRONG  "3s"
46 
47 extern int cnvIpaToXsampa(const char16_t* ipaString, size_t ipaStringSize, char** outXsampaString);
48 extern char * createPhonemeString( const char * xsampa, int length );
49 
SvoxSsmlParser()50 SvoxSsmlParser::SvoxSsmlParser() : m_isInBreak(0), m_appendix(NULL), m_docLanguage(NULL)
51 {
52     mParser = XML_ParserCreate("UTF-8");
53     if (mParser)
54     {
55         XML_SetElementHandler(mParser, starttagHandler, endtagHandler);
56         XML_SetCharacterDataHandler(mParser, textHandler);
57         XML_SetUserData(mParser, (void*)this);
58         m_datasize = 512;
59         m_data = new char[m_datasize];
60         m_data[0] = '\0';
61     }
62 }
63 
~SvoxSsmlParser()64 SvoxSsmlParser::~SvoxSsmlParser()
65 {
66     if (mParser)
67         XML_ParserFree(mParser);
68     if (m_data)
69         delete [] m_data;
70     if (m_appendix)
71         delete [] m_appendix;
72     if (m_docLanguage)
73         delete [] m_docLanguage;
74 }
75 
initSuccessful()76 int SvoxSsmlParser::initSuccessful()
77 {
78     return (mParser && m_data);
79 }
80 
parseDocument(const char * ssmldoc,int isFinal)81 int SvoxSsmlParser::parseDocument(const char* ssmldoc, int isFinal)
82 {
83     int doclen = (int)strlen(ssmldoc) + 1;
84     int status = XML_Parse(mParser, ssmldoc, doclen, isFinal);
85     if (status == XML_STATUS_ERROR)
86     {
87         /* Note: for some reason Expat almost always complains about invalid tokens, even when document is well formed */
88         ALOGI("Parser error at line %d: %s\n", (int)XML_GetCurrentLineNumber(mParser), XML_ErrorString(XML_GetErrorCode(mParser)));
89     }
90     return status;
91 }
92 
getParsedDocument()93 char* SvoxSsmlParser::getParsedDocument()
94 {
95     return m_data;
96 }
97 
getParsedDocumentLanguage()98 char* SvoxSsmlParser::getParsedDocumentLanguage()
99 {
100     return m_docLanguage;
101 }
102 
starttagHandler(void * data,const XML_Char * element,const XML_Char ** attributes)103 void SvoxSsmlParser::starttagHandler(void* data, const XML_Char* element, const XML_Char** attributes)
104 {
105     ((SvoxSsmlParser*)data)->startElement(element, attributes);
106 }
107 
startElement(const XML_Char * element,const XML_Char ** attributes)108 void SvoxSsmlParser::startElement(const XML_Char* element, const XML_Char** attributes)
109 {
110     if (strcmp(element, "speak") == 0)
111     {
112         if (strlen(m_data) > 0)
113         {
114             /* we have old data, get rid of it and reallocate memory */
115             delete m_data;
116             m_data = NULL;
117             m_datasize = 512;
118             m_data = new char[m_datasize];
119             if (!m_data)
120             {
121                 ALOGE("Error: failed to allocate memory for string!\n");
122                 return;
123             }
124         }
125 
126         /* the only attribute supported in the speak tag is xml:lang, all others are ignored */
127         for (int i = 0; attributes[i]; i += 2)
128         {
129             if (strcmp(attributes[i], "xml:lang") == 0)
130             {
131                 if (!m_docLanguage)
132                 {
133                     m_docLanguage = new char[strlen(attributes[i+1])+1];
134                 }
135                 strcpy(m_docLanguage, attributes[i+1]);
136                 break;
137             }
138         }
139     }
140     else if (strcmp(element, "p") == 0) /* currently no attributes are supported for <p> */
141     {
142         if (strlen(m_data) + 4 > (size_t)m_datasize)
143         {
144             if (!growDataSize(100))
145             {
146                 ALOGE("Error: failed to allocate memory for string!\n");
147                 return;
148             }
149         }
150         strcat(m_data, "<p>");
151     }
152     else if (strcmp(element, "s") == 0) /* currently no attributes are supported for <s> */
153     {
154         if (strlen(m_data) + 4 > (size_t)m_datasize)
155         {
156             if (!growDataSize(100))
157             {
158                 ALOGE("Error: failed to allocate memory for string!\n");
159                 return;
160             }
161         }
162         strcat(m_data, "<s>");
163     }
164     else if (strcmp(element, "phoneme") == 0) /* only ipa and xsampa alphabets are supported */
165     {
166         int alpha = 1; /* set to 1 if alphabet is ipa */
167         int tagComplete = 0; /* set to 1 if phoneme tag has already been added */
168     char16_t* ph = NULL;
169         char* xsampastr = NULL;
170     size_t phsize = 0;
171     size_t xsampasize = 0;
172 
173         for (int i = 0; attributes[i]; i += 2)
174         {
175             if (strcmp(attributes[i], "alphabet") == 0)
176             {
177                 if (strcmp(attributes[i+1], "xsampa") == 0)
178                 {
179                     alpha = 0;
180                 }
181             }
182             if (strcmp(attributes[i], "ph") == 0)
183             {
184           ph = new char16_t[strlen8to16(attributes[i+1]) + 1];
185           ph = strdup8to16(attributes[i+1], &phsize);
186             }
187         }
188         if (!ph)
189         {
190             /* error, no phonetic string */
191             ALOGE("Error: bad SSML syntax, ph attribute not supplied.");
192             return;
193         }
194 
195         if (alpha)
196         {
197           /* need to convert phoneme string to xsampa */
198       xsampasize = cnvIpaToXsampa(ph, phsize, &xsampastr);
199       delete [] ph;
200       if (!xsampastr)
201             {
202                 ALOGE("Error: failed to allocate memory for IPA string conversion");
203                 return;
204             }
205         }
206         else
207         {
208       xsampastr = strndup16to8(ph, phsize);
209       xsampasize = strlen(xsampastr);
210           delete [] ph;
211         }
212 
213         /* split XSAMPA string into multiple phonemes if needed */
214         if (strstr(xsampastr, " ") || strstr(xsampastr, "#")) /* check again to see if we have multiple words */
215         {
216             char* phonstr = createPhonemeString(xsampastr, strlen(xsampastr) + 1);
217             free(xsampastr);
218             xsampastr = NULL;
219             xsampastr = (char*)malloc(strlen(phonstr) + 1);
220             strcpy(xsampastr, phonstr);
221             free(phonstr);
222             phonstr = NULL;
223             tagComplete = 1;
224         }
225 
226         if (tagComplete)
227         {
228             if (strlen(m_data) + strlen(xsampastr) + 1 > (size_t)m_datasize)
229             {
230                 if (!growDataSize(100))
231                 {
232                     ALOGE("Error: failed to allocate memory for string!");
233                     free(xsampastr);
234                     return;
235                 }
236             }
237         }
238         else
239         {
240             if (strlen(m_data) + strlen(xsampastr) + 17 > (size_t)m_datasize)
241             {
242                 if (!growDataSize(100))
243                 {
244                     ALOGE("Error: failed to allocate memory for string!");
245                     free(xsampastr);
246                     return;
247                 }
248             }
249             strcat(m_data, "<phoneme ph='");
250         }
251 
252         strcat(m_data, xsampastr);
253         free(xsampastr);
254 
255     if (!tagComplete)
256       {
257         if (strlen(m_data) + 4 > (size_t)m_datasize)
258           {
259         if (!growDataSize(100))
260           {
261             ALOGE("Error: failed to allocate memory for string!\n");
262             return;
263           }
264           }
265         strcat(m_data, "'/>");
266       }
267 
268         m_isInBreak = 1; /* set flag to indicate any text between open and close tag is to be discarded */
269     }
270     else if (strcmp(element, "break") == 0)
271     {
272         if (strlen(m_data) + 17 > (size_t)m_datasize)
273         {
274             if (!growDataSize(100))
275             {
276                 ALOGE("Error: failed to allocate memory for string!\n");
277                 return;
278             }
279         }
280         strcat(m_data, "<break time='");
281         char* time = NULL;
282 
283         for (int i = 0; attributes[i]; i += 2)
284         {
285             if (strcmp(attributes[i], "time") == 0)
286             {
287                 time = new char[strlen(attributes[i+1]) + 1];
288                 if (!time)
289                 {
290                     ALOGE("Error: failed to allocate memory for string!\n");
291                     return;
292                 }
293                 strcpy(time, attributes[i+1]);
294             }
295             else if (strcmp(attributes[i], "strength") == 0 && !time)
296             {
297                 time = convertBreakStrengthToTime(attributes[i+1]);
298             }
299         }
300         if (!time)
301         {
302             time = new char[6];
303             if (!time)
304             {
305                 ALOGE("Error: failed to allocate memory for string!\n");
306                 return;
307             }
308             strcpy(time, SSML_BREAK_WEAK); /* if no time or strength attributes are specified, default to weak break */
309         }
310         if (strlen(m_data) + strlen(time) + 4 > (size_t)m_datasize)
311         {
312             if (!growDataSize(100))
313             {
314                 ALOGE("Error: failed to allocate memory for string!\n");
315                 return;
316             }
317         }
318         strcat(m_data, time);
319         strcat(m_data, "'/>");
320         m_isInBreak = 1; /* set flag to indicate any text between open and close tag is to be discarded */
321     }
322     else if (strcmp(element, "prosody") == 0) /* only pitch, rate and volume attributes are supported */
323     {
324         for (int i = 0; attributes[i]; i += 2)
325         {
326             if (strcmp(attributes[i], "pitch") == 0)
327             {
328                 char* svoxpitch = convertToSvoxPitch(attributes[i+1]);
329                 if (!svoxpitch)
330                 {
331                     ALOGE("Error: failed to allocate memory for string!\n");
332                     return;
333                 }
334                 if (!svoxpitch)
335                 {
336                     svoxpitch = new char[4];
337                     if (!svoxpitch)
338                     {
339                         ALOGE("Error: failed to allocate memory for string!\n");
340                         return;
341                     }
342                     strcpy(svoxpitch, "100");
343                 }
344                 char* pitch = new char[17 + strlen(svoxpitch)];
345                 if (!pitch)
346                 {
347                     ALOGE("Error: failed to allocate memory for string!\n");
348                     return;
349                 }
350                 sprintf(pitch, "<pitch level='%s'>", svoxpitch);
351                 if (strlen(m_data) + strlen(pitch) + 1 > (size_t)m_datasize)
352                 {
353                     if (!growDataSize(100))
354                     {
355                         ALOGE("Error: failed to allocate memory for string!\n");
356                         return;
357                     }
358                 }
359                 strcat(m_data, pitch);
360                 if (!m_appendix)
361                 {
362                     m_appendix = new char[30];
363                     m_appendix[0] = '\0';
364                 }
365                 strcat(m_appendix, "</pitch>");
366                 delete [] svoxpitch;
367                 delete [] pitch;
368             }
369             else if (strcmp(attributes[i], "rate") == 0)
370             {
371                 char* svoxrate = convertToSvoxRate(attributes[i+1]);
372                 if (!svoxrate)
373                 {
374                     svoxrate = new char[4];
375                     if (!svoxrate)
376                     {
377                         ALOGE("Error: failed to allocate memory for string!\n");
378                         return;
379                     }
380                     strcpy(svoxrate, "100");
381                 }
382                 char* rate = new char[17 + strlen(svoxrate)];
383                 if (!rate)
384                 {
385                     ALOGE("Error: failed to allocate memory for string!\n");
386                     return;
387                 }
388                 sprintf(rate, "<speed level='%s'>", svoxrate);
389                 if (strlen(m_data) + strlen(rate) + 1 > (size_t)m_datasize)
390                 {
391                     if (!growDataSize(100))
392                     {
393                         ALOGE("Error: failed to allocate memory for string!\n");
394                         return;
395                     }
396                 }
397                 strcat(m_data, rate);
398                 if (!m_appendix)
399                 {
400                     m_appendix = new char[30];
401                     if (!m_appendix)
402                     {
403                         ALOGE("Error: failed to allocate memory for string!\n");
404                         return;
405                     }
406                     m_appendix[0] = '\0';
407                 }
408                 strcat(m_appendix, "</speed>");
409                 delete [] svoxrate;
410                 delete [] rate;
411             }
412             else if (strcmp(attributes[i], "volume") == 0)
413             {
414                 char* svoxvol = convertToSvoxVolume(attributes[i+1]);
415                 if (!svoxvol)
416                 {
417                     svoxvol = new char[4];
418                     if (!svoxvol)
419                     {
420                         ALOGE("Error: failed to allocate memory for string!\n");
421                         return;
422                     }
423                     strcpy(svoxvol, "100");
424                 }
425                 char* volume = new char[18 + strlen(svoxvol)];
426                 if (!volume)
427                 {
428                     ALOGE("Error: failed to allocate memory for string!\n");
429                     return;
430                 }
431                 sprintf(volume, "<volume level='%s'>", svoxvol);
432                 if (strlen(m_data) + strlen(volume) + 1 > (size_t)m_datasize)
433                 {
434                     if (!growDataSize(100))
435                     {
436                         ALOGE("Error: failed to allocate memory for string!\n");
437                         return;
438                     }
439                 }
440                 strcat(m_data, volume);
441                 if (!m_appendix)
442                 {
443                     m_appendix = new char[30];
444                     m_appendix[0] = '\0';
445                 }
446                 strcat(m_appendix, "</volume>");
447                 delete [] svoxvol;
448                 delete [] volume;
449             }
450         }
451     }
452     else if (strcmp(element, "audio") == 0) /* only 16kHz 16bit wav files are supported as src */
453     {
454         if (strlen(m_data) + 17 > (size_t)m_datasize)
455         {
456             if (!growDataSize(100))
457             {
458                 ALOGE("Error: failed to allocate memory for string!\n");
459                 return;
460             }
461         }
462         strcat(m_data, "<usesig file='");
463 
464         for (int i = 0; attributes[i]; i += 2)
465         {
466             if (strcmp(attributes[i], "src") == 0)
467             {
468                 if (strlen(m_data) + strlen(attributes[i+1]) + 1 > (size_t)m_datasize)
469                 {
470                     if (!growDataSize(100))
471                     {
472                         ALOGE("Error: failed to allocate memory for string!\n");
473                         return;
474                     }
475                 }
476                 strcat(m_data, attributes[i+1]);
477             }
478         }
479         strcat(m_data, "'>");
480     }
481 }
482 
endtagHandler(void * data,const XML_Char * element)483 void SvoxSsmlParser::endtagHandler(void* data, const XML_Char* element)
484 {
485     ((SvoxSsmlParser*)data)->endElement(element);
486 }
487 
endElement(const XML_Char * element)488 void SvoxSsmlParser::endElement(const XML_Char* element)
489 {
490     if (strcmp(element, "speak") == 0)
491     {
492       /* do nothing */
493     }
494     else if (strcmp(element, "p") == 0)
495     {
496         if (strlen(m_data) + 5 > (size_t)m_datasize)
497         {
498             if (!growDataSize(100))
499             {
500                 ALOGE("Error: failed to allocate memory for string!\n");
501                 return;
502             }
503         }
504         strcat(m_data, "</p>");
505     }
506     else if (strcmp(element, "s") == 0)
507     {
508         if (strlen(m_data) + 5 > (size_t)m_datasize)
509         {
510             if (!growDataSize(100))
511             {
512                 ALOGE("Error: failed to allocate memory for string!\n");
513                 return;
514             }
515         }
516         strcat(m_data, "</s>");
517     }
518     else if (strcmp(element, "phoneme") == 0)
519     {
520         m_isInBreak = 0; /* indicate we are no longer in phoneme tag */
521     }
522     else if (strcmp(element, "break") == 0)
523     {
524         m_isInBreak = 0; /* indicate we are no longer in break tag */
525     }
526     else if (strcmp(element, "prosody") == 0)
527     {
528         if (m_appendix)
529         {
530             if (strlen(m_data) + strlen(m_appendix) + 1 > (size_t)m_datasize)
531             {
532                 if (!growDataSize(100))
533                 {
534                     ALOGE("Error: failed to allocate memory for string!\n");
535                     return;
536                 }
537             }
538             strcat(m_data, m_appendix);
539             delete [] m_appendix;
540             m_appendix = NULL;
541         }
542     }
543     else if (strcmp(element, "audio") == 0)
544     {
545         if (strlen(m_data) + 10 > (size_t)m_datasize)
546         {
547             if (!growDataSize(100))
548             {
549                 ALOGE("Error: failed to allocate memory for string!\n");
550                 return;
551             }
552         }
553         strcat(m_data, "</usesig>");
554     }
555 }
556 
textHandler(void * data,const XML_Char * text,int length)557 void SvoxSsmlParser::textHandler(void* data, const XML_Char* text, int length)
558 {
559     ((SvoxSsmlParser*)data)->textElement(text, length);
560 }
561 
textElement(const XML_Char * text,int length)562 void SvoxSsmlParser::textElement(const XML_Char* text, int length)
563 {
564     if (m_isInBreak)
565     {
566         return; /* handles the case when someone has added text inside the break or phoneme tag - this text is thrown away */
567     }
568 
569     char* content = new char[length + 1];
570     if (!content)
571     {
572         ALOGE("Error: failed to allocate memory for string!\n");
573         return;
574     }
575     strncpy(content, text, length);
576     content[length] = '\0';
577 
578     if (strlen(m_data) + strlen(content) + 1 > (size_t)m_datasize)
579     {
580         if (!growDataSize(100))
581         {
582             ALOGE("Error: failed to allocate memory for string!\n");
583             return;
584         }
585     }
586     strcat(m_data, content);
587     delete [] content;
588 }
589 
590 /**
591 convertToSvoxPitch
592 Converts SSML pitch labels to SVOX pitch levels
593 */
convertToSvoxPitch(const char * value)594 char* SvoxSsmlParser::convertToSvoxPitch(const char* value)
595 {
596     char* converted = NULL;
597     if (strcmp(value, "x-low") == 0)
598     {
599         converted = new char[4];
600         if (!converted)
601         {
602             ALOGE("Error: failed to allocate memory for string!\n");
603             return NULL;
604         }
605         strcpy(converted, SSML_PITCH_XLOW);
606     }
607     else if (strcmp(value, "low") == 0)
608     {
609         converted = new char[4];
610         if (!converted)
611         {
612             ALOGE("Error: failed to allocate memory for string!\n");
613             return NULL;
614         }
615         strcpy(converted, SSML_PITCH_LOW);
616     }
617     else if (strcmp(value, "medium") == 0)
618     {
619         converted = new char[4];
620         if (!converted)
621         {
622             ALOGE("Error: failed to allocate memory for string!\n");
623             return NULL;
624         }
625         strcpy(converted, SSML_PITCH_MEDIUM);
626     }
627     else if (strcmp(value, "default") == 0)
628     {
629         converted = new char[4];
630         if (!converted)
631         {
632             ALOGE("Error: failed to allocate memory for string!\n");
633             return NULL;
634         }
635         strcpy(converted, SSML_PITCH_MEDIUM);
636     }
637     else if (strcmp(value, "high") == 0)
638     {
639         converted = new char[4];
640         if (!converted)
641         {
642             ALOGE("Error: failed to allocate memory for string!\n");
643             return NULL;
644         }
645         strcpy(converted, SSML_PITCH_HIGH);
646     }
647     else if (strcmp(value, "x-high") == 0)
648     {
649         converted = new char[4];
650         if (!converted)
651         {
652             ALOGE("Error: failed to allocate memory for string!\n");
653             return NULL;
654         }
655         strcpy(converted, SSML_PITCH_XHIGH);
656     }
657     return converted;
658 }
659 
660 /**
661     convertToSvoxRate
662     Converts SSML rate labels to SVOX speed levels
663 */
convertToSvoxRate(const char * value)664 char* SvoxSsmlParser::convertToSvoxRate(const char* value)
665 {
666     char* converted = NULL;
667     if (strcmp(value, "x-slow") == 0)
668     {
669         converted = new char[4];
670         if (!converted)
671         {
672             ALOGE("Error: failed to allocate memory for string!\n");
673             return NULL;
674         }
675         strcpy(converted, SSML_RATE_XSLOW);
676     }
677     else if (strcmp(value, "slow") == 0)
678     {
679         converted = new char[4];
680         if (!converted)
681         {
682             ALOGE("Error: failed to allocate memory for string!\n");
683             return NULL;
684         }
685         strcpy(converted, SSML_RATE_SLOW);
686     }
687     else if (strcmp(value, "medium") == 0)
688     {
689         converted = new char[4];
690         if (!converted)
691         {
692             ALOGE("Error: failed to allocate memory for string!\n");
693             return NULL;
694         }
695         strcpy(converted, SSML_RATE_MEDIUM);
696     }
697     else if (strcmp(value, "default") == 0)
698     {
699         converted = new char[4];
700         if (!converted)
701         {
702             ALOGE("Error: failed to allocate memory for string!\n");
703             return NULL;
704         }
705         strcpy(converted, SSML_RATE_MEDIUM);
706     }
707     else if (strcmp(value, "fast") == 0)
708     {
709         converted = new char[4];
710         if (!converted)
711         {
712             ALOGE("Error: failed to allocate memory for string!\n");
713             return NULL;
714         }
715         strcpy(converted, SSML_RATE_FAST);
716     }
717     else if (strcmp(value, "x-fast") == 0)
718     {
719         converted = new char[4];
720         if (!converted)
721         {
722             ALOGE("Error: failed to allocate memory for string!\n");
723             return NULL;
724         }
725         strcpy(converted, SSML_RATE_XFAST);
726     }
727     return converted;
728 }
729 
730 /**
731 convertToSvoxVolume
732 Converts SSML volume labels to SVOX volume levels
733 */
convertToSvoxVolume(const char * value)734 char* SvoxSsmlParser::convertToSvoxVolume(const char* value)
735 {
736     char* converted = NULL;
737     if (strcmp(value, "silent") == 0)
738     {
739         converted = new char[4];
740         if (!converted)
741         {
742             ALOGE("Error: failed to allocate memory for string!\n");
743             return NULL;
744         }
745         strcpy(converted, SSML_VOLUME_SILENT);
746     }
747     else if (strcmp(value, "x-low") == 0)
748     {
749         converted = new char[4];
750         if (!converted)
751         {
752             ALOGE("Error: failed to allocate memory for string!\n");
753             return NULL;
754         }
755         strcpy(converted, SSML_VOLUME_XLOW);
756     }
757     else if (strcmp(value, "low") == 0)
758     {
759         converted = new char[4];
760         if (!converted)
761         {
762             ALOGE("Error: failed to allocate memory for string!\n");
763             return NULL;
764         }
765         strcpy(converted, SSML_VOLUME_LOW);
766     }
767     else if (strcmp(value, "medium") == 0)
768     {
769         converted = new char[4];
770         if (!converted)
771         {
772             ALOGE("Error: failed to allocate memory for string!\n");
773             return NULL;
774         }
775         strcpy(converted, SSML_VOLUME_MEDIUM);
776     }
777     else if (strcmp(value, "default") == 0)
778     {
779         converted = new char[4];
780         if (!converted)
781         {
782             ALOGE("Error: failed to allocate memory for string!\n");
783             return NULL;
784         }
785         strcpy(converted, SSML_VOLUME_MEDIUM);
786     }
787     else if (strcmp(value, "loud") == 0)
788     {
789         converted = new char[4];
790         if (!converted)
791         {
792             ALOGE("Error: failed to allocate memory for string!\n");
793             return NULL;
794         }
795         strcpy(converted, SSML_VOLUME_LOUD);
796     }
797     else if (strcmp(value, "x-loud") == 0)
798     {
799         converted = new char[4];
800         if (!converted)
801         {
802             ALOGE("Error: failed to allocate memory for string!\n");
803             return NULL;
804         }
805         strcpy(converted, SSML_VOLUME_XLOUD);
806     }
807     return converted;
808 }
809 
810 /**
811 convertBreakStrengthToTime
812 Converts SSML break strength labels to SVOX break time
813 */
convertBreakStrengthToTime(const char * value)814 char* SvoxSsmlParser::convertBreakStrengthToTime(const char* value)
815 {
816     char* converted = NULL;
817     if (strcmp(value, "none") == 0)
818     {
819         converted = new char[6];
820         if (!converted)
821         {
822             ALOGE("Error: failed to allocate memory for string!\n");
823             return NULL;
824         }
825         strcpy(converted, SSML_BREAK_NONE);
826     }
827     else if (strcmp(value, "x-weak") == 0)
828     {
829         converted = new char[6];
830         if (!converted)
831         {
832             ALOGE("Error: failed to allocate memory for string!\n");
833             return NULL;
834         }
835         strcpy(converted, SSML_BREAK_XWEAK);
836     }
837     else if (strcmp(value, "weak") == 0)
838     {
839         converted = new char[6];
840         if (!converted)
841         {
842             ALOGE("Error: failed to allocate memory for string!\n");
843             return NULL;
844         }
845         strcpy(converted, SSML_BREAK_WEAK);
846     }
847     else if (strcmp(value, "medium") == 0)
848     {
849         converted = new char[6];
850         if (!converted)
851         {
852             ALOGE("Error: failed to allocate memory for string!\n");
853             return NULL;
854         }
855         strcpy(converted, SSML_BREAK_MEDIUM);
856     }
857     else if (strcmp(value, "strong") == 0)
858     {
859         converted = new char[6];
860         if (!converted)
861         {
862             ALOGE("Error: failed to allocate memory for string!\n");
863             return NULL;
864         }
865         strcpy(converted, SSML_BREAK_STRONG);
866     }
867     else if (strcmp(value, "x-strong") == 0)
868     {
869         converted = new char[6];
870         if (!converted)
871         {
872             ALOGE("Error: failed to allocate memory for string!\n");
873             return NULL;
874         }
875         strcpy(converted, SSML_BREAK_XSTRONG);
876     }
877     return converted;
878 }
879 
880 /**
881 growDataSize
882 Increases the size of the internal text storage member
883 */
growDataSize(int sizeToGrow)884 int SvoxSsmlParser::growDataSize(int sizeToGrow)
885 {
886     char* tmp = new char[m_datasize];
887     if (!tmp)
888         return 0;
889 
890     strcpy(tmp, m_data);
891     delete [] m_data;
892     m_data = NULL;
893     m_data = new char[m_datasize + sizeToGrow];
894     if (!m_data)
895     {
896         m_data = tmp;
897         return 0;
898     }
899     m_datasize += sizeToGrow;
900     strcpy(m_data, tmp);
901     delete [] tmp;
902     tmp = NULL;
903     return 1;
904 }
905