VXIrec_utils.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:36k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. #include <iostream>
  23. #include <sstream>
  24. #include <VXIvalue.h>
  25. #include <VXItrd.h>
  26. #include "VXIrec_utils.h"
  27. #include "XMLChConverter.hpp"
  28. #include "LogBlock.hpp"
  29. VXIunsigned VXIrecData::diagLogBase = 0;
  30. /* Avoid locale dependant ctype.h macros */
  31. static inline bool VXIrecIsSpace(const wchar_t c)
  32. {
  33.   return (((c == L' ') || (c == L't') || (c == L'n') || (c == L'r')) ?
  34.           true : false);
  35. }
  36. /******************************************
  37.  * VXIrecWordList : A list of words
  38.  ******************************************/
  39. class VXIrecWordList : public VXIrecGrammar {
  40. public:
  41.   enum GTYPE {
  42.     GTYPE_NONE,
  43.     GTYPE_DTMF,
  44.     GTYPE_SPEECH
  45.   };
  46.   GRAMMARINFOLIST * grammarInfoList;
  47.   bool enabled;
  48.   GTYPE gtype;
  49. public:
  50. public: // VXIrecGrammar fuctions...
  51.   virtual void SetEnabled(bool e)    { enabled = e;    }
  52.   virtual bool IsEnabled() const     { return enabled; }
  53.   virtual GRAMMARINFOLIST * GetGrammarInfoList() const { return grammarInfoList; }
  54.   virtual bool GetGrammarInfo(const VXIchar* input,
  55.                               VXIrecGrammarInfo ** gramInfo) const;
  56.   virtual bool IsDtmf() const { return gtype == GTYPE_DTMF; }
  57. public:
  58.   VXIrecWordList();
  59.   virtual ~VXIrecWordList();
  60. };
  61. VXIrecWordList::VXIrecWordList()
  62.   : enabled(false), gtype(VXIrecWordList::GTYPE_NONE), grammarInfoList(NULL)
  63. { }
  64. VXIrecWordList::~VXIrecWordList()
  65. {
  66.   delete grammarInfoList;
  67. }
  68. bool VXIrecWordList::GetGrammarInfo(const VXIchar* input,
  69.                                     VXIrecGrammarInfo ** gramInfo) const
  70. {
  71.   for( GRAMMARINFOLIST::iterator i = grammarInfoList->begin();
  72.        i != grammarInfoList->end(); ++i ) {
  73.     if( input == (*i).word ) {
  74.       *gramInfo = &(*i);
  75.       return true;
  76.     }
  77.   }
  78.   return false;
  79. }
  80. /******************************************
  81.  * GrammarSaxHandler : The grammar sax parser
  82.  ******************************************/
  83. //////////////////////////////////////////////////////
  84. static VXItrdMutex* gblMutex = NULL;
  85. static VXIunsigned  gblDiagBase = 0;
  86. static VXIlogInterface* gblLog = NULL;
  87. static VXIulong GRAM_ROOT_COUNTER = 0;
  88. static const VXIchar * const GRAM_ROOT_PREFIX  = L"_GRAMROOT_";
  89. // recursively replace all occurence of sstr with rstr
  90. static vxistring::size_type ReplaceChar(vxistring &modstr,
  91.                                         const vxistring &sstr,
  92.                                         const vxistring &rstr,
  93.                                         vxistring::size_type pos0)
  94. {
  95.   vxistring::size_type pos1;
  96.   pos1 = modstr.find(sstr, pos0);
  97.   if (pos1 == vxistring::npos) return pos1;
  98.   modstr.replace(pos1, sstr.length(), rstr);
  99.   return ReplaceChar(modstr, sstr, rstr, pos1 + rstr.length());
  100. }
  101. static void FixEscapeChar(vxistring & modstr)
  102. {
  103.   vxistring::size_type pos0 = 0;
  104.   vxistring a_sym[6] = { L"&amp;", L"&lt;", L"&gt;", L"&", L"<", L">" };
  105.   vxistring r_sym[6] = { L"and", L"less than", L"greater than", L"and", L"less than", L"greater than" };
  106.   for (int i = 0; i < 6; i++)
  107.     ReplaceChar(modstr, a_sym[i], r_sym[i], 0);
  108. }
  109. static void PruneWhitespace(vxistring & str)
  110. {
  111.   vxistring::size_type len = str.length();
  112.   if (len == 0) return;
  113.   // Convert all whitespace to spaces.
  114.   unsigned int i;
  115.   for (i = 0; i < len; ++i)
  116.     if (str[i] == 'r' || str[i] == 'n' || str[i] == 't')  str[i] = ' ';
  117.   // Eliminate trailing and double spaces
  118.   bool lastWasSpace = true;
  119.   for (i = len; i > 0; --i) {
  120.     if (str[i-1] != ' ') {
  121.       lastWasSpace = false;
  122.       continue;
  123.     }
  124.     if (lastWasSpace)
  125.       str.erase(i-1, 1);
  126.     else
  127.       lastWasSpace = true;
  128.   }
  129.   // Eliminate space at very beginning.
  130.   if (str[0] == ' ') str.erase(0, 1);
  131. }
  132. GrammarSaxHandler::GrammarSaxHandler(VXIlogInterface *l)
  133. : log(l), grammarInfoList(NULL), processTag(false),
  134.   nodeType(UNKNOWN_NODE), isDTMFGram(false)
  135. {
  136. }
  137. GrammarSaxHandler::~GrammarSaxHandler()
  138. {
  139. }
  140. void GrammarSaxHandler::startElement(const XMLCh* const name,
  141.                                      AttributeList& attributes)
  142. {
  143.   const VXIchar* fnname = L"startElement";
  144.   LogBlock logger(log, VXIrecData::diagLogBase, fnname, VXIREC_MODULE);
  145.   
  146.   XMLChToVXIchar gName(name);
  147.   logger.logDiag(DIAG_TAG_PARSE, L"%s%s", L"Element: ", gName.c_str());   
  148.   
  149.   // Show attributes
  150.   if( logger.isEnabled(VXIrecData::diagLogBase+DIAG_TAG_PARSE) )
  151.   {
  152.     for(unsigned int i = 0; i < attributes.getLength(); i++)
  153.     {
  154.       XMLChToVXIchar gAttr(attributes.getName(i));
  155.       XMLChToVXIchar gAttrVal(attributes.getValue(i));
  156.       logger.logDiag(DIAG_TAG_PARSE, L"%s%s%s", gAttr.c_str(), 
  157.                      L" = ", gAttrVal.c_str());
  158.     }
  159.   }
  160.   
  161.   if( wcscmp(GRAMMAR, gName.c_str()) == 0 ) {
  162.     nodeType = GRAMMAR_NODE;    
  163.     // Retrieve grammar attributes
  164.     for(unsigned int i = 0; i < attributes.getLength(); i++)
  165.     {
  166.       XMLChToVXIchar gAttr(attributes.getName(i));
  167.       XMLChToVXIchar gAttrVal(attributes.getValue(i));
  168.       // Got DTMF grammar
  169.       if( wcscmp(L"mode", gAttr.c_str()) == 0 &&
  170.           wcscmp(L"dtmf", gAttrVal.c_str()) == 0 ) 
  171.       {
  172.         isDTMFGram = true;    
  173.       }
  174.     }
  175.   }
  176.   else if( wcscmp(ITEM, gName.c_str()) == 0 ) {
  177.     // <item>
  178.     nodeType = ITEM_NODE;
  179.   }
  180.   else if( wcscmp(TAG, gName.c_str()) == 0 ) {
  181.     // <tag>
  182.     nodeType = ITEM_NODE;
  183.     processTag = true;
  184.   }
  185.   else if( wcscmp(META, gName.c_str()) == 0 ) {
  186.     // <meta>
  187.     nodeType = META_NODE;
  188.     // Retrieve semantic interpretation
  189.     for(unsigned int i = 0; i < attributes.getLength(); i++)
  190.     {
  191.       XMLChToVXIchar gAttr(attributes.getName(i));
  192.       if( wcscmp(NAME, gAttr.c_str()) == 0 )
  193.       {
  194.         XMLChToVXIchar gAttrVal(attributes.getValue(i));
  195.         if( wcscmp(L"swirec_simple_result_key", gAttrVal.c_str()) )
  196.           break; // only know how to process SSFT's semantic interp.
  197.       }
  198.       else if( wcscmp(CONTENT, gAttr.c_str()) == 0 ) {
  199.         // Copy the semantic meaning
  200.         grammarInfo.semantic = XMLChToVXIchar(attributes.getValue(i)).c_str();
  201.       }
  202.     }
  203.   }
  204. }
  205. void GrammarSaxHandler::characters(const XMLCh* const chars,
  206.                                    const unsigned int length)
  207. {
  208.   const VXIchar* fnname = L"characters";
  209.   LogBlock logger(log, VXIrecData::diagLogBase, fnname, VXIREC_MODULE);
  210.   XMLChToVXIchar gChars(chars);
  211.   logger.logDiag(DIAG_TAG_PARSE, L"%s", gChars.c_str());
  212.   
  213.   switch( nodeType ) {
  214.     case ITEM_NODE: {
  215.       if( processTag ) {
  216.         grammarInfo.tag = gChars.c_str();
  217.       }
  218.       else grammarInfo.word = gChars.c_str();
  219.     } break;
  220.   }
  221. }
  222. void GrammarSaxHandler::endElement(const XMLCh* const name)
  223. {
  224.   const VXIchar* fnname = L"endElement";
  225.   LogBlock logger(log, VXIrecData::diagLogBase, fnname, VXIREC_MODULE);
  226.   XMLChToVXIchar gName(name);
  227.   if( wcscmp(ITEM, gName.c_str()) == 0 ) {
  228.     // <item>
  229.     // prune white spaces
  230.     PruneWhitespace(grammarInfo.word);
  231.     PruneWhitespace(grammarInfo.tag);
  232.     PruneWhitespace(grammarInfo.semantic);
  233.     logger.logDiag(DIAG_TAG_PARSE, L"%s%s%s%s%s%s", 
  234.              L"word: ", grammarInfo.word.c_str(),
  235.              L", tag: ", grammarInfo.tag.c_str(),
  236.              L", semantic: ", grammarInfo.semantic.c_str());
  237.     // store this item
  238.     grammarInfoList->push_back(grammarInfo);
  239.     // clear this item for next processing
  240.     grammarInfo.tag = L"";
  241.     grammarInfo.word = L"";
  242.     // don't clear the semantic, it will remain the same for the rest of grammar
  243.   }
  244.   else if( wcscmp(TAG, gName.c_str()) == 0 ) {
  245.     // <tag>
  246.     processTag = false;
  247.   }
  248. }
  249. void GrammarSaxHandler::processError(const SAXParseException& exception,
  250.                                 const VXIchar* errType)
  251. {
  252.   LogError(352, L"%s%s%s%s%s%s%s%u%s%u",
  253.            L"errType", errType,
  254.            L"errMsg", XMLChToVXIchar(exception.getMessage()).c_str(),
  255.            L"file", XMLChToVXIchar(exception.getSystemId()).c_str(),
  256.            L"line", exception.getLineNumber(),
  257.            L"column", exception.getColumnNumber());
  258. }
  259. VXIlogResult GrammarSaxHandler::LogError(VXIunsigned errorID,
  260.                                const VXIchar *format, ...) const
  261. {
  262.   VXIlogResult rc;
  263.   va_list args;
  264.   if (!log)
  265.     return VXIlog_RESULT_NON_FATAL_ERROR;
  266.   if (format) {
  267.     va_start(args, format);
  268.     rc = (*log->VError)(log, COMPANY_DOMAIN L".VXIrec", errorID, format, args);
  269.     va_end(args);
  270.   } else {
  271.     rc = (*log->Error)(log, COMPANY_DOMAIN L".VXIrec", errorID, NULL);
  272.   }
  273.   return rc;
  274. }
  275. VXIlogResult GrammarSaxHandler::LogDiag(VXIunsigned offset, const VXIchar *subtag,
  276.                               const VXIchar *format, ...) const
  277. {
  278.   VXIlogResult rc;
  279.   va_list args;
  280.   VXIunsigned tag = offset + VXIrecData::diagLogBase;
  281.   if (!log)
  282.     return VXIlog_RESULT_NON_FATAL_ERROR;
  283.   if (format) {
  284.     va_start(args, format);
  285.     rc = (*log->VDiagnostic)(log, tag, subtag, format, args);
  286.     va_end(args);
  287.   } else {
  288.     rc = (*log->Diagnostic)(log, tag, subtag, NULL);
  289.   }
  290.   return rc;
  291. }
  292. /******************************************
  293.  * VXIrecData : The grammar container
  294.  ******************************************/
  295. // Initialize & Shutdown
  296. int VXIrecData::Initialize(VXIlogInterface* log, VXIunsigned diagBase)
  297. {
  298.   gblLog = log;
  299.   gblDiagBase = diagBase;
  300.   diagLogBase = diagBase;
  301.   if( gblMutex == NULL ) {
  302.     VXItrdMutexCreate(&gblMutex);
  303.   }
  304.   // Initialize the SAX parser
  305.   try {
  306.     XMLPlatformUtils::Initialize();
  307.   }
  308.   catch (const XMLException& exception) {
  309.     log->Error(log, L".VXIrec", 353, L"%s%s",
  310.                L"grammar parser exception",
  311.                XMLChToVXIchar(exception.getMessage()).c_str());
  312.     return VXIlog_RESULT_FAILURE;
  313.   }
  314.   return 0;
  315. }
  316. int VXIrecData::ShutDown()
  317. {
  318.   if( gblMutex != NULL ) {
  319.     VXItrdMutexDestroy(&gblMutex);
  320.     gblMutex = NULL;
  321.   }
  322.   try {
  323.     XMLPlatformUtils::Terminate();
  324.   }
  325.   catch (const XMLException &) {
  326.     // do nothing
  327.   }
  328.   return 0;
  329. }
  330. // C'ctor
  331. VXIrecData::VXIrecData(VXIlogInterface *l,
  332.            VXIinetInterface *i)
  333. : log(l), inet(i), grammars(), 
  334.   parser(NULL), xmlHandler(NULL)
  335. {
  336.   parser = new SAXParser();
  337.   parser->setDoValidation(false);
  338.   parser->setDoNamespaces(false);
  339.   // Register our own handler class (callback)
  340.   xmlHandler = new GrammarSaxHandler(l);
  341.   ErrorHandler* errHandler = (ErrorHandler*) xmlHandler;
  342.   parser->setDocumentHandler((DocumentHandler *)xmlHandler);
  343.   parser->setErrorHandler(errHandler);
  344. }
  345. // D'ctor
  346. VXIrecData::~VXIrecData()
  347. {
  348.   if( !grammars.empty() )
  349.     for (GRAMMARS::iterator i = grammars.begin(); i != grammars.end(); ++i)
  350.       delete *i;
  351.   if (parser) delete parser;
  352.   if (xmlHandler) delete xmlHandler;
  353. }
  354. void VXIrecData::ShowPropertyValue(const VXIchar *key,
  355.            const VXIValue *value, VXIunsigned PROP_TAG)
  356. {
  357.   VXIchar subtag[512] = L"Property";
  358.   if( value == 0 ) return;
  359.   VXIvalueType type = VXIValueGetType(value);
  360.   {
  361.     switch( type )
  362.     {
  363.       case VALUE_INTEGER:
  364.         wcscpy(subtag, L"Property:INT");
  365.         LogDiag(PROP_TAG, subtag, 
  366.              L"%s=%d", key, VXIIntegerValue((const VXIInteger*)value));
  367.         break;
  368.       case VALUE_FLOAT:
  369.         wcscpy(subtag, L"Property:FLT");
  370.         LogDiag(PROP_TAG, subtag, 
  371.              L"%s=%f", key, VXIFloatValue((const VXIFloat*)value));
  372.         break;
  373.       case VALUE_BOOLEAN:     
  374.         wcscpy(subtag, L"Property:BOOL");
  375.         LogDiag(PROP_TAG, subtag, 
  376.              L"%s=%d", key, VXIBooleanValue((const VXIBoolean*)value));
  377.         break;
  378.       case VALUE_STRING:
  379.         wcscpy(subtag, L"Property:STR");
  380.         LogDiag(PROP_TAG, subtag, 
  381.              L"%s=%s", key, VXIStringCStr((const VXIString*)value));
  382.         break;
  383.       case VALUE_PTR:
  384.         wcscpy(subtag, L"Property:PTR");
  385.         LogDiag(PROP_TAG, subtag, 
  386.              L"%s(ptr)=0x%p", key, VXIPtrValue((const VXIPtr*)value));
  387.         break;
  388.       case VALUE_CONTENT:
  389.         wcscpy(subtag, L"Property:CNT");
  390.         LogDiag(PROP_TAG, subtag, 
  391.              L"%s(content)=0x%p", key, value);
  392.         break;
  393.       case VALUE_MAP:
  394.         {
  395.           VXIchar endtag[512];
  396.           const VXIchar *mykey = key ? key : L"NULL";
  397.           wcscpy(subtag, L"Property:MAP:BEG");
  398.           wcscpy(endtag, L"Property:MAP:END");
  399.           LogDiag(PROP_TAG, subtag, L"%s", mykey);
  400.           const VXIchar *key = NULL;
  401.           const VXIValue *gvalue = NULL;
  402.           VXIMapIterator *it = VXIMapGetFirstProperty((const VXIMap*)value, &key, &gvalue);
  403.           int ret = 0;
  404.           while( ret == 0 && key && gvalue )
  405.           {
  406.             ShowPropertyValue(key, gvalue, PROP_TAG);
  407.             ret = VXIMapGetNextProperty(it, &key, &gvalue);
  408.           }
  409.           VXIMapIteratorDestroy(&it);         
  410.           LogDiag(PROP_TAG, endtag, L"%s", mykey);
  411.         }   
  412.         break;
  413.       case VALUE_VECTOR:
  414.         {
  415.           VXIunsigned vlen = VXIVectorLength((const VXIVector*)value);
  416.           for(VXIunsigned i = 0; i < vlen; ++i)
  417.           {
  418.             const VXIValue *gvalue = VXIVectorGetElement((const VXIVector*)value, i);
  419.             ShowPropertyValue(L"Vector", gvalue, PROP_TAG);
  420.           }
  421.         }
  422.         break;
  423.       default:
  424.         LogDiag(PROP_TAG, subtag, L"%s=%s", key, L"UNKOWN");
  425.     }          
  426.   }
  427.   return;
  428. }
  429. void VXIrecData::ShowPropertyValue(const VXIMap *properties)
  430. {
  431.   const VXIchar *key = NULL;
  432.   const VXIValue *gvalue = NULL;
  433.   const VXIunsigned PROP_TAG = DIAG_TAG_PROPERTY;
  434.   if( log && (log->DiagnosticIsEnabled(log, diagLogBase+PROP_TAG) == TRUE) 
  435.       && properties ) 
  436.   {
  437.     VXIMapIterator *it = VXIMapGetFirstProperty(properties, &key, &gvalue);
  438.     int ret = 0;
  439.     while( ret == 0 && key && gvalue )
  440.     {
  441.       ShowPropertyValue(key, gvalue, PROP_TAG);
  442.       ret = VXIMapGetNextProperty(it, &key, &gvalue);
  443.     }
  444.     VXIMapIteratorDestroy(&it);     
  445.   }
  446.   return;
  447. }
  448. // Pasre SRGS grammar
  449. // NOTES: re-parse the same grammar seems to be slow, optimization is welcome!
  450. //
  451. VXIrecGrammar * VXIrecData::ParseSRGSGrammar(const vxistring & srgsgram, 
  452.                                              const VXIMap    * properties,
  453.                                              bool isdtmf)
  454. {
  455.   const VXIchar* fnname = L"ParseSRGSGrammar";
  456.   LogBlock logger(log, VXIrecData::diagLogBase, fnname, VXIREC_MODULE);
  457.   VXIrecWordList * newGrammarPtr = new VXIrecWordList();
  458.   
  459.   try {
  460.     xmlHandler->CreateGrammarInfoList();
  461.     const VXIbyte* buffer = reinterpret_cast<const VXIbyte*>(srgsgram.c_str());
  462.     VXIulong bufSize = srgsgram.length() * sizeof(VXIchar) / sizeof(VXIbyte);
  463.     MemBufInputSource membuf(buffer, bufSize, "SRGSGRAM", false);
  464.     parser->parse(membuf);
  465.   }
  466.   catch (const XMLException & exception) {
  467.     LogError(352, L"%s%s", L"Parse Error", XMLChToVXIchar(exception.getMessage()).c_str());
  468.     xmlHandler->DestroyGrammarInfoList();
  469.     delete newGrammarPtr;
  470.     return NULL;
  471.   }
  472.   catch (const SAXParseException & exception) {
  473.     LogError(353, L"%s%s%s%d%s%d%s%s",
  474.              L"ID", XMLChToVXIchar(exception.getSystemId()).c_str(),
  475.              L"line", exception.getLineNumber(),
  476.              L"col", exception.getColumnNumber(),
  477.              L"msg", XMLChToVXIchar(exception.getMessage()).c_str());
  478.     xmlHandler->DestroyGrammarInfoList();
  479.     delete newGrammarPtr;
  480.     return NULL;
  481.   }
  482.   // Take the ownership of grammar info list
  483.   if( !isdtmf ) isdtmf = xmlHandler->isDTMFGrammar();
  484.   newGrammarPtr->gtype = ( isdtmf ? VXIrecWordList::GTYPE_DTMF : 
  485.                            VXIrecWordList::GTYPE_SPEECH);
  486.   newGrammarPtr->grammarInfoList = xmlHandler->AcquireGrammarInfoList();
  487.   return newGrammarPtr;
  488. }
  489. void VXIrecData::Clear()
  490. {
  491.   if( !grammars.empty() )
  492.     for (GRAMMARS::iterator i = grammars.begin(); i != grammars.end(); ++i)
  493.       delete *i;
  494.   grammars.clear();
  495. }
  496. void VXIrecData::ActivateGrammar(VXIrecGrammar *g)
  497. {
  498.   g->SetEnabled(true);
  499.   activeGrammars.push_back(g);
  500. }
  501. void VXIrecData::DeactivateGrammar(VXIrecGrammar *g)
  502. {
  503.   g->SetEnabled(false);
  504.   activeGrammars.remove(g);
  505. }
  506. int VXIrecData::GetActiveCount() const
  507. {
  508.   /*int count = 0;
  509.   for (GRAMMARS::const_iterator i = grammars.begin(); i != grammars.end(); ++i) {
  510.     if ((*i)->IsEnabled()) count++;
  511.   }
  512.   return count;*/
  513.   return activeGrammars.size();
  514. }
  515. void VXIrecData::AddGrammar(VXIrecGrammar * l)
  516. {
  517.   if (l == NULL) return;
  518.   grammars.push_front(l);
  519. }
  520. void VXIrecData::FreeGrammar(VXIrecGrammar * l)
  521. {
  522.   if (l == NULL) return;
  523.   if( !grammars.empty() )
  524.     grammars.remove(l);
  525.   delete l;
  526. }
  527. bool VXIrecData::ProcessSemanticInterp(vxistring & result, const VXIrecGrammarInfo *ginfo)
  528. {
  529.   const VXIchar* fnname = L"ProcessSemanticInterp";
  530.   LogBlock logger(log, VXIrecData::diagLogBase, fnname, VXIREC_MODULE);
  531.   result = L"";
  532.   if( !ginfo ) return false;
  533.   if( ginfo->tag.empty() ) {
  534.     // there is no tag
  535.     result = L"<instance></instance>";
  536.     return true;
  537.   }
  538.   // Processin <tag>
  539.   // this is only a partial impl.
  540.   // given a tag of:
  541.   //    x=new Object(); x.a='valueA'; x.b='valueB'; y='valueY'; z='valueZ'; 
  542.   // the following should be created:
  543.   //    <instance>
  544.   //       <x>
  545.   //          <a>valueA</a>
  546.   //          <b>valueB</b>
  547.   //       </x>
  548.   //       <y>valueY</y>
  549.   //       <z>valueZ</z>
  550.   //    </instance>
  551.   //
  552.   // but... this code won't do that.
  553.   vxistring temp = ginfo->tag;
  554.   vxistring::size_type pos = temp.find(L"=");
  555.   // handle simple result.  ex.: <tag>frog</tag> would
  556.   // return <instance>frog</instance>
  557.   if( pos == vxistring::npos ){
  558.     result = L"<instance>" + ginfo->tag + L"</instance>";
  559.     return true;
  560.   }
  561.   result =  L"<instance>";
  562.   bool gotit = false;
  563.   while (!temp.empty() && pos != vxistring::npos ) {
  564.     // retrieve var.
  565.     vxistring semvar = temp.substr(0, pos);
  566.     PruneWhitespace(semvar);
  567.     temp.erase(0, pos+1);
  568.     PruneWhitespace(temp);
  569.    
  570.     // find value
  571.     vxistring value;
  572.     pos = temp.find(L";");
  573.     if( pos == vxistring::npos ) {
  574.       if( temp.empty() ) return false;
  575.       value = temp;
  576.       temp = L"";
  577.     }
  578.     else {
  579.       value = temp.substr(0, pos);
  580.       temp.erase(0, pos+1);
  581.     }
  582.     if( !value.empty() ) {
  583.       PruneWhitespace(value);
  584.       // remove single or double quotes
  585.       if( value[0] == L'"' ) value.erase(0,1);
  586.       if( value[value.length()-1] == L'"' ) value.erase(value.length()-1);
  587.       if( value[0] == L''' ) value.erase(0,1);
  588.       if( value[value.length()-1] == L''' ) value.erase(value.length()-1);
  589.     }
  590.     else {
  591.       result = L"";
  592.       return false;
  593.     }
  594.     // construct semantic
  595.     logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%s%s%s%s%s", L"tag: ", semvar.c_str(),
  596.                L", value: ", value.c_str(),
  597.                L", semantic: ", ginfo->semantic.c_str());
  598.                
  599.     if( semvar == ginfo->semantic ) {
  600.       if( gotit ) {
  601.         result = L"";
  602.         return false;
  603.       }
  604.       gotit = true;
  605.       result += value;
  606.     }
  607.     else {
  608.       result += L"<" + semvar;
  609.       result += L" confidence='100'>";
  610.       result += value;
  611.       result += L"</" + semvar + L">";
  612.     }
  613.     // Search for next var.
  614.     pos = temp.find(L"=");
  615.   }
  616.   result +=  L"</instance>";
  617.   return true;
  618. }
  619. bool VXIrecData::ConstructNLSMLForInput(const VXIchar* input, vxistring & nlsmlresult)
  620. {
  621.   const VXIchar* fnname = L"ConstructNLSMLForInput";
  622.   LogBlock logger(log, VXIrecData::diagLogBase, fnname, VXIREC_MODULE);
  623.   VXIrecGrammar * match = NULL;
  624.   VXIrecGrammarInfo * gInfo = NULL;
  625.   VXIchar gramid[64];
  626.   nlsmlresult = L"";
  627.   if( !input || input[0] == L'' ) return false;
  628.   for (GRAMMARS::iterator i = activeGrammars.begin(); i != activeGrammars.end(); ++i) {
  629.     if ((*i)->IsEnabled() && (*i)->GetGrammarInfo(input, &gInfo)) {
  630.       logger.logDiag(DIAG_TAG_RECOGNITION, L"%s%p%s%s",
  631.            (match ? L"Multiple grammars matched " : L"Found matched grammar "),
  632.            (*i), L" for ", gInfo->word.c_str());
  633.       match = *i;
  634.       // Constructing NLSML result
  635.       if( nlsmlresult.empty() ) {
  636.         // header
  637.         nlsmlresult = L"<?xml version='1.0'?>"
  638.                       L"<result>";
  639.       }
  640.       // Create grammar ID
  641.       SWIswprintf(gramid, 64, L"%p", match);
  642.       // interpretation
  643.       nlsmlresult += L"<interpretation grammar='";
  644.       nlsmlresult += gramid;
  645.       nlsmlresult += L"' confidence='99'><input mode='";
  646.       nlsmlresult += ( match->IsDtmf() ? L"dtmf'>" : L"speech'>");
  647.       nlsmlresult += gInfo->word;
  648.       nlsmlresult += L"</input>";
  649.       // Semantic interp.
  650.       vxistring temp(L"");
  651.       if( !ProcessSemanticInterp(temp, gInfo) )
  652.       {
  653.         nlsmlresult = L"";
  654.         break;
  655.       }
  656.       nlsmlresult += temp.c_str();
  657.       // close interpretation
  658.       nlsmlresult += L"</interpretation>";
  659.     }
  660.   }
  661.   if( !nlsmlresult.empty() ) {
  662.     nlsmlresult += L"</result>";
  663.     return true;
  664.   }
  665.   return false;
  666. }
  667. //////////////////////////////////////////////////////
  668. // These routines process JSGF-lite grammars.       //
  669. //////////////////////////////////////////////////////
  670. static const int FINISH_STAGE = 3;
  671. void VXIrecData::ConvertJSGFType(const vxistring & dataIn, JSGFInfo & info)
  672. {
  673.   // search tokens
  674.   const vxistring fEqualToken(L"=");
  675.   const vxistring fCommaToken(L";");
  676.   const vxistring fHeaderToken(L"#JSG");
  677.   vxistring data(dataIn);
  678.   vxistring fVersion;
  679.   vxistring fName;
  680.   vxistring fPublic;
  681.   // search
  682.   vxistring::size_type pos = data.find(fCommaToken);
  683.   int stage = 0;
  684.   while( pos != vxistring::npos && stage < FINISH_STAGE) {
  685.     vxistring temp = data.substr(0, pos);
  686.     switch( stage++ ) {
  687.       case 0: // version
  688.         // confirm JSGF header
  689.         if( temp.find(fHeaderToken) == vxistring::npos) {
  690.           // quit parsing,
  691.           stage = FINISH_STAGE;
  692.           break;
  693.         }
  694.         info.versionStr = temp;
  695.         data.erase(0, pos+1);
  696.         break;
  697.       case 1: // grammar name
  698.         info.nameStr = temp;
  699.         data.erase(0, pos+1);
  700.         break;
  701.       case 2: // public type
  702.       {
  703.         // remove the found token
  704.         data.erase(pos);
  705.         // search for "=" token
  706.         vxistring::size_type tpos = data.find(fEqualToken);
  707.         if( tpos != vxistring::npos ) {
  708.           info.publicStr = data.substr(0, tpos);
  709.           // remove the public string
  710.           data.erase(0, tpos+1);
  711.         }
  712.       } break;
  713.     }
  714.     // Continue searching
  715.     if( stage != FINISH_STAGE ) pos = data.find(fCommaToken);
  716.   }
  717.   // finally copy the content string
  718.   info.contentStr = data;
  719. }
  720. static void GetNextToken(const vxistring & grammar,
  721.                          vxistring::size_type pos,
  722.                          vxistring::size_type end,
  723.                          vxistring & token)
  724. {
  725.   // Find first real character
  726.   while (pos != grammar.length() && VXIrecIsSpace(grammar[pos])) ++pos;
  727.   if (pos == grammar.length()) {
  728.     token.erase();
  729.     return;
  730.   }
  731.   // Extract wordRaw; we know there is at least one character
  732.   while (VXIrecIsSpace(grammar[end - 1])) --end;
  733.   token = grammar.substr(pos, end - pos);
  734. }
  735. //
  736. // This conversion function is tied to ScanSoft's semantic interpretation
  737. //
  738. bool VXIrecData::JSGFToSRGS(const vxistring & incoming,
  739.                             vxistring & result,
  740.                             const VXIMap* props)
  741. {
  742.   // These define the symbols used in the JSGF-lite that defines these grammars
  743.   const wchar_t NEXT      = L'|';
  744.   const wchar_t BEGIN_VAL = L'{';
  745.   const wchar_t END_VAL   = L'}';
  746.   // retrieve language id
  747.   vxistring xmllang(L"");
  748.   const VXIValue *v = VXIMapGetProperty(props, REC_LANGUAGE);
  749.   if( v && VXIValueGetType(v) == VALUE_STRING )
  750.     xmllang = VXIStringCStr((const VXIString*)v);
  751.   // Unable to detect language id
  752.   if( xmllang.empty() ) return false;
  753.   // retrieve dtmf id
  754.   bool isDTMF = false;
  755.   v = VXIMapGetProperty(props, REC_INPUT_MODES);
  756.   if( v && VXIValueGetType(v) == VALUE_INTEGER)
  757.   {
  758.     isDTMF = (VXIIntegerValue((const VXIInteger*)v) == REC_INPUT_MODE_DTMF);
  759.   }
  760.   // create ROOT id, potential bug anyone care???
  761.   VXItrdMutexLock(gblMutex);
  762.   VXIulong cnt = GRAM_ROOT_COUNTER++;
  763.   VXItrdMutexUnlock(gblMutex);
  764.   std::basic_stringstream<VXIchar> ROOT_ID;
  765.   ROOT_ID << GRAM_ROOT_PREFIX << cnt;
  766.   result = L"<?xml version='1.0'?>"
  767.            L"<grammar xmlns='http://www.w3.org/2001/06/grammar' "
  768.            L"version='1.0' root='";
  769.   result += ROOT_ID.str();
  770.   result += L"' tag-format='swi-semantics/1.0' xml:lang='";
  771.   result += xmllang;
  772.   result += L"'";
  773.   if (isDTMF)
  774.     result += L" mode='dtmf'";
  775.   result += L">n"
  776.             L"<meta name="swirec_simple_result_key" content="MEANING"/>"
  777.             L"<rule id='";
  778.   result += ROOT_ID.str();
  779.   result += L"' scope='public'>n"
  780.             L"<one-of>n";
  781.   // These define the units from which we'll build new rules.
  782.   const vxistring RULE_BEGIN  = L"<item>";
  783.   const vxistring RULE_MIDDLE = L"<tag>MEANING="";
  784.   const vxistring RULE_END    = L"";</tag></item>n";
  785.   // TODO: Must escape values in tags???
  786.   // These are positions within the string that we're parsing.
  787.   vxistring::size_type pos = 0;
  788.   vxistring::size_type next;
  789.   vxistring::size_type valmark;
  790.   vxistring wordRaw;
  791.   vxistring wordValue;
  792.   while (pos < incoming.length()) {
  793.     // Find the next item
  794.     next = incoming.find(NEXT, pos);
  795.     if (next == vxistring::npos) next = incoming.length();
  796.     // Find the start of the value
  797.     valmark = incoming.find(BEGIN_VAL, pos);
  798.     if (valmark == vxistring::npos || valmark > next) valmark = next;
  799.     // Extract left hand side (raw text)
  800.     GetNextToken(incoming, pos, valmark, wordRaw);
  801.     if (wordRaw.empty()) {
  802.       pos = next + 1;
  803.       continue;
  804.     }
  805.     pos = valmark + 1;
  806.     // Extract right hand side (value)
  807.     if (valmark != next && pos < incoming.length()) {
  808.       valmark = incoming.find(END_VAL, pos);
  809.       if (valmark == vxistring::npos || valmark > next) {
  810.         LogError(280, L"%s%s", L"Error", L"Mismatched { } pair");
  811.         return false;
  812.       }
  813.       GetNextToken(incoming, pos, valmark, wordValue);
  814.       if (wordValue.empty()) {
  815.         return false;
  816.       }
  817.       pos = next + 1;
  818.     }
  819.     else
  820.       wordValue.erase();
  821.     // Add word to grammar
  822.     FixEscapeChar(wordRaw);
  823.     if (!wordValue.empty()) {
  824.       // Got tag value
  825.       FixEscapeChar(wordValue);
  826.       result += RULE_BEGIN + wordRaw + RULE_MIDDLE + wordValue + RULE_END;
  827.     } else {
  828.       // Didn't get tag value
  829.       result += RULE_BEGIN + wordRaw + RULE_MIDDLE + wordRaw + RULE_END;
  830.     }
  831.   }
  832.   // add end tag
  833.   result += L"</one-of></rule></grammar>";
  834.   return true;
  835. }
  836. bool VXIrecData::OptionToSRGS(const VXIMap    * props,
  837.                   const VXIVector * choices,
  838.                   const VXIVector * values,
  839.                   const VXIVector * acceptances,
  840.                   const VXIbool     isDTMF,
  841.                   vxistring & srgs)
  842. {
  843.   static const VXIchar* fnname = L"OptionToSRGS";
  844.   srgs = L"";
  845.   // (1) Validate vectors.
  846.   if (choices == NULL || values == NULL || acceptances == NULL) {
  847.     LogError(281, L"%s%s", L"A Vector", L"NULL");
  848.     return false;
  849.   }
  850.   unsigned int len = VXIVectorLength(choices);
  851.   if (len != VXIVectorLength(values)) {
  852.     LogError(281, L"%s%s", L"Vectors", L"Mismatched vector lengths");
  853.     return false;
  854.   }
  855.   for (unsigned int j = 0; j < len; ++j) {
  856.     const VXIValue * c = VXIVectorGetElement(choices, j);
  857.     const VXIValue * v = VXIVectorGetElement(values, j);
  858.     const VXIValue * a = VXIVectorGetElement(acceptances, j);
  859.     if (c == NULL || v == NULL || VXIValueGetType(c) != VALUE_STRING ||
  860.         VXIValueGetType(v) != VALUE_STRING)
  861.     {
  862.       LogError(281, L"%s%s", L"Options", L"Contents not all strings");
  863.       return false;
  864.     }
  865.     LogDiag(4, fnname, L"%s%s%s%s%s%d",
  866.             L"choice: ", VXIStringCStr(reinterpret_cast<const VXIString *>(c)),
  867.             L", value: ", VXIStringCStr(reinterpret_cast<const VXIString *>(v)),
  868.             L", accept: ", VXIIntegerValue(reinterpret_cast<const VXIInteger *>(a)) );
  869.   }
  870.   // (2) extracting weight (does not meaning anything for simulator ???)
  871.   VXIulong weight = 1;
  872.   const VXIValue* val = VXIMapGetProperty(props, REC_GRAMMAR_WEIGHT);
  873.   if( val && VXIValueGetType(val) == VALUE_FLOAT )
  874.     weight *= (VXIulong)VXIFloatValue((const VXIFloat*)val);
  875.   // (3) retrieve language id
  876.   vxistring xmllang(L"");
  877.   const VXIValue *v = VXIMapGetProperty(props, REC_LANGUAGE);
  878.   if( v && VXIValueGetType(v) == VALUE_STRING )
  879.     xmllang = VXIStringCStr((const VXIString*)v);
  880.   // Unable to detect language id
  881.   if( xmllang.empty() ) return false;
  882.   // (4) create ROOT id, wrap-round potential bug, anyone care???
  883.   VXItrdMutexLock(gblMutex);
  884.   VXIulong cnt = GRAM_ROOT_COUNTER++;
  885.   VXItrdMutexUnlock(gblMutex);
  886.   std::basic_stringstream<VXIchar> ROOT_ID;
  887.   ROOT_ID << GRAM_ROOT_PREFIX << cnt;
  888.   // (4) construct srgs -- NOTES: this construction is tied to SSFT's semantic
  889.   srgs = L"<?xml version='1.0'?><grammar "
  890.          L"xmlns='http://www.w3.org/2001/06/grammar' "
  891.          L"version='1.0' root='";
  892.   srgs += ROOT_ID.str();
  893.   srgs += L"' tag-format='swi-semantics/1.0' xml:lang='";
  894.   srgs += xmllang;
  895.   srgs += L"'";
  896.   if (isDTMF) srgs += L" mode='dtmf'";
  897.   srgs += L"><meta name='swirec_simple_result_key' content='MEANING'/>"
  898.           L"<rule id='";
  899.   srgs += ROOT_ID.str();
  900.   srgs += L"' scope='public'><one-of>";
  901.   // (5) Add item for each <option>.
  902.   // These define the units from which we'll build new rules.
  903.   const vxistring RULE_BEGIN  = L"<item>";
  904.   const vxistring RULE_MIDDLE = L"<tag>MEANING='";
  905.   const vxistring RULE_END    = L"';</tag></item>";
  906.   for (unsigned int i = 0; i < len; ++i) {
  907.     const VXIValue * c = VXIVectorGetElement(choices, i);
  908.     const VXIValue * v = VXIVectorGetElement(values, i);
  909.     const VXIValue * a = VXIVectorGetElement(acceptances, i);
  910.     vxistring aitem( VXIStringCStr(reinterpret_cast<const VXIString *>(c)));
  911.     vxistring avalue(VXIStringCStr(reinterpret_cast<const VXIString *>(v)));
  912.     // normalize text
  913.     FixEscapeChar(aitem);
  914.     if( !isDTMF && VXIIntegerValue(reinterpret_cast<const VXIInteger *>(a)) > 0 )
  915.     {
  916.       // If Recongizer does not support approximate recognition we need to
  917.       // split the string into single item based on single space
  918.       bool done = false;
  919.       vxistring tmpStr(aitem);
  920.       vxistring::size_type idx;
  921.       VXIchar aWord[1024];
  922.       const VXIchar *ptr = tmpStr.c_str();
  923.       // search for the 1st white space
  924.       // TODO: should take care about tab, multiple spaces!!!
  925.       idx = tmpStr.find(L" ", 0);
  926.       do
  927.       {
  928.         // create single item separated by space
  929.         if( idx == vxistring::npos )
  930.         {
  931.           idx = tmpStr.length();
  932.           done = true;
  933.         }
  934.         // create separate <item> for each word
  935.         wcsncpy(aWord, ptr, idx);
  936.         aWord[idx] = L'';
  937.         srgs += RULE_BEGIN;
  938.         srgs += aWord;
  939.         srgs += RULE_MIDDLE;
  940.         srgs += avalue;
  941.         srgs += RULE_END;
  942.         // search for the next word
  943.         if( !done )
  944.         {
  945.           ptr += (idx+1);
  946.           tmpStr = ptr;
  947.           idx = tmpStr.find(L" ", idx + 1);
  948.         }
  949.       } while( !done );
  950.     } else {
  951.       srgs += RULE_BEGIN;
  952.       srgs += aitem;
  953.       srgs += RULE_MIDDLE;
  954.       srgs += avalue;
  955.       srgs += RULE_END;
  956.     }
  957.   }
  958.   // (6) Finish everything and add grammar.
  959.   srgs += L"</one-of></rule></grammar>";
  960.   LogDiag(DIAG_TAG_RECOGNITION, fnname, L"%s%s", L"OPTION GRAMMAR: ", srgs.c_str());
  961.   return true;
  962. }
  963. VXIlogResult VXIrecData::LogError(VXIunsigned errorID,
  964.                                const VXIchar *format, ...) const
  965. {
  966.   VXIlogResult rc;
  967.   va_list args;
  968.   if (!log)
  969.     return VXIlog_RESULT_NON_FATAL_ERROR;
  970.   if (format) {
  971.     va_start(args, format);
  972.     rc = (*log->VError)(log, COMPANY_DOMAIN L".VXIrec", errorID, format, args);
  973.     va_end(args);
  974.   } else {
  975.     rc = (*log->Error)(log, COMPANY_DOMAIN L".VXIrec", errorID, NULL);
  976.   }
  977.   return rc;
  978. }
  979. VXIlogResult VXIrecData::LogDiag(VXIunsigned tag, const VXIchar *subtag,
  980.                               const VXIchar *format, ...) const
  981. {
  982.   VXIlogResult rc;
  983.   va_list args;
  984.   if (!log)
  985.     return VXIlog_RESULT_NON_FATAL_ERROR;
  986.   if (format) {
  987.     va_start(args, format);
  988.     rc = (*log->VDiagnostic)(log, tag + diagLogBase, subtag, format, args);
  989.     va_end(args);
  990.   } else {
  991.     rc = (*log->Diagnostic)(log, tag + diagLogBase, subtag, NULL);
  992.   }
  993.   return rc;
  994. }
  995. bool VXIrecData::FetchContent(
  996.     const VXIchar *  name, 
  997.     const VXIMap  *  properties,
  998.     VXIbyte       ** result,
  999.     VXIulong      &  read )
  1000. {
  1001.   *result = NULL;
  1002.   read = 0;
  1003.   VXIinetStream *stream;
  1004.   VXIMapHolder streamInfo;
  1005.  
  1006.   if (inet->Open(inet,
  1007. L"Rec",
  1008. name,
  1009. INET_MODE_READ,
  1010. 0,
  1011. properties,
  1012. streamInfo.GetValue(),
  1013. &stream ) != VXIinet_RESULT_SUCCESS ) return false;
  1014.   const VXIValue * tempSize = NULL;
  1015.   tempSize = VXIMapGetProperty(streamInfo.GetValue(), INET_INFO_SIZE_BYTES);
  1016.   if (tempSize == NULL || VXIValueGetType(tempSize) != VALUE_INTEGER) {
  1017.     inet->Close(inet, &stream);
  1018. return false;
  1019.   }
  1020.   VXIint32 bufSize
  1021.     = VXIIntegerValue(reinterpret_cast<const VXIInteger *>(tempSize));
  1022.   if (bufSize < 2047)
  1023.     bufSize = 2047;
  1024.   ++bufSize;
  1025.   VXIbyte * buffer = new VXIbyte[bufSize];
  1026.   if(buffer == NULL){
  1027.     inet->Close(inet, &stream);
  1028.     return false;
  1029.   }
  1030.   bool reachedEnd = false; 
  1031.   while (!reachedEnd) {
  1032.     VXIulong bytesRead = 0;
  1033.     switch (inet->Read(inet, buffer+read, bufSize-read, &bytesRead, stream)) {
  1034.     case VXIinet_RESULT_SUCCESS:
  1035.       read += bytesRead;
  1036.       break;
  1037.     case VXIinet_RESULT_END_OF_STREAM:
  1038.       read += bytesRead;
  1039.       reachedEnd = true;  // exit while
  1040.       break;
  1041.     case VXIinet_RESULT_WOULD_BLOCK:
  1042.       VXItrdThreadYield();
  1043.       break;
  1044.     default:
  1045.       inet->Close(inet, &stream);
  1046.       delete[] buffer;
  1047.       return false;
  1048.     }
  1049.     if (read == static_cast<VXIulong>(bufSize)) {
  1050.       // The number of bytes read exceeds the number expected.  Double the
  1051.       // size and keep reading.
  1052.       VXIbyte * temp = new VXIbyte[2*bufSize];
  1053.       if(temp == NULL) {
  1054.         delete [] buffer;
  1055.         return false;
  1056.       }
  1057.       memcpy(static_cast<void *>(temp), static_cast<void *>(buffer),
  1058.              bufSize * sizeof(VXIbyte));
  1059.       delete[] buffer;
  1060.       buffer = temp;
  1061.       bufSize *= 2;
  1062.     }
  1063.   }
  1064.   inet->Close(inet, &stream);
  1065.   *result = buffer;
  1066.   return true;
  1067. }