xmlconfig.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:60k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: xmlconfig.cpp,v 1.9.22.1 2004/07/19 21:04:07 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. //  $Id: xmlconfig.cpp,v 1.9.22.1 2004/07/19 21:04:07 hubbe Exp $
  50. #ifdef _UNIX 
  51. #include <sys/stat.h> 
  52. #endif 
  53. #include "hxtypes.h"
  54. #include "hxcom.h"
  55. #include "looseprs.h"
  56. #include "cbbqueue.h"
  57. #include "hxstrutl.h"
  58. #include "ihxpckts.h"
  59. #include "chxpckts.h"
  60. #include "hxmon.h" // for registry property type enums
  61. #include "hxerror.h"
  62. #include "xmlconfig.h"
  63. #include "errmsg_macros.h"
  64. #define MAX_TAG_SIZE 32768
  65. #define MAX_ERROR_CHARS 20 // Number of chars to print if an error occurs
  66. static const XMLConfigAlias aliases[] = {
  67.     //Note: Attribute specs here should not have quotes in them!
  68.     //      %0 is replaced with the name of the alias (leftmost column)
  69.     //      %n with the value of the nth attribute
  70.     //      %  args can only appear in the values of attributes
  71.     
  72.     //Alias This Tag    To This         With these 3 args      and these flags
  73.     {"FSMount", "List", "Name=FSMount", NULL, NULL,         0},
  74.     {"Plugin",          "List", "Name=%1",      NULL, NULL,         0},
  75.     {"MimeTypes",       "List", "Name=MimeTypes", NULL, NULL,       0},
  76.     {"Type",            "List", "Name=%1",      NULL, NULL,         0},
  77.     {"Ext",             "Var",  NULL,           NULL, NULL,         0},
  78.     {"IPBindings",      "List", "Name=IPBindings", NULL, NULL,      0},
  79.     {"HTTPDeliverable", "List", "Name=HTTPDeliverable", NULL, NULL,      0},
  80.     {"Path",      "Var", NULL, NULL, NULL,     0},
  81.     {"ConnectControl",  "List", "Name=ConnectControl", NULL, NULL,  0},
  82.     {"Multicast", "List", "Name=Multicast", NULL, NULL,0},
  83.     {"Address",         "Var",  NULL,           NULL, NULL,         0},
  84.     {"NetMask",         "Var",  NULL,           NULL, NULL,         0},
  85.     {"AccessLogging",   "List", "Name=AccessLogging", NULL, NULL,   0},
  86.     {"LiveArchive",     "List", "Name=LiveArchive", NULL, NULL,     0},
  87.     {"FarmSplit",       "List", "Name=FarmSplit", NULL, NULL,     0},
  88.     {"Directory",       "List", "Name=%1",      NULL, NULL,         0},
  89.     {"AccessControl",   "List", "Name=AccessControl", NULL, NULL,     0},
  90.     {"Rule",      "List", "Name=%1", NULL, NULL,     0},
  91.     {"Access",      "Var", NULL, NULL, NULL,     0},
  92.     {"Transmission",    "Var",  NULL, NULL, NULL,     0},
  93.     {"To",      "Var", NULL, NULL, NULL,     0},
  94.     {"From",      "Var", NULL, NULL, NULL,     0},
  95.     {"Ports",      "List", "Name=Ports", NULL, NULL,     0},
  96.     {"Num",      "Var", NULL, NULL, NULL,     0},
  97.     {"Proxy",      "List", "Name=Proxy", NULL, NULL,     0},
  98.     {NULL, NULL, NULL, NULL, NULL, 0}
  99. };
  100. #if defined (_WINDOWS ) || defined (_WIN32) || defined(_SYMBIAN)
  101. #define OS_SEPARATOR_CHAR '\'
  102. #define OS_SEPARATOR_STRING "\"
  103. #elif defined (_UNIX)
  104. #define OS_SEPARATOR_CHAR '/'
  105. #define OS_SEPARATOR_STRING "/"
  106. #elif defined (_MACINTOSH) 
  107. #ifdef _MAC_MACHO
  108. #define OS_SEPARATOR_CHAR       '/' 
  109. #define OS_SEPARATOR_STRING     "/" 
  110. #else
  111. #define OS_SEPARATOR_CHAR       ':' 
  112. #define OS_SEPARATOR_STRING     ":" 
  113. #endif
  114. #endif // defined (_WINDOWS ) || defined (_WIN32)
  115. XMLConfig::XMLConfigListNode::~XMLConfigListNode()
  116. {
  117.     if(m_pList)
  118.     {
  119. delete m_pList;
  120.     }
  121.     if(m_name)
  122. delete [] m_name;
  123.     if(m_value)
  124. delete [] m_value;
  125. }
  126. XMLConfig::XMLConfigList::~XMLConfigList()
  127. {
  128.     CHXSimpleList::Iterator i;
  129.     for(i = Begin(); i != End(); ++i)
  130.     {
  131. XMLConfigListNode* node = (XMLConfigListNode*)(*i);
  132. delete node;
  133.     }
  134. }
  135. XMLConfig::XMLConfig():m_filename(NULL), m_lRefCount(0), m_pList(NULL),
  136.                        m_ulMajor(0), m_ulMinor(0), m_ActiveSetsOutstanding(0),
  137.                        m_pRegistry(NULL), m_pMessages(NULL), m_szServerversion(NULL),
  138.                        m_pReconfigureResponse(NULL)
  139. {
  140. }
  141. XMLConfig::XMLConfig(IHXRegistry2* pRegistry, IHXErrorMessages* pMessages, const char* szserverversion,
  142.                      UINT32 dwMajor, UINT32 dwMinor)
  143.      : m_filename(0), m_lRefCount(0), m_pList(NULL), m_ulMajor(dwMajor), m_ulMinor(dwMinor)
  144.        , m_ActiveSetsOutstanding(0), m_pReconfigureResponse(NULL)
  145. {
  146.     if (pRegistry)
  147.     {
  148.         m_pRegistry = pRegistry;
  149.         m_pRegistry->AddRef();
  150.     }
  151.     if (pMessages)
  152.     {
  153.         m_pMessages = pMessages;
  154.         m_pMessages->AddRef(); 
  155.     }
  156.     m_szServerversion = new_string(szserverversion);
  157.     
  158.     XMLConfigAlias* alias = (XMLConfigAlias*) &aliases[0];
  159.     char lwr[256]; /* Flawfinder: ignore */
  160.     m_vserver = -1;
  161.     while(alias->from)
  162.     {
  163. SafeStrCpy(lwr, alias->from, 256);
  164. strlwr(lwr);
  165. m_alias_dict.enter(lwr, alias);
  166. alias++;
  167.     }
  168. }
  169. XMLConfig::~XMLConfig()
  170. {
  171.     delete[] m_szServerversion; 
  172.     HX_RELEASE(m_pReconfigureResponse);
  173.     HX_RELEASE(m_pRegistry);
  174.     HX_RELEASE(m_pMessages); 
  175. }
  176. HX_RESULT
  177. XMLConfig::init(IHXRegistry2* pRegistry, IHXErrorMessages* pMessages, const char* szserverversion,
  178.                      UINT32 dwMajor, UINT32 dwMinor)
  179. {
  180.     m_ulMajor = dwMajor;
  181.     m_ulMinor = dwMinor;
  182.     if (pRegistry)
  183.     {
  184.         m_pRegistry = pRegistry;
  185.         m_pRegistry->AddRef();
  186.     }
  187.     if (pMessages)
  188.     {
  189.         m_pMessages = pMessages;
  190.         m_pMessages->AddRef(); 
  191.     }
  192.     m_szServerversion = new_string(szserverversion);
  193.     
  194.     XMLConfigAlias* alias = (XMLConfigAlias*) &aliases[0];
  195.     char lwr[256]; /* Flawfinder: ignore */
  196.     m_vserver = -1;
  197.     while(alias->from)
  198.     {
  199. SafeStrCpy(lwr, alias->from, 256);
  200. strlwr(lwr);
  201. m_alias_dict.enter(lwr, alias);
  202. alias++;
  203.     }
  204.     return HXR_OK;
  205. }
  206. STDMETHODIMP
  207. XMLConfig::QueryInterface(REFIID riid, void** ppvObj)
  208. {
  209.     if(IsEqualIID(riid, IID_IUnknown))
  210.     {
  211.         AddRef();
  212.         *ppvObj = (IUnknown*)(IHXRegConfig*)this;
  213.         return HXR_OK;
  214.     }
  215.     else if (IsEqualIID(riid, IID_IHXRegConfig))
  216.     {
  217. AddRef();
  218. *ppvObj = (IHXRegConfig*)this;
  219. return HXR_OK;
  220.     }
  221.     *ppvObj = NULL;
  222.     return HXR_NOINTERFACE;
  223. }
  224. STDMETHODIMP_(UINT32)
  225. XMLConfig::AddRef()
  226. {
  227.     return InterlockedIncrement(&m_lRefCount);    
  228. }
  229. STDMETHODIMP_(UINT32)
  230. XMLConfig::Release()
  231. {
  232.     if (InterlockedDecrement(&m_lRefCount) > 0)
  233.     {
  234.         return m_lRefCount;
  235.     }
  236.     delete this;
  237.     return 0;
  238. }
  239. HX_RESULT
  240. XMLConfig::Write(const char* name, const char* filename)
  241. {
  242.     FILE* outfile = fopen(filename, "w");
  243.     if(!outfile)
  244.     {
  245. return HXR_INVALID_FILE;
  246.     }
  247.     fprintf(outfile, "<?XML Version="1.0" ?>n");
  248.     fprintf(outfile, "<!-- Auto generated by %s %d.%d -->nn",
  249.             m_szServerversion, m_ulMajor, m_ulMinor);
  250. #ifdef _UNIX
  251.     chmod(filename, 0700);
  252. #endif //UNIX
  253.     return DumpConfig(name, 0, outfile, m_pRegistry);
  254. }
  255. HX_RESULT
  256. XMLConfig::DumpConfig(const char* name, int indent, FILE* outfile,
  257.       IHXRegistry2* pRegistry)
  258. {
  259.     IHXValues* pValues;
  260.     const char* propName;
  261.     HX_RESULT res;
  262.     UINT32 prop_id;
  263.     if(HXR_OK != pRegistry->GetPropListByName(name,
  264.   pValues))
  265. return HXR_FAIL;
  266.     char* point = (char*)strrchr(name, '.');
  267.     if(point)
  268.     {
  269. if(strcasecmp(point + 1, "XXXBADLIST") == 0)
  270.     return HXR_FAIL;
  271. for(int j = 0; j < indent - 1; j++)
  272.     fprintf(outfile, "  ");
  273. fprintf(outfile, "<List %s>n", point + 1);
  274.     }
  275.     
  276.     res = pValues->GetFirstPropertyULONG32(propName, prop_id);
  277.     while(res == HXR_OK)
  278.     {
  279. HXPropType type = pRegistry->GetTypeById(prop_id);
  280. switch(type)
  281. {
  282.     case PT_COMPOSITE:
  283. DumpConfig(propName, indent+1, outfile, pRegistry);
  284. break;
  285.     case PT_INTEGER:
  286.     {
  287. INT32 val;
  288. if(HXR_OK == pRegistry->GetIntById(prop_id, val))
  289. {
  290.     
  291.     fprintf(outfile, "%*.*s<Var %s="%ld"/>n",
  292.     indent * 2, indent * 2, "  ",
  293.     strrchr(propName, '.') + 1,
  294.     val);
  295. }
  296. break;
  297.     }
  298.     case PT_INTREF:
  299. break;
  300.     case PT_STRING:
  301.     {
  302. IHXBuffer* pBuffer;
  303. if(HXR_OK == pRegistry->GetStrById(prop_id, pBuffer) && pBuffer)
  304. {
  305.     fprintf(outfile, "%*.*s<Var %s="%s"/>n",
  306.     indent * 2, indent * 2, "  ",
  307.     strrchr(propName, '.') + 1,
  308.     pBuffer->GetBuffer());
  309.     pBuffer->Release();
  310. }
  311. break;
  312.     }
  313.     case PT_BUFFER:
  314.     {
  315. IHXBuffer* pBuffer;
  316. pRegistry->GetBufById(prop_id, pBuffer);
  317. if(pBuffer)
  318. {
  319.     fprintf(outfile, "%*.*s<Var %s="%s"/>n",
  320.     indent * 2, indent * 2, "  ",
  321.     strrchr(propName, '.') + 1,
  322.     pBuffer->GetBuffer());
  323.     pBuffer->Release();
  324. }
  325. break;
  326.     }
  327.     case PT_UNKNOWN:
  328.     default:
  329. break;
  330. }
  331. res = pValues->GetNextPropertyULONG32(propName, prop_id);
  332.     }
  333.     if(point)
  334. fprintf(outfile, "%*.*s</List>n", (indent - 1) * 2, (indent-1)*2, "  ");
  335.     fflush(outfile);
  336.     pValues->Release();
  337.     return HXR_OK;
  338. }
  339. void
  340. XMLConfig::ExpandAttribute(XMLTag* tag, const char* attribute)
  341. {
  342.     const char* equals;
  343.     char subst[2048]; /* Flawfinder: ignore */
  344.     const char* a;
  345.     UINT32 arg;
  346.     UINT32 i;
  347.     equals = strchr(attribute, '=');
  348.     // Aliases are hardcoded.  Don't enter wrong ones, dumbass.
  349.     HX_ASSERT(equals);
  350.     tag->new_attribute()->name = new char[equals - attribute + 1];
  351.     strncpy(tag->m_cur_attribute->name, attribute, /* Flawfinder: ignore */
  352.     equals - attribute);
  353.     tag->m_cur_attribute->name[equals - attribute] = 0;
  354.     // Attributes already present in the tag with the same name
  355.     // as an aliased attribute override the alias.
  356.     for(i = 0; i < tag->m_numAttributes - 1; i++)
  357.     {
  358. if(tag->attribute(i)->name && 
  359.    (strcasecmp(tag->attribute(i)->name, 
  360.        tag->m_cur_attribute->name) == 0))
  361. {
  362.     break;
  363. }
  364.     }
  365.     if(i < tag->m_numAttributes - 1)
  366.     {
  367. // Found a duplicate attribute with this name, throw out the
  368. // alias version.
  369. delete tag->m_cur_attribute;
  370. tag->m_numAttributes--;
  371.     }
  372.     else if(!strchr(equals, '%'))
  373.     {
  374. tag->m_cur_attribute->value = new_string(equals+1);
  375.     }
  376.     else
  377.     {
  378. for(a = equals, i = 0; *a; a++, i++)
  379. {
  380.     switch(*a)
  381.     {
  382. case '%':
  383.     arg = *(a+1) - '0';
  384.     if(arg > 0)
  385.     {
  386. if(arg - 1 < tag->m_numAttributes)
  387. {
  388.     SafeStrCpy(&subst[i], tag->attribute(arg - 1)->value, 2048-i);
  389.     i+= strlen(tag->attribute(arg - 1)->value);
  390. }
  391. else
  392. {
  393.     ERRMSG(m_pMessages,
  394.    "%s: Alias %s requires at least %d arguments",
  395.    m_filename,
  396.    tag->m_name, arg);
  397.     return;
  398. }
  399.     }
  400.     else
  401.     {
  402. SafeStrCpy(&subst[i], tag->m_name, 2048-i);
  403. i += strlen(tag->m_name);
  404.     }
  405.     break;
  406. default:
  407.     subst[i] = *a;
  408.     }
  409. }
  410. subst[i] = 0;
  411. tag->m_cur_attribute->value = new_string(subst);
  412.     }
  413. }
  414. // XMLConfig::Expand
  415. //
  416. // Do alias and loose syntax expansion
  417. BOOL
  418. XMLConfig::Expand(XMLTag* tag, CBigByteQueue* queue)
  419. {
  420.     UINT32 i;
  421.     Dict_entry* ent;
  422.     XMLConfigAlias* alias;
  423.     char* lwr = new char[strlen(tag->m_name) + 1];
  424.     BOOL ignore = FALSE;
  425.     strcpy(lwr, tag->m_name); /* Flawfinder: ignore */
  426.     strlwr(lwr);
  427.     if((ent = m_alias_dict.find(lwr)) != NULL)
  428.     {
  429. alias = (XMLConfigAlias*)ent->obj;
  430. delete [] tag->m_name;
  431. tag->m_name = new_string(alias->to);
  432. if(tag->m_type == XMLPlainTag)
  433. {
  434.     if(alias->attr1)
  435.     {
  436. ExpandAttribute(tag, alias->attr1);
  437.     }
  438.     if(alias->attr2)
  439.     {
  440. ExpandAttribute(tag, alias->attr2);
  441.     }
  442.     if(alias->attr3)
  443.     {
  444. ExpandAttribute(tag, alias->attr3);
  445.     }
  446. }
  447. if((alias->flags & AL_TAGIFY) && (tag->m_type != XMLEndTag))
  448. {
  449.     UINT32 bytesAvail = queue->GetQueuedItemCount();
  450.     BYTE* buf = new BYTE[bytesAvail];
  451.     queue->DeQueue(buf, bytesAvail);
  452.     BOOL isList = FALSE;
  453.     char ibuf[1024]; /* Flawfinder: ignore */
  454.     if(!tag->m_need_close && strcasecmp(alias->to, "list") == 0)
  455.     {
  456. isList = TRUE;
  457. ignore = TRUE;
  458. if(tag->get_attribute("name"))
  459.     SafeSprintf(ibuf, 1024, "<List Name="%s">",
  460.     tag->get_attribute("name"));
  461. else
  462.     SafeSprintf(ibuf, 1024, "<List Name="%s">",
  463.     alias->from);
  464. queue->EnQueue(ibuf, strlen(ibuf));
  465.     }
  466.     UINT32 i;
  467.     for(i = 0; i < tag->m_numAttributes; i++)
  468.     {
  469. if (tag->attribute(i)->name)
  470. {
  471.     SafeSprintf(ibuf, 1024, "<Var Name="%s" Value="%s"/>",
  472.    (tag->attribute(i)->name ? tag->attribute(i)->name : ""),
  473.     tag->attribute(i)->value);
  474.     queue->EnQueue(ibuf, strlen(ibuf));
  475. }
  476.     }
  477.     if(isList)
  478.     {
  479. sprintf(ibuf, "</List>"); /* Flawfinder: ignore */
  480. queue->EnQueue(ibuf, strlen(ibuf));
  481.     }
  482.     queue->EnQueue(buf, bytesAvail);
  483. }
  484.     }
  485.     delete [] lwr;
  486.     if(tag->m_type != XMLPlainTag || ignore)
  487. return ignore;
  488.     if(strcasecmp(tag->m_name, "list") == 0)
  489.     {
  490. if(tag->m_numAttributes < 1)
  491. {
  492.     return ignore;
  493. }
  494. for(i = 0; i < tag->m_numAttributes; i++)
  495. {
  496.     if(!tag->attribute(i)->name)
  497.     {
  498. tag->attribute(i)->name = new_string("name");
  499.     }
  500.     else if(strcasecmp(tag->attribute(i)->name, "name") != 0)
  501.     {
  502. ERRMSG(m_pMessages,
  503.        "%s: Unknown List Attribute %s",
  504.        m_filename,
  505.        tag->attribute(i)->name);
  506. return ignore;
  507.     }
  508. }
  509.     }
  510.     else if(strcasecmp(tag->m_name, "var") == 0)
  511.     {
  512. if(tag->m_numAttributes < 1)
  513. {
  514.     ERRMSG(m_pMessages,
  515.    "%s: Var tag requires at least one attribute",
  516.    m_filename);
  517.     return ignore;
  518. }
  519. if(tag->m_numAttributes == 1)
  520. {
  521.     // Special case, <Var x=y> converts to <Var name=x value=y>
  522.     tag->new_attribute()->name = new_string("value");
  523.     tag->attribute(1)->value = tag->attribute(0)->value;
  524.     tag->attribute(0)->value = tag->attribute(0)->name;
  525.     if(!tag->attribute(0)->value)
  526.     {
  527. char* val = new char[20];
  528. sprintf(val, "elem%ld", tag->elem); /* Flawfinder: ignore */
  529. tag->attribute(0)->value = val;
  530.     }
  531.     tag->attribute(0)->name = new_string("name");
  532. }
  533.     }
  534.     else if(strcasecmp(tag->m_name, "server") == 0)
  535.     {
  536. if(tag->m_numAttributes < 1)
  537. {
  538.     ERRMSG(m_pMessages,
  539.    "%s: Server tag requires at least one attribute",
  540.    m_filename);
  541.     return ignore;
  542. }
  543. if(!tag->get_attribute("number"))
  544. {
  545.     tag->attribute(0)->name = new_string("number");
  546. }
  547.     }
  548.     return ignore;
  549. }
  550. XMLConfigVarType
  551. XMLConfig::GetVarType(XMLConfigListNode* node)
  552. {
  553.     char* pos = node->m_value;
  554.     if (0 == *pos)
  555.     {
  556.          return CfgVarString;
  557.     }
  558.     for(; *pos && isdigit(*pos); pos++)
  559. ;
  560.     if(*pos == 0 && *(node->m_value) != 0)
  561.     {
  562. node->m_int = atol(node->m_value);
  563. return CfgVarInt;
  564.     }
  565.     
  566.     if(strcasecmp(node->m_value, "true") == 0)
  567.     {
  568. node->m_bool = TRUE;
  569. return CfgVarBool;
  570.     }
  571.     else if(strcasecmp(node->m_value, "false") == 0)
  572.     {
  573. node->m_bool = FALSE;
  574. return CfgVarBool;
  575.     }
  576.     return CfgVarString;
  577. }
  578. void
  579. XMLConfig::StuffRegistry(XMLConfigList* list)
  580. {
  581.     CHXSimpleList::Iterator i;
  582.     char* regname = list->m_parentnode->get_registry_name();
  583.     if(m_pRegistry->GetTypeByName(regname) == PT_UNKNOWN)
  584.     { 
  585. m_pRegistry->AddComp(regname);
  586.     }
  587.     delete [] regname;
  588.     for(i = list->Begin(); i != list->End(); ++i)
  589.     {
  590. XMLConfigListNode* node = (XMLConfigListNode*)(*i);
  591. switch(node->m_type)
  592. {
  593.     case CfgVar:
  594. regname = node->get_registry_name();
  595. switch(GetVarType(node))
  596. {
  597.     case CfgVarInt:
  598. // printf("%s = %ldn", regname, node->m_int);
  599.                         if(m_pRegistry->GetTypeByName(regname) == PT_UNKNOWN)
  600. {
  601.     m_pRegistry->AddInt(regname, node->m_int);
  602. }
  603. else
  604. {
  605.     m_pRegistry->SetIntByName(regname, node->m_int);
  606. }
  607. break;
  608.     case CfgVarString:
  609.     {
  610. CHXBuffer* pBuffer = new CHXBuffer;
  611. pBuffer->AddRef();
  612. pBuffer->Set((UINT8*)node->m_value,
  613.      strlen(node->m_value) + 1);
  614. // printf("%s = %sn", regname, (const char *)pBuffer->GetBuffer());
  615. if(m_pRegistry->GetTypeByName(regname) == PT_UNKNOWN)
  616. {
  617.     m_pRegistry->AddStr(regname, pBuffer);
  618. }
  619. else
  620. {
  621.     m_pRegistry->SetStrByName(regname, pBuffer);
  622. }
  623. pBuffer->Release();
  624. break;
  625.     }
  626.     case CfgVarBool:
  627. // printf("%s = %ldn", regname, node->m_bool);
  628. if(m_pRegistry->GetTypeByName(regname) == PT_UNKNOWN)
  629. {
  630.     m_pRegistry->AddInt(regname, node->m_bool);
  631. }
  632. else
  633. {
  634.     m_pRegistry->SetIntByName(regname, node->m_bool);
  635. }
  636. break;
  637. }
  638. delete [] regname;
  639. break;
  640.     case CfgList:
  641. StuffRegistry(node->m_pList);
  642. break;
  643. }
  644.     }
  645. }
  646. // 
  647. // Method: Read
  648. //
  649. // Parameters:
  650. //
  651. // filename:    The file to be read.
  652. // pWinRegKey:  The Windows registry key to be filled in (can be
  653. //   NULL if no registry writing is needed).
  654. // pServRegKey: The Server registry key to be filled in.
  655. // 
  656. // Notes: the bIncludedFile is for internal recursive use only.  Do not 
  657. // set it when calling from outside this object.
  658. HX_RESULT
  659. XMLConfig::Read(char* filename, 
  660. char* pServRegKey, 
  661. BOOL  bIncludedFile)
  662. {
  663.     HX_RESULT hResult = HXR_OK;
  664.     FILE* fp=0;
  665.     XMLParser parser;
  666.     XMLTag*   tag = 0;
  667.     CBigByteQueue queue(MAX_TAG_SIZE);
  668.     int l=0;
  669.     BOOL filedone = FALSE;
  670.     UINT32 indent = 0;
  671.     HX_ASSERT(filename && strlen(filename));
  672.     HX_VECTOR_DELETE(m_filename);
  673.     m_filename = new_string(filename);
  674.     fp = fopen(filename, "r");
  675.     if (!fp)
  676.     {
  677. ERRMSG(m_pMessages, "%s: file not found", filename);
  678. return HXR_FILE_NOT_FOUND;
  679.     }
  680.     if(!m_pList)
  681.     {
  682. m_pList = new XMLConfigList;
  683. m_pList->m_parentnode = new XMLConfigListNode;
  684. m_pList->m_parentnode->m_name = new_string(pServRegKey);
  685. m_pList->m_parentnode->m_parent = NULL;
  686.     }
  687.     // read the config file into the byte queue
  688.     INT32 nBufSize = 16384;
  689.     BYTE* pBuf = new BYTE[nBufSize];
  690.     while (!filedone && hResult == HXR_OK)
  691.     {
  692.         l = fread(pBuf, 1, nBufSize, fp);
  693.         if (l > 0)
  694.         {
  695.     if (!queue.EnQueue(pBuf, l))
  696.             {
  697.                 if (!queue.Grow(l))
  698.                 {
  699.                     ERRMSG(m_pMessages,
  700.                            "error expanding data structure while parsing %s",
  701.                            filename);
  702.                     hResult = HXR_FAIL;
  703.                 }
  704.                 if (!queue.EnQueue(pBuf, l))
  705.                 {
  706.                     ERRMSG(m_pMessages,
  707.                            "unknown error while parsing %s",
  708.                            filename);
  709.                     hResult = HXR_FAIL;
  710.                 }
  711.             }
  712.         }
  713.         else
  714.         {
  715.          filedone = TRUE;
  716.         }
  717.     }
  718.     UINT32 bytesUsed=0;
  719.     UINT32 bytesAvail=0;
  720.     BYTE* p=0;
  721.     while (hResult == HXR_OK && (bytesAvail = queue.GetQueuedItemCount()) > 0)
  722.     {
  723. if (bytesAvail > nBufSize)
  724.         {
  725.             HX_VECTOR_DELETE(pBuf);
  726.             pBuf = new BYTE[bytesAvail];
  727.             nBufSize = bytesAvail;
  728.         }
  729. p = pBuf;
  730. queue.DeQueue(pBuf, bytesAvail);
  731. bytesUsed = bytesAvail;
  732.         HX_DELETE(tag);
  733. XMLParseResult res = parser.Parse((const char*&)p, bytesAvail, tag);
  734. queue.EnQueue(p, bytesAvail - (p - pBuf));
  735. switch(res)
  736. {
  737.     case XMLPNoClose:
  738. // A tag opener was found, but no closer yet.
  739. if (filedone)
  740. {
  741.     pBuf[bytesAvail - 1] = '';
  742.     if (bytesAvail > MAX_ERROR_CHARS)
  743.     {
  744. pBuf[MAX_ERROR_CHARS - 1] = '';
  745.     }
  746.     ERRMSG(m_pMessages,
  747.     "%s: Missing close for tag '%s'...", m_filename, pBuf);
  748.     hResult = HXR_FAIL;
  749. }
  750. break;
  751.     case XMLPNoTagType:
  752. *p = 0;
  753. ERRMSG(m_pMessages,
  754.        "%s: Badly formed tag '%s'", m_filename, pBuf);
  755. break;
  756.     case XMLPBadAttribute:
  757. *p = 0;
  758. ERRMSG(m_pMessages,
  759.        "%s: Badly formed attribute in '%s'", m_filename,
  760.        pBuf);
  761. break;
  762.     case XMLPPlainText:
  763. //Some text.  What do we care?
  764. break;
  765.     case XMLPBadEndTag:
  766. *p = 0;
  767. ERRMSG(m_pMessages,
  768.        "%s: Unexpected end tag '</%s>'", m_filename, tag->m_name);
  769. hResult = HXR_FAIL;
  770. break;
  771.     case XMLPComment:
  772. // A comment, fine.
  773. if(tag != NULL)
  774. {
  775.     //Some kind of comment directive
  776.     XMLAttribute* pAttr = tag->attribute(0);
  777.     if(pAttr &&
  778. pAttr->name)
  779.     {
  780. if(strcasecmp(pAttr->name, "include") == 0)
  781. {
  782.     char* path;
  783.     char* newfile = new char[1024];
  784.     if(!strchr(tag->attribute(0)->value, 
  785.        OS_SEPARATOR_CHAR) &&
  786.        ((path = strrchr(m_filename, OS_SEPARATOR_CHAR))
  787. != NULL))
  788.     {
  789. path++;
  790.                                 if (path - m_filename < 1024)
  791.                                 {
  792.                                     strncpy(newfile, m_filename, path - m_filename);
  793.                                     newfile[path - m_filename] = '';
  794.                                 }
  795. SafeStrCat(newfile, tag->attribute(0)->value, 1024);
  796.     }
  797.     else
  798.     {
  799. SafeStrCpy(newfile, tag->attribute(0)->value, 1024);
  800.     }
  801.     char* filename = m_filename;
  802.     m_filename = NULL;
  803.     Read(newfile, pServRegKey, TRUE);
  804.     delete[] m_filename;
  805.     m_filename = filename;
  806.                             delete[] newfile;
  807. }
  808.     }
  809. }
  810. break;
  811.     case XMLPDirective:
  812. // A directive.  We don't handle any yet.
  813. break;
  814.     case XMLPProcInst:
  815. // A processing Instruction, whee!
  816. break;
  817.     case XMLPTag:
  818.     {
  819. if(Expand(tag, &queue))
  820.     break;
  821. XMLConfigListNode* node = new XMLConfigListNode;
  822. node->m_parent = m_pList->m_parentnode;
  823. node->m_vserver = m_vserver;
  824. if(tag->m_need_close)
  825. {
  826.     if(strcasecmp(tag->m_name, "list") == 0)
  827.     {
  828. const char* name = tag->get_attribute("name");
  829. if(!name)
  830. {
  831.     ERRMSG(m_pMessages,
  832.    "%s: List tag requires a name attribute",
  833.    m_filename);
  834.     // Process anyway, give it a dummy name
  835.     name = "XXXBADLIST";
  836. }
  837. node->m_type = CfgList;
  838. node->m_name = new_string(name);
  839. node->m_num = tag->elem;
  840. m_pList->AddTail(node);
  841. m_pListStack.Push(m_pList);
  842. node->m_pList = new XMLConfigList;
  843. m_pList = node->m_pList;
  844. m_pList->m_parentnode = node;
  845.     }
  846.     else if(strcasecmp(tag->m_name, "server") == 0)
  847.     {
  848. const char* server = tag->get_attribute("number");
  849. if(!server)
  850. {
  851.     ERRMSG(m_pMessages,
  852.    "%s: Server tag requires a number, defaulting to 0",
  853.    m_filename);
  854.     m_vserver = 0;
  855. }
  856. else
  857. {
  858.     char vserver_str[64]; /* Flawfinder: ignore */
  859.     m_vserver = atol(server);
  860.     sprintf(vserver_str, "server%ld", m_vserver); /* Flawfinder: ignore */
  861.     if(m_pRegistry->GetTypeByName(vserver_str) == PT_UNKNOWN)
  862.     {
  863. m_pRegistry->AddComp(vserver_str);
  864. sprintf(vserver_str, "server%ld.config", /* Flawfinder: ignore */
  865. m_vserver);
  866. m_pRegistry->AddComp(vserver_str);
  867.     }
  868. }
  869.     }
  870. }
  871. else if(tag->m_type != XMLEndTag)
  872. {
  873.     const char* name = tag->get_attribute("name");
  874.     const char* value = tag->get_attribute("value");
  875.     if(name && value)
  876.     {
  877. node->m_type  = CfgVar;
  878. node->m_name  = new_string(name);
  879. node->m_value = new_string(value);
  880. node->m_num   = tag->elem;
  881. m_pList->AddTail(node);
  882.     }
  883. }
  884. else
  885. {
  886.     // An End Tag
  887.     if(strcasecmp(tag->m_name, "list") == 0)
  888.     {
  889. m_pList = (XMLConfigList*)m_pListStack.Pop();
  890.     }
  891.     else if(strcasecmp(tag->m_name, "server") == 0)
  892.     {
  893. if(m_vserver < 0)
  894. {
  895.     ERRMSG(m_pMessages,
  896.    "%s: </Server> Tag with no matching <Server>",
  897.    m_filename);
  898. }
  899. else
  900. {
  901.     m_vserver = -1;
  902. }
  903.     }
  904. }
  905. break;
  906.     }
  907. }
  908.     }
  909.     if(hResult == HXR_OK && !bIncludedFile)
  910.     {
  911. StuffRegistry(m_pList);
  912. delete m_pList->m_parentnode;
  913.     }
  914.     if (hResult == HXR_OK && !m_pListStack.IsEmpty())
  915.     {
  916.         ERRMSG(m_pMessages,
  917.    "%s: <List> tag with no matching </List>",
  918.    m_filename);
  919. hResult = HXR_FAIL;
  920.     }
  921.     // cleanup
  922.     if (fp) fclose(fp);
  923.     HX_VECTOR_DELETE(pBuf);
  924.     HX_DELETE(tag);
  925.     return hResult;
  926. }
  927. char*
  928. XMLConfig::XMLConfigListNode::get_registry_name(INT32 vserver)
  929. {
  930.     char* name;
  931.     if(m_parent)
  932.     {
  933. char* parentname = m_parent->get_registry_name(
  934.     vserver < 0 ? m_vserver : vserver);
  935. name = new char[strlen(parentname) + strlen(m_name) + 2];
  936. sprintf(name, "%s.%s", parentname, m_name); /* Flawfinder: ignore */
  937. delete [] parentname;
  938. return name;
  939.     }
  940.     else
  941.     {
  942. if(vserver >= 0)
  943. {
  944.     name = new char[26 + strlen(m_name) + 2];
  945.     sprintf(name, "server%ld.%s", vserver, m_name); /* Flawfinder: ignore */
  946. }
  947. else
  948. {
  949.     name = new_string(m_name);
  950. }
  951. return name;
  952.     }
  953. }
  954. ///XXXPM This func does not correctly handle the original file not
  955. ///being there.
  956. HX_RESULT
  957. XMLConfig::WriteToFile(const char* pKeyName, const char* pFileName)
  958. {
  959.     UINT32 ulListsToIgnore = 0;
  960.     /*
  961.      * Make sure we have a valid file name to use.
  962.      */
  963.     if (!pFileName)
  964.     {
  965. return HXR_FAIL;
  966.     }
  967.     /*
  968.      * Copy filename to filename.bak.
  969.      */
  970.     char *pNewFileName = new char[strlen(pFileName) + strlen(".bak") + 1];
  971.     sprintf(pNewFileName, "%s.bak", pFileName); /* Flawfinder: ignore */
  972.     FILE* fpOld = fopen(pFileName, "r");
  973.     FILE* fpNew = fopen(pNewFileName, "w");
  974.     if (!fpNew || !fpOld)
  975.     {
  976. HX_VECTOR_DELETE(pNewFileName);
  977. if (fpNew) fclose(fpNew);
  978. if (fpOld) fclose(fpOld);
  979. return HXR_FAIL;
  980.     }
  981.     INT32 nBufSize=16384;
  982.     BYTE* pBuf = new BYTE[nBufSize];
  983.     int iGot = 0;
  984.     while (!feof(fpOld))
  985.     {
  986. iGot = fread(pBuf, sizeof(char), nBufSize, fpOld);
  987. if (iGot)
  988. {
  989.     fwrite(pBuf, sizeof(char), iGot, fpNew);
  990. }
  991.     }
  992.     fclose(fpNew);
  993.     fclose(fpOld);
  994. #ifdef _UNIX
  995.     chmod(pNewFileName, 0700);
  996. #endif //UNIX
  997.     fpNew = fopen(pFileName, "w");
  998.     fpOld = fopen(pNewFileName, "r");
  999.     HX_VECTOR_DELETE(pNewFileName);
  1000.     if (!fpNew || !fpOld)
  1001.     {
  1002. if (fpNew) fclose(fpNew);
  1003. if (fpOld) fclose(fpOld);
  1004. return HXR_FAIL;
  1005.     }
  1006.     int l;
  1007.     BOOL filedone = 0;
  1008.     XMLTag*   tag = 0;
  1009.     XMLTag*   wspacetag = 0;
  1010.     CBigByteQueue queue(MAX_TAG_SIZE);
  1011.     XMLParser parser;
  1012.     HX_RESULT hResult = HXR_OK;
  1013.     /*
  1014.      * Files are all aready.  Now we need to build our config levels list.
  1015.      */
  1016.     CHXSimpleList levlist;
  1017.     /*
  1018.      *  Add for level 0.
  1019.      */
  1020.     CHXSimpleList* pNewList = new CHXSimpleList;
  1021.     IHXValues* pValues = 0;
  1022.     _AddPropsToList(pNewList, pKeyName, m_pRegistry);
  1023.     XMLConfigString curr_level;
  1024.     curr_level.AddLevel(pKeyName);
  1025.     while (!filedone && hResult == HXR_OK)
  1026.     {
  1027.         l = fread(pBuf, 1, nBufSize, fpOld);
  1028.         if (l > 0)
  1029.         {
  1030.             if (!queue.EnQueue(pBuf, l))
  1031.             {
  1032.                 if (!queue.Grow(l))
  1033.                 {
  1034.                     ERRMSG(m_pMessages,
  1035.                            "error expanding data structure while parsing");
  1036.                     hResult = HXR_FAIL;
  1037.                 }
  1038.                 if (!queue.EnQueue(pBuf, l))
  1039.                 {
  1040.                     ERRMSG(m_pMessages,
  1041.                            "unknown error while parsing");
  1042.                     hResult = HXR_FAIL;
  1043.                 }
  1044.             }
  1045.         }
  1046.         else
  1047.         {
  1048.             filedone = TRUE;
  1049.         }
  1050.     }
  1051.     UINT32 bytesUsed=0;
  1052.     UINT32 bytesAvail=0;
  1053.     BYTE* p=0;
  1054.     while (hResult == HXR_OK && (bytesAvail = queue.GetQueuedItemCount()) > 0)
  1055.     {
  1056. if (bytesAvail > nBufSize)
  1057.         {
  1058.             HX_VECTOR_DELETE(pBuf);
  1059.             pBuf = new BYTE[bytesAvail];
  1060.             nBufSize = bytesAvail;
  1061.         }
  1062. p = pBuf;
  1063. queue.DeQueue(pBuf, bytesAvail);
  1064. bytesUsed = bytesAvail;
  1065.         HX_DELETE(tag);
  1066. XMLParseResult res = parser.Parse((const char*&)p, bytesAvail, tag);
  1067. queue.EnQueue(p, bytesAvail - (p - pBuf));
  1068. switch(res)
  1069. {
  1070.     case XMLPNoClose:
  1071. // A tag opener was found, but no closer yet.
  1072. if (filedone)
  1073. {
  1074.     pBuf[bytesAvail - 1] = '';
  1075.     if (bytesAvail > MAX_ERROR_CHARS)
  1076.     {
  1077. pBuf[MAX_ERROR_CHARS - 1] = '';
  1078.     }
  1079.     ERRMSG(m_pMessages,
  1080.     "%s: Missing close for tag %s...", m_filename, pBuf);
  1081.     hResult = HXR_FAIL;
  1082. }
  1083. break;
  1084.     case XMLPNoTagType:
  1085. *p = 0;
  1086. ERRMSG(m_pMessages,
  1087.        "%s: Badly formed tag %s", m_filename, pBuf);
  1088. break;
  1089.     case XMLPBadAttribute:
  1090. *p = 0;
  1091. ERRMSG(m_pMessages,
  1092.        "%s: Badly formed attribute in %s", m_filename,
  1093.        pBuf);
  1094. break;
  1095.     case XMLPPlainText:
  1096. /* 
  1097.  * Just plaintext.  Dump this out directly.
  1098.  */
  1099. if (wspacetag)
  1100. {
  1101.     delete wspacetag;
  1102. }
  1103. wspacetag = tag;
  1104. tag = 0;
  1105. /*
  1106. fwrite(tag->m_cur_attribute->value, sizeof(char),
  1107.     strlen(tag->m_cur_attribute->value), fpNew);
  1108.     */
  1109. break;
  1110.     case XMLPBadEndTag:
  1111. *p = 0;
  1112. ERRMSG(m_pMessages,
  1113.        "%s: Unexpected tag %s", m_filename, pBuf);
  1114. break;
  1115.     case XMLPComment:
  1116. /*
  1117.  * Just a comment.  Dump it out.  Comment lives from
  1118.  * p to pBuf.
  1119.  */
  1120. if (wspacetag)
  1121. {
  1122.     fwrite(wspacetag->m_cur_attribute->value, sizeof(char),
  1123. strlen(wspacetag->m_cur_attribute->value), fpNew);
  1124.     delete wspacetag;
  1125.     wspacetag = 0;
  1126. }
  1127. fwrite(pBuf, sizeof(char), p - pBuf, fpNew);
  1128. break;
  1129.     case XMLPDirective:
  1130. // A directive.  We don't handle any yet.
  1131. break;
  1132.     case XMLPProcInst:
  1133.                 /*
  1134.  * Just dump processing instructions as we read them.
  1135.  */
  1136. if (wspacetag)
  1137. {
  1138.     fwrite(wspacetag->m_cur_attribute->value, sizeof(char),
  1139. strlen(wspacetag->m_cur_attribute->value), fpNew);
  1140.     delete wspacetag;
  1141.     wspacetag = 0;
  1142. }
  1143. fwrite(pBuf, sizeof(char), p - pBuf, fpNew);
  1144. break;
  1145.     case XMLPTag:
  1146.     {
  1147. if(Expand(tag, &queue))
  1148.     break;
  1149. if(tag->m_need_close)
  1150. {
  1151.     if(strcasecmp(tag->m_name, "list") == 0)
  1152.     {
  1153. if (ulListsToIgnore)
  1154. {
  1155.     ulListsToIgnore++;
  1156. }
  1157. else
  1158. {
  1159.     const char* name = tag->get_attribute("name");
  1160.     if(!name)
  1161.     {
  1162. ERRMSG(m_pMessages,
  1163.        "%s: List tag requires a name attribute",
  1164.        m_filename);
  1165. // Process anyway, give it a dummy name
  1166. name = "XXXBADLIST";
  1167.     }
  1168.     /*
  1169.      * Remove current tag from list, push current list,
  1170.      * create new list, add next level's props.
  1171.      */
  1172.     _RemovePropFromList(pNewList, name);
  1173.     curr_level.AddLevel(name);
  1174.     if (!_PropExists(&curr_level, m_pRegistry))
  1175.     {
  1176. curr_level.RemoveLevel();
  1177. ulListsToIgnore++;
  1178.     }
  1179.     else
  1180.     {
  1181. levlist.AddHead((void*)pNewList);
  1182. if (wspacetag)
  1183. {
  1184.     fwrite(wspacetag->m_cur_attribute->value, sizeof(char),
  1185. strlen(wspacetag->m_cur_attribute->value), fpNew);
  1186.     delete wspacetag;
  1187.     wspacetag = 0;
  1188. }
  1189. fprintf(fpNew, "<List Name="%s">", name);
  1190. pNewList = new CHXSimpleList;
  1191. _AddPropsToList(pNewList, curr_level.CharStar(), m_pRegistry);
  1192.     }
  1193. }
  1194.     }
  1195. }
  1196. else if(tag->m_type != XMLEndTag)
  1197. {
  1198.     if (!ulListsToIgnore)
  1199.     {
  1200. const char* name = tag->get_attribute("name");
  1201. const char* value = tag->get_attribute("value");
  1202. if (name)
  1203. {
  1204.     curr_level.AddLevel(name);
  1205.     _RemovePropFromList(pNewList, name);
  1206.     /*
  1207.      * Make sure this prop is still set.
  1208.      */
  1209.     if (_PropExists(&curr_level, m_pRegistry))
  1210.     {
  1211. if (wspacetag)
  1212. {
  1213.     fwrite(wspacetag->m_cur_attribute->value, sizeof(char),
  1214. strlen(wspacetag->m_cur_attribute->value), fpNew);
  1215.     delete wspacetag;
  1216.     wspacetag = 0;
  1217. }
  1218. char* p = _GetPropValueString(curr_level.CharStar(), m_pRegistry);
  1219. if (p)
  1220. {
  1221.     fprintf(fpNew, "<Var %s="%s"/>",
  1222. name,
  1223. p);
  1224.     delete[] p;
  1225. }
  1226.     }
  1227.     curr_level.RemoveLevel();
  1228. }
  1229.     }
  1230. }
  1231. else
  1232. {
  1233.     // An End Tag
  1234.     if(strcasecmp(tag->m_name, "list") == 0)
  1235.     {
  1236. if (ulListsToIgnore)
  1237. {
  1238.     ulListsToIgnore --;
  1239. }
  1240. else
  1241. {
  1242.     /*
  1243.      * Need to add the stuff at this level that was
  1244.      * was not in the config file.
  1245.      */
  1246.     if (pNewList->GetCount() == 0)
  1247.     {
  1248. if (wspacetag)
  1249. {
  1250.     fwrite(wspacetag->m_cur_attribute->value, sizeof(char),
  1251. strlen(wspacetag->m_cur_attribute->value), fpNew);
  1252. }
  1253.     }
  1254.     else
  1255.     {
  1256. fprintf(fpNew, "n");
  1257. AppendPropsToFile(fpNew, curr_level, pNewList,
  1258.     4, m_pRegistry, pKeyName);
  1259. _IndentFile(fpNew, 4, curr_level, pKeyName);
  1260.     }
  1261.     delete wspacetag;
  1262.     wspacetag = 0;
  1263.     fprintf(fpNew, "</List>");
  1264.     curr_level.RemoveLevel();
  1265.     delete pNewList;
  1266.     pNewList = (CHXSimpleList*)levlist.RemoveHead();
  1267. }
  1268.     }
  1269. }
  1270. break;
  1271.     }
  1272. }
  1273. // Give up if we've lost all hope
  1274. if (HXR_OK != hResult)
  1275. {
  1276.     break;
  1277. }
  1278.     }
  1279.     if (hResult == HXR_OK && wspacetag)
  1280.     {
  1281. fwrite(wspacetag->m_cur_attribute->value, sizeof(char),
  1282.     strlen(wspacetag->m_cur_attribute->value), fpNew);
  1283. delete wspacetag;
  1284. wspacetag = 0;
  1285.     }
  1286.     /*
  1287.      * Ok, done with the whole file. Make sure that all of the base level stuff
  1288.      * gets added.
  1289.      */
  1290.      //XXXPM Calculate this later.
  1291.     if (hResult == HXR_OK)
  1292.     {
  1293.         int indent = 4;
  1294.         AppendPropsToFile(fpNew, curr_level, pNewList, indent, m_pRegistry, pKeyName);
  1295.     }
  1296.     // cleanup
  1297.     if (fpNew) fclose(fpNew);
  1298.     if (fpOld) fclose(fpOld);
  1299.     HX_DELETE(pNewList);
  1300.     HX_VECTOR_DELETE(pBuf);
  1301.     HX_DELETE(tag);
  1302.     return hResult;
  1303. }
  1304. void
  1305. XMLConfig::_AddPropsToList(CHXSimpleList* pList, const char* pName,
  1306.   IHXRegistry2* preg)
  1307. {
  1308.     IHXValues* pValues = 0;
  1309.     UINT32 ul;
  1310.     const char* pPropName;
  1311.     preg->GetPropListByName(pName, pValues);
  1312.     if (pValues)
  1313.     {
  1314. if (HXR_OK == pValues->GetFirstPropertyULONG32(pPropName, ul))
  1315. {
  1316.     XMLPropInfo* pInfo = new XMLPropInfo;
  1317.     pInfo->m_pName = new char[strlen(pPropName) + 1 - strlen(pName)];
  1318.     strcpy(pInfo->m_pName, &(pPropName[strlen(pName) + 1])); /* Flawfinder: ignore */
  1319.     pInfo->m_Type = preg->GetTypeByName(pPropName);
  1320.     pList->AddHead((void*)pInfo);
  1321.     while (HXR_OK == pValues->GetNextPropertyULONG32(pPropName, ul))
  1322.     {
  1323. XMLPropInfo* pInfo = new XMLPropInfo;
  1324. pInfo->m_pName = new char[strlen(pPropName) + 1 - strlen(pName)];
  1325. strcpy(pInfo->m_pName, &(pPropName[strlen(pName) + 1]));
  1326. pInfo->m_Type = preg->GetTypeByName(pPropName);
  1327. pList->AddHead((void*)pInfo);
  1328.     }
  1329. }
  1330. pValues->Release();
  1331.     }
  1332. }
  1333. void
  1334. XMLConfig::_RemovePropFromList(CHXSimpleList* pList, const char* pName)
  1335. {
  1336.     LISTPOSITION pos;
  1337.     pos = pList->GetHeadPosition();
  1338.     XMLPropInfo* pProp;
  1339.     
  1340.     while (pos)
  1341.     {
  1342. pProp = (XMLPropInfo*)pList->GetAt(pos);
  1343. if (!pProp)
  1344. {
  1345.     return;
  1346. }
  1347. if (!strcasecmp(pProp->m_pName, pName))
  1348. {
  1349.     pList->RemoveAt(pos);
  1350.     delete pProp;
  1351.     return;
  1352. }
  1353. pList->GetNext(pos);
  1354.     }
  1355. }
  1356. char*
  1357. XMLConfig::_GetPropValueString(const char* pName, IHXRegistry2* pReg)
  1358. {
  1359.     int vartype;
  1360.     IHXBuffer* pBuffer;
  1361.     INT32 l;
  1362.     char* ret;
  1363.     vartype = pReg->GetTypeByName(pName);
  1364.     if(vartype == PT_INTEGER)
  1365.     {
  1366. if(HXR_OK == pReg->GetIntByName(pName, l))
  1367. {
  1368.     char num[32]; /* Flawfinder: ignore */
  1369.     sprintf(num, "%d", l); /* Flawfinder: ignore */
  1370.     ret = new char[strlen(num) + 1];
  1371.     strcpy(ret, num); /* Flawfinder: ignore */
  1372.     return ret;
  1373. }
  1374. else
  1375. {
  1376.     return 0;
  1377. }
  1378.     }
  1379.     else if(vartype == PT_STRING)
  1380.     {
  1381. if(HXR_OK == pReg->GetStrByName(pName,
  1382.     pBuffer) && pBuffer)
  1383. {
  1384.     ret = new char[pBuffer->GetSize()+1];
  1385.     strcpy(ret, (const char*)pBuffer->GetBuffer()); /* Flawfinder: ignore */
  1386.     pBuffer->Release();
  1387.     return ret;
  1388. }
  1389. else
  1390. {
  1391.     return 0;
  1392. }
  1393.     }
  1394.     return 0;
  1395. }
  1396. void
  1397. XMLConfig::_CleanList(CHXSimpleList* pList)
  1398. {
  1399.     XMLPropInfo* pInfo;
  1400.     while (!pList->IsEmpty())
  1401.     {
  1402. pInfo = (XMLPropInfo*)pList->RemoveHead();
  1403. delete pInfo;
  1404.     }
  1405. }
  1406. void
  1407. XMLConfig::AppendPropsToFile(FILE* fp, XMLConfigString level,
  1408.     CHXSimpleList* pList, int indent_per_level,
  1409.     IHXRegistry2* hxreg, const char* pBase)
  1410. {
  1411.     XMLPropInfo* pInfo = 0;
  1412.     while (!pList->IsEmpty())
  1413.     {
  1414. pInfo = (XMLPropInfo*)pList->RemoveHead();
  1415. level.AddLevel(pInfo->m_pName);
  1416. _AppendPropToFile(fp, level, indent_per_level, hxreg, pBase);
  1417. level.RemoveLevel();
  1418. delete pInfo;
  1419.     }
  1420. }
  1421. void
  1422. XMLConfig::_IndentFile(FILE* fp, int indent_per_level,
  1423.  XMLConfigString level,
  1424.  const char* pBase)
  1425. {
  1426.     int dots_to_ignore = 1;
  1427.     INT32 i;
  1428.     const char* pc;
  1429.     pc = pBase;
  1430.     while (*pc)
  1431.     {
  1432. if (*pc == '.')
  1433. {
  1434.     dots_to_ignore ++;
  1435. }
  1436. pc++;
  1437.     }
  1438.     pc = level.CharStar();
  1439.     while (*pc)
  1440.     {
  1441. if (*pc == '.')
  1442. {
  1443.     if (dots_to_ignore)
  1444.     {
  1445. dots_to_ignore--;
  1446.     }
  1447.     else
  1448.     {
  1449. for (i = 0; i < indent_per_level; i++)
  1450. {
  1451.     fprintf(fp, " ");
  1452. }
  1453.     }
  1454. }
  1455. pc ++;
  1456.     }
  1457. }
  1458. void
  1459. XMLConfig::_AppendPropToFile(FILE* fp, XMLConfigString level,
  1460.      int indent_per_level,
  1461.      IHXRegistry2* hxreg,
  1462.      const char* pBase)
  1463. {
  1464.     /*
  1465.      * Indent a proper amount.
  1466.      */
  1467.     INT32 i;
  1468.     IHXBuffer* pBuf = 0;
  1469.     _IndentFile(fp, indent_per_level, level, pBase);
  1470.     HXPropType type = hxreg->GetTypeByName(level.CharStar());
  1471.     switch (type)
  1472.     {
  1473.     case PT_COMPOSITE:
  1474. fprintf(fp, "<List Name="%s">n", level.Top());
  1475. IHXValues* pValues;
  1476. if (HXR_OK == hxreg->GetPropListByName(level.CharStar(),
  1477.     pValues) && pValues)
  1478. {
  1479.     HX_RESULT res;
  1480.     UINT32 ul;
  1481.     const char* pName;
  1482.     res = pValues->GetFirstPropertyULONG32(pName, ul);
  1483.     while (res == HXR_OK)
  1484.     {
  1485. const char* pc = pName + strlen(pName);
  1486. while (pc > pName)
  1487. {
  1488.     pc--;
  1489.     if (*pc == '.')
  1490.     {
  1491. pc++;
  1492. level.AddLevel(pc);
  1493. _AppendPropToFile(fp, level, indent_per_level, hxreg, pBase);
  1494. level.RemoveLevel();
  1495. res = pValues->GetNextPropertyULONG32(pName, ul);
  1496. break;
  1497.     }
  1498. }
  1499.     }
  1500.     pValues->Release();
  1501. }
  1502. _IndentFile(fp, indent_per_level, level, pBase);
  1503. fprintf(fp, "</List>n");
  1504. break;
  1505.     case PT_INTEGER:
  1506. if (HXR_OK == hxreg->GetIntByName(level.CharStar(), i))
  1507. {
  1508.     fprintf(fp, "<Var %s="%ld"/>n", level.Top(),
  1509. i);
  1510. }
  1511. break;
  1512.     case PT_STRING:
  1513. if (HXR_OK == hxreg->GetStrByName(level.CharStar(), pBuf)
  1514.     && pBuf)
  1515. {
  1516.     fprintf(fp, "<Var %s="%s"/>n", level.Top(),
  1517. (const char*)pBuf->GetBuffer());
  1518.     pBuf->Release();
  1519.     pBuf = 0;
  1520. }
  1521. break;
  1522.     }
  1523. }
  1524. int
  1525. XMLConfig::_PropExists(XMLConfigString* p, IHXRegistry2* preg)
  1526. {
  1527.     return (preg->GetPropStatusByName(p->CharStar()) == HXR_OK) ? TRUE : FALSE;
  1528. }
  1529. /*
  1530.  * IHXRegConfig::WriteKey
  1531.  */
  1532. STDMETHODIMP
  1533. XMLConfig::WriteKey(const char* pKeyName)
  1534. {
  1535.     /*
  1536.      * If there is a filename then we got it from a file.
  1537.      */
  1538.     if (m_filename)
  1539.     {
  1540. WriteToFile(pKeyName, m_filename);
  1541. return HXR_OK;
  1542.     }
  1543.     HX_ASSERT(0);
  1544.     return HXR_FAIL;
  1545. }
  1546. HX_RESULT
  1547. XMLConfig::Reconfigure(IHXReconfigServerResponse* pResp)
  1548. {
  1549.     if (m_pReconfigureResponse)
  1550.     {
  1551. return HXR_UNEXPECTED;
  1552.     }
  1553.     m_pReconfigureResponse = pResp;
  1554.     m_pReconfigureResponse->AddRef();
  1555.     /*
  1556.      * If they started from a config file, then reload
  1557.      * from the config file.
  1558.      */
  1559.     if (m_filename)
  1560.     {
  1561. return Reconfigure(m_filename);
  1562.     }
  1563.     /*
  1564.      * If we got here there was a booboo
  1565.      */
  1566.     m_pReconfigureResponse->ReconfigServerDone(HXR_OK, 0, 0);
  1567.     m_pReconfigureResponse->Release();
  1568.     m_pReconfigureResponse = 0;
  1569.     return HXR_OK;
  1570. }
  1571. HX_RESULT
  1572. XMLConfig::Reconfigure(const char* pFileName)
  1573. {
  1574.     if (!pFileName)
  1575.     {
  1576. return HXR_FAIL;
  1577.     }
  1578.     FILE* fp = fopen(pFileName, "r");
  1579.     if (!fp)
  1580.     {
  1581. return HXR_FAIL;
  1582.     }
  1583.     /*
  1584.      * Pretend that there is one outstanding just to keep
  1585.      * the done methods from getting called, seeing a 0,
  1586.      * and sending the response until the end of this 
  1587.      * func.
  1588.      */
  1589.     m_ActiveSetsOutstanding++;
  1590.     const char* pKeyName = "config";
  1591.     int l = 0;
  1592.     BOOL filedone = 0;
  1593.     XMLTag*   tag = 0;
  1594.     CBigByteQueue queue(MAX_TAG_SIZE);
  1595.     XMLParser parser;
  1596.     HX_RESULT hResult = HXR_OK;
  1597.     /*
  1598.      * Files are all aready.  Now we need to build our config levels list.
  1599.      */
  1600.     CHXSimpleList levlist;
  1601.     /*
  1602.      *  Add for level 0.
  1603.      */
  1604.     CHXSimpleList* pNewList = new CHXSimpleList;
  1605.     IHXValues* pValues = 0;
  1606.     _AddPropsToList(pNewList, pKeyName, m_pRegistry);
  1607.     XMLConfigString curr_level;
  1608.     curr_level.AddLevel(pKeyName);
  1609.     // read the config file into the byte queue
  1610.     INT32 nBufSize = 16384;
  1611.     BYTE* pBuf = new BYTE[nBufSize];
  1612.     while (!filedone && hResult == HXR_OK)
  1613.     {
  1614.         l = fread(pBuf, 1, nBufSize, fp);
  1615.         if (l > 0)
  1616.         {
  1617.             if (!queue.EnQueue(pBuf, l))
  1618.             {
  1619.                 if (!queue.Grow(l))
  1620.                 {
  1621.                     ERRMSG(m_pMessages,
  1622.                            "error expanding data structure while parsing %s",
  1623.                            pFileName);
  1624.                     hResult = HXR_FAIL;
  1625.                 }
  1626.                 if (!queue.EnQueue(pBuf, l))
  1627.                 {
  1628.                     ERRMSG(m_pMessages,
  1629.                            "unknown error while parsing %s",
  1630.                            pFileName);
  1631.                     hResult = HXR_FAIL;
  1632.                 }
  1633.             }
  1634. }
  1635. else
  1636. {
  1637.             filedone = TRUE;
  1638. }
  1639.     }
  1640.     UINT32 bytesUsed=0;
  1641.     UINT32 bytesAvail=0;
  1642.     BYTE* p=0;
  1643.     while (hResult == HXR_OK && (bytesAvail = queue.GetQueuedItemCount()) > 0)
  1644.     {
  1645. if (bytesAvail > nBufSize)
  1646.         {
  1647.             HX_VECTOR_DELETE(pBuf);
  1648.             pBuf = new BYTE[bytesAvail];
  1649.             nBufSize = bytesAvail;
  1650.         }
  1651. p = pBuf;
  1652. queue.DeQueue(pBuf, bytesAvail);
  1653. bytesUsed = bytesAvail;
  1654.         HX_DELETE(tag);
  1655. XMLParseResult res = parser.Parse((const char*&)p, bytesAvail, tag);
  1656. queue.EnQueue(p, bytesAvail - (p - pBuf));
  1657. switch(res)
  1658. {
  1659.     case XMLPNoClose:
  1660. // A tag opener was found, but no closer yet.
  1661. if (filedone)
  1662. {
  1663.     pBuf[bytesAvail - 1] = '';
  1664.     if (bytesAvail > MAX_ERROR_CHARS)
  1665.     {
  1666. pBuf[MAX_ERROR_CHARS - 1] = '';
  1667.     }
  1668.     ERRMSG(m_pMessages,
  1669.     "%s: Missing close for tag %s...", m_filename, pBuf);
  1670.     hResult = HXR_FAIL;
  1671. }
  1672. break;
  1673.     case XMLPNoTagType:
  1674. *p = 0;
  1675. ERRMSG(m_pMessages,
  1676.        "%s: Badly formed tag %s", m_filename, pBuf);
  1677. break;
  1678.     case XMLPBadAttribute:
  1679. *p = 0;
  1680. ERRMSG(m_pMessages,
  1681.        "%s: Badly formed attribute in %s", m_filename,
  1682.        pBuf);
  1683. break;
  1684.     case XMLPPlainText:
  1685. break;
  1686.     case XMLPBadEndTag:
  1687. *p = 0;
  1688. ERRMSG(m_pMessages,
  1689.        "%s: Unexpected tag %s", m_filename, pBuf);
  1690. break;
  1691.     case XMLPComment:
  1692. break;
  1693.     case XMLPDirective:
  1694. // A directive.  We don't handle any yet.
  1695. break;
  1696.     case XMLPProcInst:
  1697. // A processing Instruction, whee!
  1698. break;
  1699.     case XMLPTag:
  1700.     {
  1701. if(Expand(tag, &queue))
  1702.     break;
  1703. if(tag->m_need_close)
  1704. {
  1705.     if(strcasecmp(tag->m_name, "list") == 0)
  1706.     {
  1707. const char* name = tag->get_attribute("name");
  1708. if(!name)
  1709. {
  1710.     ERRMSG(m_pMessages,
  1711.    "%s: List tag requires a name attribute",
  1712.    m_filename);
  1713.     // Process anyway, give it a dummy name
  1714.     name = "XXXBADLIST";
  1715. }
  1716. /*
  1717.  * Remove current tag from list, push current list,
  1718.  * create new list, add next level's props.
  1719.  */
  1720. _RemovePropFromList(pNewList, name);
  1721. curr_level.AddLevel(name);
  1722. levlist.AddHead((void*)pNewList);
  1723. pNewList = new CHXSimpleList;
  1724. _AddPropsToList(pNewList, curr_level.CharStar(), m_pRegistry);
  1725.     }
  1726. }
  1727. else if(tag->m_type != XMLEndTag)
  1728. {
  1729.     const char* name = tag->get_attribute("name");
  1730.     const char* value = tag->get_attribute("value");
  1731.     if (name)
  1732.     {
  1733. curr_level.AddLevel(name);
  1734. _RemovePropFromList(pNewList, name);
  1735. /*
  1736.  * Here we need to try to set that value.
  1737.  */
  1738. _ResetProp(&curr_level, value, m_pRegistry);
  1739. curr_level.RemoveLevel();
  1740.     }
  1741. }
  1742. else
  1743. {
  1744.     // An End Tag
  1745.     /*
  1746.      * Here we need to try to delete everything that
  1747.      * was not in the file.
  1748.      */
  1749.     if(strcasecmp(tag->m_name, "list") == 0)
  1750.     {
  1751. _HandlePropsRemovedFromFile(
  1752.     &curr_level, pNewList,
  1753.     m_pRegistry);
  1754. curr_level.RemoveLevel();
  1755. delete pNewList;
  1756. pNewList = (CHXSimpleList*)levlist.RemoveHead();
  1757.     }
  1758. }
  1759. break;
  1760.     }
  1761. }
  1762.     }
  1763.     
  1764.     _HandlePropsRemovedFromFile(&curr_level, pNewList, m_pRegistry);
  1765.     // cleanup
  1766.     if (fp) fclose(fp);
  1767.     HX_DELETE(tag);
  1768.     HX_DELETE(pNewList);
  1769.     HX_VECTOR_DELETE(pBuf);
  1770.     // send reconfig response
  1771.     m_ActiveSetsOutstanding--;
  1772.     MaybeSendReconfigResponse();
  1773.     return hResult;
  1774. }
  1775. #ifdef _WIN32
  1776. HX_RESULT
  1777. XMLConfig::ReconfigureFromReg(const char* pKeyname)
  1778. {
  1779.     HX_ASSERT(pKeyname && strlen(pKeyname));
  1780.     /* 
  1781.      * This should be a duplication of the above loop just using
  1782.      * the registry instead of a file.
  1783.      */
  1784.     /*
  1785.      * Pretend that there is one outstanding just to keep
  1786.      * the done methods from getting called, seeing a 0,
  1787.      * and sending the response until the end of this 
  1788.      * func.
  1789.      */
  1790.     m_ActiveSetsOutstanding++;
  1791.     CHXSimpleList levlist;
  1792.     CHXSimpleList indexlist;
  1793.     int curr_index = 0;
  1794.     UINT32 ulBufLen = 512;
  1795.     UINT32 ulRealBufLen = 512;
  1796.     char* pRegBuf = new char[512];
  1797.     UINT32 ulBufLen2 = 256;
  1798.     UINT32 ulRealBufLen2 = 256;
  1799.     char* pRegBuf2 = new char[256];
  1800.     UINT32 ulBufLen3 = 256;
  1801.     UINT32 ulRealBufLen3 = 256;
  1802.     char* pRegBuf3 = new char[256];
  1803.     FILETIME msbs;
  1804.     /*
  1805.      *  Add for level 0.
  1806.      */
  1807.     CHXSimpleList* pNewList = new CHXSimpleList;
  1808.     IHXValues* pValues = 0;
  1809.     _AddPropsToList(pNewList, "Config", m_pRegistry);
  1810.     XMLConfigString curr_level;
  1811.     curr_level.AddLevel("Config");
  1812.     char* pRegBase = new char[512];
  1813.     memset(pRegBase, 0, 512);
  1814.     SafeSprintf(pRegBase, 512, "Software\RealNetworks\%s\%d.%d\",
  1815.             m_szServerversion, m_ulMajor, m_ulMinor);
  1816.     UINT32 ulRegBase = strlen(pRegBase) + 1;
  1817.     HKEY hKey=0;
  1818.     LONG ret=0;
  1819.     BOOL bDone = 0;
  1820.     char* pc=0;
  1821.     /*
  1822.      * While we are not done...
  1823.      */
  1824.     while (!bDone)
  1825.     {
  1826. pc = pRegBase + ulRegBase;
  1827. SafeStrCpy(pc, curr_level.CharStar(), 512-ulRegBase);
  1828. while (pc < pRegBase + 512 && *pc)
  1829. {
  1830.     if (*pc == '.')
  1831.     {
  1832. *pc = '\';
  1833.     }
  1834.     pc++;
  1835. }
  1836. ret = RegOpenKeyEx(HKEY_CLASSES_ROOT, pRegBase, 0, KEY_READ, &hKey);
  1837. if (ret != ERROR_SUCCESS)
  1838. {
  1839.     //XXXPM fix this
  1840.     HX_ASSERT(0);
  1841. }
  1842. ulBufLen = ulRealBufLen;
  1843. //XXXPM handle buffer too small
  1844. ret = RegEnumKeyEx(hKey, curr_index,
  1845.     pRegBuf, &ulBufLen, 0, NULL, NULL, &msbs);
  1846. curr_index++;
  1847. /*
  1848.  * If it is a composite...
  1849.  */
  1850. if (ret == ERROR_SUCCESS)
  1851. {
  1852.     const char* name = pRegBuf;
  1853.     _RemovePropFromList(pNewList, name);
  1854.     curr_level.AddLevel(name);
  1855.     levlist.AddHead((void*)pNewList);
  1856.     indexlist.AddHead((void*)curr_index);
  1857.     curr_index = 0;
  1858.     pNewList = new CHXSimpleList;
  1859.     _AddPropsToList(pNewList, curr_level.CharStar(), m_pRegistry);
  1860. }
  1861. /*
  1862.  * It is a non composite value, so we need to get that value.
  1863.  */
  1864. else
  1865. {
  1866.     const char* name = pRegBuf;
  1867.     const char* value = 0;
  1868.     ulBufLen2 = ulRealBufLen2;
  1869.     ulBufLen3 = ulRealBufLen3;
  1870.     DWORD dwType;
  1871.     //XXXPM handle buffer too small
  1872.     ret = RegEnumValue(hKey, 0, pRegBuf2, &ulBufLen2, 0, &dwType, 
  1873.                (unsigned char*)pRegBuf3, &ulBufLen3);
  1874.     if (ret == ERROR_SUCCESS)
  1875.     {
  1876. value = pRegBuf3;
  1877. _ResetProp(&curr_level, value, m_pRegistry);
  1878. curr_level.RemoveLevel();
  1879. delete pNewList;
  1880. pNewList = (CHXSimpleList*)levlist.RemoveHead();
  1881. curr_index = (int)indexlist.RemoveHead();
  1882.     }
  1883.     else
  1884.     {
  1885. /*
  1886.  * Closing a composite.
  1887.  */
  1888. _HandlePropsRemovedFromFile(&curr_level, pNewList, m_pRegistry);
  1889. curr_level.RemoveLevel();
  1890. delete pNewList;
  1891. if (!levlist.IsEmpty())
  1892. {
  1893.     pNewList = (CHXSimpleList*)levlist.RemoveHead();
  1894.     curr_index = (int)indexlist.RemoveHead();
  1895. }
  1896. else
  1897. {
  1898.     pNewList = 0;
  1899.     bDone = 1;
  1900. }
  1901.     }
  1902. }
  1903. RegCloseKey(hKey);
  1904.     }
  1905.     delete[] pRegBase;
  1906.     delete[] pRegBuf;
  1907.     delete[] pRegBuf2;
  1908.     delete[] pRegBuf3;
  1909.     m_ActiveSetsOutstanding--;
  1910.     MaybeSendReconfigResponse();
  1911.     return HXR_OK;
  1912. }
  1913. #endif
  1914. HX_RESULT
  1915. XMLConfig::_ResetProp(XMLConfigString* plevel, const char* value, IHXRegistry2* preg)
  1916. {
  1917.     HX_RESULT res = HXR_FAIL;
  1918.     IHXActiveRegistry* pActiveReg = 0;
  1919.     LONG32 ulCurrent;
  1920.     LONG32 ulNew;
  1921.     preg->QueryInterface(IID_IHXActiveRegistry,
  1922. (void**)&pActiveReg);
  1923.     if (pActiveReg == 0)
  1924.     {
  1925. return HXR_FAIL;
  1926.     }
  1927.     /*
  1928.      * If the prop exists, then figure out the type.
  1929.      */
  1930.     if (_PropExists(plevel, preg))
  1931.     {
  1932. HXPropType type;
  1933. type = preg->GetTypeByName(plevel->CharStar());
  1934. switch (type)
  1935. {
  1936. case PT_INTEGER:
  1937.     ulCurrent = 0;
  1938.     ulNew = atoi(value);
  1939.     /*
  1940.      * If it is an int and we are not changing its value, then say ok and
  1941.      * exit.
  1942.      */
  1943.     preg->GetIntByName(plevel->CharStar(),
  1944. ulCurrent);
  1945.     if (ulCurrent == ulNew)
  1946.     {
  1947. res = HXR_OK;
  1948. goto done;
  1949.     }
  1950.     /*
  1951.      * Try to set it by hand first.
  1952.      */
  1953.     res = preg->SetIntByName(plevel->CharStar(),
  1954. atoi(value));
  1955.     /*
  1956.      * If it failed because it was active, then use the active reg
  1957.      * to set it and add it to our outstanding actives count.
  1958.      */
  1959.     if (res == HXR_PROP_ACTIVE)
  1960.     {
  1961. m_ActiveSetsOutstanding ++;
  1962. res = pActiveReg->SetActiveInt(plevel->CharStar(),
  1963.     ulNew, this);
  1964. if (res != HXR_OK)
  1965. {
  1966.     m_ActiveSetsOutstanding --;
  1967. }
  1968.     }
  1969.     /*
  1970.      * res should be set for good by now.
  1971.      */
  1972.     goto done;
  1973.     
  1974. case PT_STRING:
  1975.     IHXBuffer* pCurrent = 0;
  1976.     /*
  1977.      * See if we are changing this string value at all.
  1978.      */
  1979.     preg->GetStrByName(plevel->CharStar(),
  1980. pCurrent);
  1981.     if (pCurrent)
  1982.     {
  1983. /*
  1984.  * If we are not changing it at all then say ok and exit.
  1985.  */
  1986. if (!strcmp((const char*)pCurrent->GetBuffer(),
  1987.     value))
  1988. {
  1989.     pCurrent->Release();
  1990.     res = HXR_OK;
  1991.     goto done;
  1992. }
  1993. pCurrent->Release();
  1994.     }
  1995.     /*
  1996.      * We are changing it so get a new buffer and set it.
  1997.      */
  1998.     IHXBuffer* pBuffer = new CHXBuffer();
  1999.             pBuffer->AddRef();
  2000.     pBuffer->Set((const unsigned char*)value, strlen(value) + 1);
  2001.     res = preg->SetStrByName(plevel->CharStar(),
  2002. pBuffer);
  2003.     /*
  2004.      * If we failed to set it because it is active, then use the
  2005.      * active registry and add to our outstanding actives count.
  2006.      */
  2007.     if (res == HXR_PROP_ACTIVE)
  2008.     {
  2009. m_ActiveSetsOutstanding++;
  2010. res = pActiveReg->SetActiveStr(plevel->CharStar(),
  2011.     pBuffer, this);
  2012. if (res != HXR_OK)
  2013. {
  2014.     m_ActiveSetsOutstanding --;
  2015. }
  2016.     }
  2017.     pBuffer->Release();
  2018.     goto done;
  2019. }
  2020.     }
  2021.     else
  2022.     {
  2023. /*
  2024.  * This is the case where this prop was not already there,
  2025.  * so figure out the type from the data.
  2026.  */
  2027. BOOL bIsNum = TRUE;
  2028. const char* pc = value;
  2029. while(*pc)
  2030. {
  2031.     if (*pc < '0' || *pc > '9')
  2032.     {
  2033. bIsNum = FALSE;
  2034. break;
  2035.     }
  2036.     pc++;
  2037. }
  2038. if (pc == value)
  2039. {
  2040.     bIsNum = FALSE;
  2041. }
  2042. if (bIsNum)
  2043. {
  2044.     /*
  2045.      * It should be an Integer type so attempt to Set it through the
  2046.      * active reg.  (This acts like an add through the active reg.  Could
  2047.      * have tried to add it by hand first, but didn't.
  2048.      */
  2049.     m_ActiveSetsOutstanding++;
  2050.     res = pActiveReg->SetActiveInt(plevel->CharStar(),
  2051. atoi(value), this);
  2052.     if (res != HXR_OK)
  2053.     {
  2054. m_ActiveSetsOutstanding--;
  2055.     }
  2056. }
  2057. else
  2058. {
  2059.     /*
  2060.      * It should be a string type.  We will just try to do it through active.
  2061.      * (see last comment).
  2062.      */
  2063.     IHXBuffer* pBuffer = new CHXBuffer();
  2064.             pBuffer->AddRef();
  2065.     pBuffer->Set((const unsigned char*)value,
  2066. strlen(value) + 1);
  2067.     m_ActiveSetsOutstanding++;
  2068.     res = pActiveReg->SetActiveStr(plevel->CharStar(),
  2069. pBuffer, this);
  2070.     if (res != HXR_OK)
  2071.     {
  2072. m_ActiveSetsOutstanding--;
  2073.     }
  2074.     pBuffer->Release();
  2075. }
  2076.     }
  2077. done:;
  2078.     pActiveReg->Release();
  2079.     return res;
  2080. }
  2081. /************************************************************************
  2082.  * IHXActivePropUserResponse stuff.
  2083.  *
  2084.  * Called with status result on completion of set request.
  2085.  */
  2086. STDMETHODIMP
  2087. XMLConfig::SetActiveIntDone(HX_RESULT res,
  2088. const char* pName,
  2089. UINT32 ul,
  2090. IHXBuffer* pInfo[],
  2091. UINT32 ulNumInfo)
  2092. {
  2093.     m_ActiveSetsOutstanding--;
  2094.     MaybeSendReconfigResponse();
  2095.     return HXR_OK;
  2096. }
  2097. STDMETHODIMP
  2098. XMLConfig::SetActiveStrDone(HX_RESULT res,
  2099. const char* pName,
  2100. IHXBuffer* pBuffer,
  2101. IHXBuffer* pInfo[],
  2102. UINT32 ulNumInfo)
  2103. {
  2104.     m_ActiveSetsOutstanding--;
  2105.     MaybeSendReconfigResponse();
  2106.     return HXR_OK;
  2107. }
  2108. STDMETHODIMP
  2109. XMLConfig::SetActiveBufDone(HX_RESULT res,
  2110. const char* pName,
  2111. IHXBuffer* pBuffer,
  2112. IHXBuffer* pInfo[],
  2113. UINT32 ulNumInfo)
  2114. {
  2115.     m_ActiveSetsOutstanding--;
  2116.     MaybeSendReconfigResponse();
  2117.     return HXR_OK;
  2118. }
  2119. STDMETHODIMP
  2120. XMLConfig::DeleteActivePropDone(HX_RESULT res,
  2121. const char* pName,
  2122. IHXBuffer* pInfo[],
  2123. UINT32 ulNumInfo)
  2124. {
  2125.     m_ActiveSetsOutstanding--;
  2126.     MaybeSendReconfigResponse();
  2127.     return HXR_OK;
  2128. }
  2129. void
  2130. XMLConfig::MaybeSendReconfigResponse()
  2131. {
  2132.     /*
  2133.      * If everything has not happened yet,
  2134.      * then bail.
  2135.      */
  2136.     if (m_ActiveSetsOutstanding)
  2137.     {
  2138. return;
  2139.     }
  2140.     m_pReconfigureResponse->ReconfigServerDone(HXR_OK,
  2141. 0, 0);
  2142.     m_pReconfigureResponse->Release();
  2143.     m_pReconfigureResponse = 0;
  2144. }
  2145. void
  2146. XMLConfig::_HandlePropsRemovedFromFile(XMLConfigString* plevel,
  2147.        CHXSimpleList* pList,
  2148.        IHXRegistry2* preg)
  2149. {
  2150.     XMLPropInfo* pInfo;
  2151.     while (!pList->IsEmpty())
  2152.     {
  2153. pInfo = (XMLPropInfo*)pList->RemoveHead();
  2154. plevel->AddLevel(pInfo->m_pName);
  2155. switch (pInfo->m_Type)
  2156. {
  2157. case PT_STRING:
  2158.     {
  2159. IHXBuffer* pval;
  2160. pval = _GetDefaultValString(
  2161.     plevel->CharStar(), preg);
  2162. if (!pval)
  2163. {
  2164.     if (!preg->DeleteByName(
  2165. plevel->CharStar()))
  2166.     {
  2167. IHXActiveRegistry* pActiveReg = 0;
  2168. preg->QueryInterface(IID_IHXActiveRegistry,
  2169.     (void**)&pActiveReg);
  2170. if (pActiveReg)
  2171. {
  2172.     m_ActiveSetsOutstanding++;
  2173.     if (HXR_OK != pActiveReg->DeleteActiveProp(
  2174. plevel->CharStar(),
  2175. this))
  2176.     {
  2177. m_ActiveSetsOutstanding--;
  2178.     }
  2179.     pActiveReg->Release();
  2180. }
  2181.     }
  2182. }
  2183. else
  2184. {
  2185.     if (HXR_PROP_ACTIVE == preg->SetStrByName(plevel->CharStar(),
  2186. pval))
  2187.     {
  2188. IHXActiveRegistry* pActiveReg = 0;
  2189. preg->QueryInterface(IID_IHXActiveRegistry,
  2190.     (void**)&pActiveReg);
  2191. if (pActiveReg)
  2192. {
  2193.     m_ActiveSetsOutstanding++;
  2194.     if (HXR_OK != pActiveReg->SetActiveStr(
  2195. plevel->CharStar(), pval,
  2196. this))
  2197.     {
  2198. m_ActiveSetsOutstanding--;
  2199.     }
  2200.     pActiveReg->Release();
  2201. }
  2202.     }
  2203.     pval->Release();
  2204. }
  2205.     }
  2206.     break;
  2207. case PT_INTEGER:
  2208.     {
  2209. INT32 i;
  2210. if (!_GetDefaultValInt(
  2211.     plevel->CharStar(),
  2212.     &i, preg))
  2213. {
  2214.     if (!preg->DeleteByName(
  2215. plevel->CharStar()))
  2216.     {
  2217. IHXActiveRegistry* pActiveReg = 0;
  2218. preg->QueryInterface(IID_IHXActiveRegistry,
  2219.     (void**)&pActiveReg);
  2220. if (pActiveReg)
  2221. {
  2222.     m_ActiveSetsOutstanding++;
  2223.     if (HXR_OK != pActiveReg->DeleteActiveProp(
  2224. plevel->CharStar(),
  2225. this))
  2226.     {
  2227. m_ActiveSetsOutstanding--;
  2228.     }
  2229.     pActiveReg->Release();
  2230. }
  2231.     }
  2232. }
  2233. else
  2234. {
  2235.     if (HXR_PROP_ACTIVE == preg->SetIntByName(plevel->CharStar(),
  2236. i))
  2237.     {
  2238. IHXActiveRegistry* pActiveReg = 0;
  2239. preg->QueryInterface(IID_IHXActiveRegistry,
  2240.     (void**)&pActiveReg);
  2241. if (pActiveReg)
  2242. {
  2243.     m_ActiveSetsOutstanding++;
  2244.     if (HXR_OK != pActiveReg->SetActiveInt(
  2245. plevel->CharStar(),
  2246. i, this))
  2247.     {
  2248. m_ActiveSetsOutstanding--;
  2249.     }
  2250.     pActiveReg->Release();
  2251. }
  2252.     }
  2253. }
  2254.     }
  2255.     break;
  2256. case PT_COMPOSITE:
  2257.     ///XXXPM there will be a bug here if we have default vars in sub lists and 
  2258.     //we try and delete the list.  The default vals will not be found here.
  2259.     IHXActiveRegistry* pActiveReg = 0;
  2260.     preg->QueryInterface(IID_IHXActiveRegistry,
  2261. (void**)&pActiveReg);
  2262.     if (pActiveReg)
  2263.     {
  2264. m_ActiveSetsOutstanding++;
  2265. HX_RESULT res;
  2266. res = pActiveReg->DeleteActiveProp(plevel->CharStar(),
  2267.     this);
  2268. if (res != HXR_OK)
  2269. {
  2270.     m_ActiveSetsOutstanding--;
  2271. }
  2272. pActiveReg->Release();
  2273.     }
  2274.     break;
  2275. }
  2276. plevel->RemoveLevel();
  2277. delete pInfo;
  2278.     }
  2279. }
  2280. IHXBuffer*
  2281. XMLConfig::_GetDefaultValString(const char* pProp,
  2282. IHXRegistry2* preg)
  2283. {
  2284.     IHXBuffer* pBuffer = 0;
  2285.     char configdefaults[256]; /* Flawfinder: ignore */
  2286.     HX_ASSERT(strlen(pProp) < 220);
  2287.     SafeSprintf(configdefaults, 256, "configdefaults%s", strchr(pProp, '.'));
  2288.     preg->GetStrByName(configdefaults, pBuffer);
  2289.     return pBuffer;
  2290. }
  2291. int
  2292. XMLConfig::_GetDefaultValInt(const char* pProp, INT32* pOut,
  2293.      IHXRegistry2* preg)
  2294. {
  2295.     char configdefaults[256]; /* Flawfinder: ignore */
  2296.     HX_ASSERT(strlen(pProp) < 220);
  2297.     SafeSprintf(configdefaults, 256, "configdefaults%s", strchr(pProp, '.'));
  2298.     if (HXR_OK != preg->GetIntByName(configdefaults, *pOut))
  2299.     {
  2300. return 0;
  2301.     }
  2302.     return 1;
  2303. }