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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: asmrulep.cpp,v 1.14.2.3 2004/07/09 01:48:15 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. // #include "hlxclib/stdio.h"      /* printf */
  50. #include "hxtypes.h"    /* Basic Types */
  51. #include "hlxclib/stdlib.h"
  52. #include "hxstrutl.h"
  53. #include "hxcom.h"      /* IUnknown */
  54. #include "ihxpckts.h"
  55. #include "asmrulep.h" /* ASM Public Include File */
  56. #include "asmrulpp.h" /* ASM Private Include File */
  57. #include "chxpckts.h"
  58. #define RULE_VAL_INFINITY -1
  59. #include "hxheap.h"
  60. /*
  61. #ifdef _DEBUG
  62. #undef HX_THIS_FILE
  63. static const char HX_THIS_FILE[] = __FILE__;
  64. #endif
  65. */
  66. static const char* const zpOpName[] =
  67. {
  68.     ">",
  69.     "<",
  70.     ">=",
  71.     "<=",
  72.     "==",
  73.     "!=",
  74.     "AND",
  75.     "OR"
  76. };
  77. ASMRuleExpression::ASMRuleExpression(const char* pExpression)
  78. {
  79.     int temp;
  80.     char* pTemp = new char[temp = (strlen(pExpression) + 1)];
  81.     memcpy(pTemp, pExpression, temp); /* Flawfinder: ignore */
  82.     m_ulNumThresholds = 1; // always have one zero rule
  83.     m_pHead = Parse(pTemp, m_ulNumThresholds);
  84.     delete[] pTemp;
  85. }
  86. ASMRuleExpression::~ASMRuleExpression()
  87. {
  88.     RDelete(m_pHead);
  89. }
  90. /* Note:  This parse is destructive to pExpression */
  91. Node*
  92. ASMRuleExpression::Parse(char* pExpression, UINT32& ulNumThreshold)
  93. {
  94.     char* pTemp = pExpression;
  95.     int PLevel = 0;
  96.     BOOL bStripAgain = 1;
  97.     int OperSize;
  98.     //printf ("Parse Expression: %sn", pExpression);
  99.     // Strip outside unneccesary parens
  100.     while ((*pExpression == '(') && (bStripAgain))
  101.     {
  102. for (pTemp = pExpression, PLevel = 0; *pTemp; pTemp++)
  103. {
  104.     if (*pTemp == '(')
  105. PLevel++;
  106.     if (*pTemp == ')')
  107.     {
  108. PLevel--;
  109. if ((!(*(pTemp + 1))) && (!PLevel))
  110. {
  111.     pExpression++;
  112.     pExpression[strlen(pExpression) - 1] = 0;
  113.     bStripAgain = 1;
  114.     break;
  115. }
  116. if (!PLevel)
  117. {
  118.     bStripAgain = 0;
  119.     break;
  120. }
  121.     }
  122. }
  123.     }
  124.     for (pTemp = pExpression, PLevel = 0; *pTemp; pTemp++)
  125.     {
  126. if (*pTemp == '(')
  127.     PLevel++;
  128. if (*pTemp == ')')
  129.     PLevel--;
  130. if (!PLevel)
  131. {
  132.     OperSize = 1;
  133.     if (((*pTemp == '>') || (*pTemp == '<')) ||
  134.         ((*pTemp == '=') || (*pTemp == '!')) ||
  135.         ((*pTemp == '&') || (*pTemp == '|')))
  136.     {
  137. OperatorNode* pNode = new OperatorNode;
  138. pNode->m_Type = HX_RE_OPERATOR;
  139. switch (*pTemp)
  140. {
  141. case '>':
  142.     if ((*(pTemp + 1)) == '=')
  143.     {
  144. pNode->m_Data = HX_RE_GREATEREQUAL;
  145. OperSize = 2;
  146.     }
  147.     else
  148. pNode->m_Data = HX_RE_GREATER;
  149.     break;
  150. case '<':
  151.     if ((*(pTemp + 1)) == '=')
  152.     {
  153. pNode->m_Data = HX_RE_LESSEQUAL;
  154. OperSize = 2;
  155.     }
  156.     else
  157. pNode->m_Data = HX_RE_LESS;
  158.     break;
  159. case '=':
  160.     if ((*(pTemp + 1)) == '=')
  161.     {
  162. pNode->m_Data = HX_RE_EQUAL;
  163. OperSize = 2;
  164.     }
  165.     break;
  166. case '!':
  167.     if ((*(pTemp + 1)) == '=')
  168.     {
  169. pNode->m_Data = HX_RE_NOTEQUAL;
  170. OperSize = 2;
  171.     }
  172.     break;
  173. case '&':
  174.     if ((*(pTemp + 1)) == '&')
  175.     {
  176. pNode->m_Data = HX_RE_AND;
  177. OperSize = 2;
  178.     }
  179.     break;
  180. case '|':
  181.     if ((*(pTemp + 1)) == '|')
  182.     {
  183. pNode->m_Data = HX_RE_OR;
  184. OperSize = 2;
  185.     }
  186.     break;
  187. default:
  188.     break;
  189. };
  190. *pTemp = 0;
  191. pNode->m_pLeft  = Parse(pExpression, ulNumThreshold);
  192. pNode->m_pRight = Parse(pTemp + OperSize, ulNumThreshold);
  193. return pNode;
  194.     }
  195. }
  196.     }
  197.     for (pTemp = pExpression, PLevel = 0; *pTemp; pTemp++)
  198.     {
  199. if (*pTemp == '(')
  200.     PLevel++;
  201. if (*pTemp == ')')
  202.     PLevel--;
  203. if (!PLevel)
  204. {
  205.     if (*pTemp == '$')
  206.     {
  207. VariableNode* pNode = new VariableNode;
  208. pNode->m_Type = HX_RE_VARIABLE;
  209. pNode->m_Data = new char[strlen(pTemp)];
  210. memcpy(pNode->m_Data, pTemp + 1, strlen(pTemp)); /* Flawfinder: ignore */
  211. pNode->m_pLeft  = 0;
  212. pNode->m_pRight = 0;
  213. ulNumThreshold++; // each open variable means one more threshold.
  214. return pNode;
  215.     }
  216. }
  217.     }
  218.     for (pTemp = pExpression, PLevel = 0; *pTemp; pTemp++)
  219.     {
  220. if (*pTemp == '(')
  221.     PLevel++;
  222. if (*pTemp == ')')
  223.     PLevel--;
  224. if (!PLevel)
  225. {
  226.     if  ((*pTemp == '0') || (*pTemp == '1') || (*pTemp == '2') ||
  227.  (*pTemp == '3') || (*pTemp == '4') || (*pTemp == '5') ||
  228.  (*pTemp == '6') || (*pTemp == '7') || (*pTemp == '8') ||
  229.  (*pTemp == '9'))
  230.     {
  231. if (strchr(pTemp, '.'))
  232. {
  233.     FloatNode* pNode = new FloatNode;
  234.     pNode->m_Type = HX_RE_FLOAT;
  235.     pNode->m_Data = (float)atof(pTemp);
  236.     pNode->m_pLeft  = 0;
  237.     pNode->m_pRight = 0;
  238.     return pNode;
  239. }
  240. else
  241. {
  242.     IntegerNode* pNode = new IntegerNode;
  243.     pNode->m_Type = HX_RE_INTEGER;
  244.     pNode->m_Data = atoi(pTemp);
  245.     pNode->m_pLeft  = 0;
  246.     pNode->m_pRight = 0;
  247.     return pNode;
  248. }
  249.     }
  250. }
  251.     }
  252.     //printf ("Panic: Bad rulen");
  253.     return 0;
  254. }
  255. void
  256. ASMRuleExpression::Dump()
  257. {
  258.     //printf ("Dumping ASMRuleExpression:n");
  259.     RDump(m_pHead);
  260.     //printf ("n");
  261. }
  262. void
  263. ASMRuleExpression::RDump(Node* pNode)
  264. {
  265.     if (!pNode)
  266. return;
  267. #if 0
  268.     switch(pNode->m_Type)
  269.     {
  270.     case HX_RE_VARIABLE:
  271. printf ("   Variable: %sn", ((VariableNode *)pNode)->m_Data);
  272. break;
  273.     case HX_RE_INTEGER:
  274. printf ("   Integer: %dn", ((IntegerNode *)pNode)->m_Data);
  275. break;
  276.     case HX_RE_FLOAT:
  277. printf ("   Float: %fn", ((FloatNode *)pNode)->m_Data);
  278. break;
  279.     case HX_RE_OPERATOR:
  280. printf ("   Operator: %sn",
  281.     zpOpName[((OperatorNode *)pNode)->m_Data]);
  282. break;
  283.     }
  284. #endif
  285.     RDump(pNode->m_pLeft);
  286.     RDump(pNode->m_pRight);
  287. }
  288. void
  289. ASMRuleExpression::RDelete(Node* pNode)
  290. {
  291.     if (!pNode)
  292. return;
  293.     if (pNode->m_Type == HX_RE_VARIABLE)
  294.     {
  295. HX_VECTOR_DELETE(((VariableNode *)pNode)->m_Data);
  296.     };
  297.     RDelete(pNode->m_pLeft);
  298.     RDelete(pNode->m_pRight);
  299.     delete pNode;
  300. }
  301. /*
  302.  * This is a recursive expression evaluator that will determine whether
  303.  * or not we are subscribed to a particular rule, given the current conditions
  304.  */ 
  305. float
  306. ASMRuleExpression::REvaluate(Node* pNode, IHXValues* pVars)
  307. {
  308.     if (!pNode)
  309.         return (float)0;
  310.     switch(pNode->m_Type)
  311.     {
  312.     case HX_RE_VARIABLE:
  313. {
  314.     IHXBuffer* pValue=NULL;
  315.             float nValue = (float)0;
  316.     pVars->GetPropertyCString(((VariableNode *)pNode)->m_Data, pValue);
  317.     if (pValue)
  318.     {
  319.                 nValue = (float)atof((const char *)pValue->GetBuffer());
  320. pValue->Release();
  321.     }
  322.     return nValue;
  323. }
  324.     case HX_RE_INTEGER:
  325.         return (float)((IntegerNode *)pNode)->m_Data;
  326. break;
  327.     case HX_RE_FLOAT:
  328. return ((FloatNode *)pNode)->m_Data;
  329. break;
  330.     case HX_RE_OPERATOR:
  331. {
  332.     float Left  = REvaluate(pNode->m_pLeft,  pVars); 
  333.     float Right = REvaluate(pNode->m_pRight, pVars); 
  334.     switch (((OperatorNode *)pNode)->m_Data)
  335.     {
  336.     case HX_RE_GREATEREQUAL:
  337.                 return (float)(Left >= Right);
  338. break;
  339.     case HX_RE_GREATER:
  340.                 return (float)(Left > Right);
  341. break;
  342.             case HX_RE_LESSEQUAL:
  343. if( Right == RULE_VAL_INFINITY )
  344. {
  345.     return (float)TRUE;
  346. }
  347.                 return (float)(Left <= Right);
  348. break;
  349.     case HX_RE_LESS:
  350. if( Right == RULE_VAL_INFINITY )
  351. {
  352.     return (float)TRUE;
  353. }
  354.                 return (float)(Left < Right);
  355. break;
  356.     case HX_RE_EQUAL:
  357.                 return (float)(Left == Right);
  358. break;
  359.     case HX_RE_NOTEQUAL:
  360.                 return (float)(Left != Right);
  361. break;
  362.     case HX_RE_AND:
  363.                 return (float)(Left && Right);
  364. break;
  365.     case HX_RE_OR:
  366.                 return (float)(Left || Right);
  367. break;
  368.             default:
  369.                 HX_ASSERT(0);
  370.                 return (float)0;
  371.                 break;
  372.     }
  373. }
  374. break;
  375.     default:
  376.         HX_ASSERT(0);
  377.         return (float)0;
  378.         break;
  379.     }
  380. }
  381. BOOL
  382. ASMRuleExpression::Evaluate(IHXValues* pVars)
  383. {
  384.     BOOL res;
  385.     //printf ("Evaluate ASMRuleExpression:n");
  386.     res = (BOOL)REvaluate(m_pHead, pVars);
  387.     //printf ("%dn", res);
  388.     return res;
  389. }
  390. /*
  391.  * This is a recursive function which will evaluate a tree with one free
  392.  * variable (pPrevar).  The returned array will contain all possible values
  393.  * that are border cases.
  394.  */
  395. float
  396. ASMRuleExpression::RPreEvaluate(Node* pNode, IHXValues* pVars,
  397. const char* pPreVar, float*& pThreshold,
  398. UINT32& ulNumThreshold,
  399. BOOL& bInvolvesTheOpenVariable)
  400. {
  401.     bInvolvesTheOpenVariable = FALSE;
  402.     float retval = 0;
  403.     float* pThresholdL = NULL;
  404.     float* pThresholdR = NULL;
  405. #define RETURN(x) retval = x; goto exitpoint;
  406.     if (!pNode)
  407.         return (float)0;
  408.     switch(pNode->m_Type)
  409.     {
  410.     case HX_RE_VARIABLE:
  411. {
  412.     IHXBuffer* pValue=NULL;
  413.             float nValue = (float)0;
  414.     pVars->GetPropertyCString(((VariableNode *)pNode)->m_Data, pValue);
  415.     if (pValue)
  416.     {
  417.                 nValue = (float)atof((const char *)pValue->GetBuffer());
  418. pValue->Release();
  419.     }
  420.     if (strcasecmp(((VariableNode *)pNode)->m_Data, pPreVar) == 0)
  421.     {
  422. bInvolvesTheOpenVariable = TRUE;
  423.     }
  424.     return nValue;
  425. }
  426.     case HX_RE_INTEGER:
  427.         return (float)((IntegerNode *)pNode)->m_Data;
  428. break;
  429.     case HX_RE_FLOAT:
  430. return ((FloatNode *)pNode)->m_Data;
  431. break;
  432.     case HX_RE_OPERATOR:
  433. {
  434.     BOOL bInvolveL, bInvolveR;
  435.     UINT32 ulNumThresholdL = 0;
  436.     pThresholdL = pThreshold;
  437.     float Left  = RPreEvaluate(pNode->m_pLeft,  pVars, pPreVar,
  438.     pThresholdL, ulNumThresholdL, bInvolveL);
  439.     UINT32 ulNumThresholdR = 0;
  440.     pThresholdR = pThreshold + ulNumThresholdL;
  441.     float Right = RPreEvaluate(pNode->m_pRight, pVars, pPreVar,
  442.     pThresholdR, ulNumThresholdR, bInvolveR);
  443.     /* Handle aggregation of Threshold arrays */
  444.     switch (((OperatorNode *)pNode)->m_Data)
  445.     {
  446.     case HX_RE_GREATEREQUAL:
  447.     case HX_RE_GREATER:
  448.     case HX_RE_LESSEQUAL:
  449.     case HX_RE_LESS:
  450.     case HX_RE_EQUAL:
  451.     case HX_RE_NOTEQUAL:
  452. if (bInvolveR)
  453. {
  454.     bInvolvesTheOpenVariable = TRUE;
  455.     *pThreshold = Left;
  456.     pThreshold++;
  457.     ulNumThreshold++;
  458.     RETURN ((float)1);
  459. }
  460. if (bInvolveL)
  461. {
  462.     bInvolvesTheOpenVariable = TRUE;
  463.     *pThreshold = Right;
  464.     pThreshold++;
  465.     ulNumThreshold++;
  466.     RETURN ((float)1);
  467. }
  468. break;
  469.     case HX_RE_AND:
  470. if ((Left && bInvolveR) || (Right && bInvolveL))
  471. {
  472.     bInvolvesTheOpenVariable = TRUE;
  473.     UINT32 ulSize = ulNumThresholdL + ulNumThresholdR;
  474.     pThreshold += ulSize;
  475.     ulNumThreshold += ulSize;
  476.     RETURN ((float)1);
  477. }
  478. else
  479. {
  480.     RETURN ((float)0);
  481. }
  482.     case HX_RE_OR:
  483. if (Left || bInvolveL || Right || bInvolveR)
  484. {
  485.     bInvolvesTheOpenVariable = TRUE;
  486.     UINT32 ulSize = ulNumThresholdL + ulNumThresholdR;
  487.     pThreshold += ulSize;
  488.     ulNumThreshold += ulSize;
  489.     RETURN ((float)1);
  490. }
  491. else
  492. {
  493.     RETURN ((float)0);
  494. }
  495.     }
  496.     switch (((OperatorNode *)pNode)->m_Data)
  497.     {
  498.     case HX_RE_GREATEREQUAL:
  499.                 RETURN ((float)(Left >= Right));
  500.     case HX_RE_GREATER:
  501.                 RETURN ((float)(Left > Right));
  502.             case HX_RE_LESSEQUAL:
  503.                 RETURN ((float)(Left <= Right));
  504.     case HX_RE_LESS:
  505.                 RETURN ((float)(Left < Right));
  506.     case HX_RE_EQUAL:
  507.                 RETURN ((float)(Left == Right));
  508.     case HX_RE_NOTEQUAL:
  509.                 RETURN ((float)(Left != Right));
  510.     case HX_RE_AND:
  511.                 RETURN ((float)(Left && Right));
  512.     case HX_RE_OR:
  513.                 RETURN ((float)(Left || Right));
  514.             default:
  515.                 HX_ASSERT(0);
  516.                 RETURN ((float)0);
  517.     }
  518. }
  519.     default:
  520.         HX_ASSERT(0);
  521.         RETURN ((float)0);
  522.     }
  523. exitpoint:
  524.     return retval;
  525. #undef RETURN
  526. }
  527. void
  528. ASMRuleExpression::PreEvaluate(float*& pThreshold, UINT32& ulNumThreshold,
  529.     IHXValues* pVariables, const char* pPreVar)
  530. {
  531.     BOOL bJunk = 0;
  532.     RPreEvaluate(m_pHead, pVariables, pPreVar, 
  533.  pThreshold, ulNumThreshold, bJunk);
  534. }
  535. /*
  536.  * This is a recursive expression evaluator that will determine whether
  537.  * or not the given variable occurs anywhere in the expression.
  538.  */ 
  539. BOOL
  540. ASMRuleExpression::RFindVariable(Node* pNode, const char* pVariable)
  541. {
  542.     if (!pNode)
  543.         return FALSE;
  544.     switch(pNode->m_Type)
  545.     {
  546.     case HX_RE_VARIABLE:
  547. {
  548.     if (strcasecmp(((VariableNode *)pNode)->m_Data, pVariable) == 0)
  549.     {
  550. return TRUE;
  551.     }
  552. }
  553. break;
  554.     case HX_RE_OPERATOR:
  555. {
  556.     return (RFindVariable(pNode->m_pLeft, pVariable) ||
  557.     RFindVariable(pNode->m_pRight, pVariable));
  558. }
  559.     case HX_RE_INTEGER:
  560.     case HX_RE_FLOAT:
  561.     default:
  562.         break;
  563.     }
  564.     return FALSE;
  565. }
  566. BOOL
  567. ASMRuleExpression::FindVariable(const char* pVariable)
  568. {
  569.     return RFindVariable(m_pHead, pVariable);
  570. }
  571. class Rule
  572. {
  573. public:
  574. Rule();
  575.     void SetExpression(const char* pExpression);
  576.     void Dump();
  577. private:
  578.     ASMRuleExpression* m_pASMRuleExpression;
  579.     // Add Properties Definitions Here
  580. };
  581. ASMRule::ASMRule()
  582.     : m_pRuleExpression(0)
  583. {
  584. m_pRuleProps = new CHXHeader;
  585. HX_ASSERT(m_pRuleProps != NULL);
  586. if(m_pRuleProps)
  587. {
  588. m_pRuleProps->AddRef();
  589. }
  590. }
  591. ASMRule::~ASMRule()
  592. {
  593.     HX_RELEASE(m_pRuleProps);
  594.     HX_DELETE(m_pRuleExpression);
  595. }
  596. void
  597. ASMRule::SetExpression(const char* pExpression)
  598. {
  599.     m_pRuleExpression = new ASMRuleExpression(pExpression);
  600. }
  601. void
  602. ASMRule::Dump()
  603. {
  604.     m_pRuleExpression->Dump();
  605. }
  606. ASMRuleBook::ASMRuleBook(const char* pRuleBook)
  607. : m_pValidRulesArray(NULL)
  608. , m_pDeletedRulesArray(NULL)
  609. , m_pRuleBook(NULL)
  610. , m_LastError(HXR_OK)
  611. {
  612.     m_ulNumThresholds = 1; // always have a default
  613.     int i;
  614.     const char* pRule;
  615.     // Count Rules
  616.     i = 0;
  617.     BOOL bSingleQuote      = 0;
  618.     BOOL bDoubleQuote     = 0;
  619.     for (pRule = pRuleBook; *pRule; pRule++)
  620.     {
  621. if ((*pRule == ''') && (!bDoubleQuote))
  622.     bSingleQuote = !bSingleQuote;
  623. if ((*pRule == '"') && (!bSingleQuote))
  624.     bDoubleQuote = !bDoubleQuote;
  625. // Count the number of semi-colons (number of rules)
  626. if ((bSingleQuote == 0) && (bDoubleQuote == 0) && (*pRule == ';'))
  627.     i++;
  628.     }
  629.     m_unNumRules = i;
  630.     m_pRules = new ASMRule[i];
  631.     if(!m_pRules)
  632.     {
  633.        m_LastError = HXR_OUTOFMEMORY;
  634.         return;
  635.     }
  636.     //printf ("%d Rulesn", i);
  637.     // Iterate through each rule
  638.     m_pRuleBook = new char[ strlen( pRuleBook ) + 1 ];
  639.     if(!m_pRuleBook)
  640.     {
  641.         m_LastError = HXR_OUTOFMEMORY;
  642.         HX_DELETE(m_pRules);
  643.         return;
  644.     }
  645.     else
  646.     {
  647.         memcpy( (void*) m_pRuleBook, pRuleBook, strlen( pRuleBook ) + 1 );
  648.     }
  649.     m_LastError = Reset();
  650. }
  651. ASMRuleBook::~ASMRuleBook()
  652. {
  653.     delete [] m_pRules;
  654.     if( m_pValidRulesArray )
  655.     {
  656.        HX_VECTOR_DELETE(m_pValidRulesArray);
  657.     }
  658.     if( m_pDeletedRulesArray )
  659.     {
  660.        HX_VECTOR_DELETE(m_pDeletedRulesArray);
  661.     }
  662. HX_VECTOR_DELETE(m_pRuleBook);
  663. }
  664. BOOL
  665. ASMRuleBook::HasExpression()
  666. {
  667.     for (int i = 0; i < m_unNumRules; i++)
  668.     {
  669.         if (m_pRules[i].m_pRuleExpression)
  670.     return TRUE;
  671.     }
  672.     return FALSE;
  673. }
  674. HX_RESULT
  675. ASMRuleBook::GetProperties(UINT16 unRuleNumber, IHXValues*& pRuleProps)
  676. {
  677.     pRuleProps = m_pRules[unRuleNumber].m_pRuleProps;
  678.     if( pRuleProps )
  679.     {
  680.         pRuleProps->AddRef();
  681.     }
  682.     return HXR_OK;
  683. }
  684. /* Uses REvaluate to return the current subscription given pVariables */
  685. HX_RESULT
  686. ASMRuleBook::GetSubscription(BOOL* pSubInfo, IHXValues* pVariables)
  687. {
  688.     UINT32 i = 0;
  689.     for (i = 0; i < m_unNumRules; i++)
  690.     {
  691.         if( m_pDeletedRulesArray && m_pDeletedRulesArray[i] == TRUE )
  692. {
  693.             pSubInfo[i] = 0;
  694. }
  695. else if (m_pRules[i].m_pRuleExpression)
  696.         {
  697.             pSubInfo[i] = m_pRules[i].m_pRuleExpression->Evaluate(pVariables);
  698.         }
  699.         else
  700.         {
  701.             pSubInfo[i] = 1;
  702.         }
  703.     }
  704.     return HXR_OK;
  705. }
  706. /* 
  707.  * Uses RFindVariable to return information on which rules contain a 
  708.  * given variable in their expressions 
  709.  */
  710. HX_RESULT
  711. ASMRuleBook::FindVariable(BOOL* pFound, const char* pVariable)
  712. {
  713.     UINT32 i = 0;
  714.     for (i = 0; i < m_unNumRules; i++)
  715.     {
  716. if (m_pRules[i].m_pRuleExpression)
  717. {
  718.     pFound[i] = m_pRules[i].m_pRuleExpression->FindVariable(pVariable);
  719. }
  720. else
  721. {
  722.     pFound[i] = FALSE;
  723. }
  724.     }
  725.     return HXR_OK;
  726. }
  727. /* 
  728.  * Uses GetProperties to return information on which rules contain a 
  729.  * given property 
  730.  */
  731. HX_RESULT
  732. ASMRuleBook::FindProperty(BOOL* pFound, const char* pProperty)
  733. {
  734.     HX_RESULT hResult     = HXR_OK;
  735.     UINT32 i     = 0;
  736.     IHXValues* pProperties = NULL;
  737.     IHXBuffer* pBuffer     = NULL;
  738.     for (i = 0; i < m_unNumRules; i++)
  739.     {
  740. hResult = GetProperties((UINT16)i, pProperties);
  741. if (HXR_OK == hResult)
  742. {
  743.     hResult = pProperties->GetPropertyCString(pProperty, pBuffer);
  744.     if (HXR_OK == hResult)
  745.     {
  746. pFound[i] = TRUE;
  747. HX_RELEASE(pBuffer);
  748.     }
  749.     HX_RELEASE(pProperties);
  750. }
  751.     }
  752.     return HXR_OK;
  753. }
  754. static int FloatCompare(const void* p1, const void* p2)
  755. {
  756.     if (*(float*)p1 < *(float*)p2)
  757. return -1;
  758.     if (*(float*)p1 > *(float*)p2)
  759. return 1;
  760.     return 0;
  761. }
  762. /*
  763.  * Uses RPreEvaluate to return the array of threshold values, 
  764.  * given pVariables and pPreVar (the free variable)
  765.  * Caveat: Your variables must say "0" for pPreVar in pVariables.
  766.  */
  767. HX_RESULT
  768. ASMRuleBook::GetPreEvaluate(float* pThreshold, UINT32& ulNumThreshold,
  769.     IHXValues* pVariables, const char* pPreVar)
  770. {
  771.     UINT16 i;
  772.     float* pUnsortedFinal   = new float[m_ulNumThresholds+1];
  773.     float* pTemp = pUnsortedFinal;
  774.     UINT32 ulUFNum = 0;
  775.     ulNumThreshold = 0;
  776.     /* Get everything into a unsorted array with duplicates */ 
  777.     for (i = 0; i < m_unNumRules; i++)
  778.     {
  779.         if (m_pRules[i].m_pRuleExpression)
  780. {
  781.             m_pRules[i].m_pRuleExpression->PreEvaluate(pTemp, ulUFNum,
  782. pVariables, pPreVar);
  783. }
  784.     }
  785.     /*
  786.      * XXXSMP Totally disgusting and doesn't belong here.  So much for
  787.      * a clean, extensible function.
  788.      */
  789.     IHXValues* pValues = 0;
  790.     IHXBuffer* pBuffer = 0;
  791.     pUnsortedFinal[ulUFNum] = (float)0;
  792.     for (i = 0; i < m_unNumRules; i++)
  793.     {
  794. BOOL bOn = TRUE;
  795. if (m_pRules[i].m_pRuleExpression)
  796. {
  797.     bOn = m_pRules[i].m_pRuleExpression->Evaluate(pVariables);
  798. }
  799. if (bOn)
  800. {
  801.     GetProperties((UINT16) i, pValues);
  802.     if (HXR_OK == pValues->GetPropertyCString("AverageBandwidth",
  803. pBuffer))
  804.     {
  805. pUnsortedFinal[ulUFNum] += atoi((char*)pBuffer->GetBuffer());
  806. pBuffer->Release();
  807.     }
  808.     if (HXR_OK == pValues->GetPropertyCString("DropByN",
  809. pBuffer))
  810.     {
  811. pUnsortedFinal[ulUFNum] += 1;
  812. pBuffer->Release();
  813.     }
  814.             HX_RELEASE(pValues);
  815. }
  816.     }
  817.     ulUFNum++;
  818.     pUnsortedFinal[ulUFNum] = (float)0;
  819.     qsort(pUnsortedFinal, ulUFNum+1, sizeof(float), FloatCompare);
  820.     /* Sort and squash duplicates into the output array */
  821.     pTemp = pUnsortedFinal;
  822.     float fLast = *pUnsortedFinal;
  823.     *pThreshold = *pUnsortedFinal;
  824.     pTemp++;
  825.     pThreshold++;
  826.     ulNumThreshold++;
  827.     for (i = 0; i < ulUFNum; i++)
  828.     {
  829. if (*pTemp > fLast)
  830. {
  831.     fLast = *pTemp;
  832.     *pThreshold = fLast;
  833.     pThreshold++;
  834.     ulNumThreshold++;
  835. }
  836. pTemp++;
  837.     }
  838.     delete [] pUnsortedFinal;
  839.     return HXR_OK;
  840. }
  841. #ifdef TESTING
  842. int
  843. main()
  844. {
  845.     const char* pRuleBook =
  846. {
  847. /* Rule 0 */
  848. "     
  849.     #(24000 <= $Bandwidth) && ($Cpu > 50),     
  850.     TolerablePacketLoss=1.5,     
  851.     AverageBandwidth=4000,     
  852.     AverageBandwidthStd=0,     
  853.     Priority=7;     
  854. "
  855. /* Rule 1 */
  856. "     
  857.     #(20000 <= $Bandwidth),     
  858.     TolerablePacketLoss=1.5,     
  859.     AverageBandwidth=4000,     
  860.     AverageBandwidthStd=0,     
  861.     Priority=7;     
  862. "
  863. /* Rule 2 */
  864. "     
  865.     # $Bandwidth >= 16000,     
  866.     TolerablePacketLoss=1.5,     
  867.     AverageBandwidth=16000,     
  868.     AverageBandwidthStd=0,     
  869.     Priority=7;     
  870. "
  871. /* Rule 3 */
  872. "     
  873.     #(16000 > $Bandwidth) && (($Bandwidth >= 8000)),     
  874.     TolerablePacketLoss=2,     
  875.     AverageBandwidth=8000,     
  876.     AverageBandwidthStd=0,     
  877.     Foo="This is a test",     
  878.     Bar="This wu'z a test",     
  879.     Priority=7;     
  880. "
  881. /* Rule 4 */
  882. "     
  883.     # ($Bandwidth > 8000),     
  884.     AverageBandwidth=4000,     
  885.     Priority=7;     
  886. "
  887. };
  888.     ASMRuleBook     r(pRuleBook);
  889.     for (int i = 0; i < 25000; i += 1000)
  890.     {
  891. IHXValues* pVal = new CHXHeader;
  892. IHXBuffer* pBuffer = new CHXBuffer;
  893. char s[1024]; /* Flawfinder: ignore */
  894. //printf ("%dn", i);
  895. sprintf (s, "%d", i); /* Flawfinder: ignore */
  896. pBuffer->Set((unsigned char *)s, 5);
  897. pVal->SetPropertyCString("Bandwidth", pBuffer);
  898. pVal->AddRef();
  899. pBuffer = new CHXBuffer;
  900. sprintf (s, "%d", 60); /* Flawfinder: ignore */
  901. pBuffer->Set((unsigned char *)s, 5);
  902. pVal->SetPropertyCString("Cpu", pBuffer);
  903. pVal->AddRef();
  904. if (i == 0)
  905. {
  906.     printf ("Threshold Points:  ");
  907.     float pThreshold[1024];
  908.     memset (pThreshold, 0xffffffff, sizeof(float) * 1024);
  909.     UINT32 ulNum = 0;
  910.     r.GetPreEvaluate(pThreshold, ulNum, pVal, "Bandwidth");
  911.     for (int j = 0; j < ulNum; j++)
  912.     {
  913. printf ("%.2f ", pThreshold[j]);
  914.     }
  915.     printf ("n");
  916. }
  917. BOOL pSubInfo[1024];
  918. r.GetSubscription(pSubInfo, pVal);
  919. printf ("    bw %5d: %d %d %d %dn", i,
  920.     pSubInfo[0], pSubInfo[1], pSubInfo[2], pSubInfo[3], pSubInfo[4]);
  921. pVal->Release();
  922.     }
  923.     return 0;
  924. }
  925. #endif
  926. HX_RESULT
  927. ASMRuleBook::InitRulesArray()
  928. {
  929.    if( !m_pValidRulesArray )
  930.    {
  931.       m_pValidRulesArray = new BOOL[ m_unNumRules ];
  932.       if(!m_pValidRulesArray)
  933.       {
  934.           return HXR_OUTOFMEMORY;
  935.       }
  936.       for( int ii=0; ii<m_unNumRules; ii++ )
  937.       {
  938.          m_pValidRulesArray[ii] = TRUE;
  939.       }
  940.    }
  941.    if( !m_pDeletedRulesArray )
  942.    {
  943.       m_pDeletedRulesArray = new BOOL[ m_unNumRules ];
  944.       if(!m_pDeletedRulesArray)
  945.       {
  946.           HX_VECTOR_DELETE(m_pValidRulesArray);
  947.           return HXR_OUTOFMEMORY;
  948.       }
  949.       for( int ii=0; ii<m_unNumRules; ii++ )
  950.       {
  951.          m_pDeletedRulesArray[ii] = FALSE;
  952.       }
  953.    }
  954.    return HXR_OK;
  955. }
  956. HX_RESULT
  957. ASMRuleBook::Enable( UINT16 nRule )
  958. {
  959.    // Allocate and initialized m_pValidRulesArray if necessary.
  960.    if( HXR_OUTOFMEMORY == InitRulesArray() )
  961.    {
  962.        return HXR_OUTOFMEMORY;
  963.    }
  964.    else
  965.    {
  966.        m_pValidRulesArray[nRule] = TRUE;
  967.    }
  968.    return HXR_OK;
  969. }
  970. HX_RESULT
  971. ASMRuleBook::Disable( UINT16 nRule )
  972. {
  973.    // Allocate and initialized m_pValidRulesArray if necessary.
  974.    if( HXR_OUTOFMEMORY == InitRulesArray() )
  975.    {
  976.        return HXR_OUTOFMEMORY;
  977.    }
  978.    else
  979.    {
  980.        m_pValidRulesArray[nRule] = FALSE;
  981.    }
  982.    return HXR_OK;
  983. }
  984. HX_RESULT
  985. ASMRuleBook::ReCompute()
  986. {
  987.    // We should call a Reset function here
  988.    if( HXR_OUTOFMEMORY == Reset() )
  989.    {
  990.        return HXR_OUTOFMEMORY;
  991.    }
  992.    for( int ii=0; ii<m_unNumRules; ii++ )
  993.    {
  994.       if( m_pValidRulesArray[ ii ] == FALSE )
  995.       {
  996.  DeleteRule( ii );
  997.       }
  998.    }
  999.    return HXR_OK;
  1000. }
  1001. // Remove a rule from the rulebook and 'collapse' the surrounding rules
  1002. // to cover the bandwidth range that up to now was covered by this rule.
  1003. HX_RESULT
  1004. ASMRuleBook::DeleteRule( int uRuleToDel )
  1005. {
  1006.    int nLeftEdge = 0;
  1007.    int nRightEdge = 0;
  1008.    ULONG32 uNumActiveRules = 0;
  1009.    int ii;
  1010.    // The rule should not be greater the max, of course.
  1011.    if( uRuleToDel > m_unNumRules )
  1012.    {
  1013.       return HXR_FAIL;
  1014.    }
  1015.    // Find the "right edge" rule.
  1016.    for( ii=0; ii<m_unNumRules; ii++ )
  1017.    {
  1018.       if( !m_pDeletedRulesArray[ii] && m_pRules[ii].m_pRuleExpression->IsRightEdge() )
  1019.       {
  1020.          nRightEdge = ii;
  1021.  break;
  1022.       }
  1023.    }
  1024.    // Find the "left edge" rule.
  1025.    for( ii=m_unNumRules-1; ii>=0; ii-- )
  1026.    {
  1027.       if( ( m_pDeletedRulesArray[ii] == FALSE ) && ( m_pRules[ ii ].m_pRuleExpression->GetLeft() || m_pRules[ ii ].m_pRuleExpression->GetRight() ) )
  1028.       {
  1029.          nLeftEdge = ii;
  1030.       }
  1031.    }
  1032.    // Determine the number of active rules.
  1033.    for( ii=0; ii<m_unNumRules; ii++ )
  1034.    {
  1035.       if( !m_pDeletedRulesArray[ii] )
  1036.       {
  1037.          uNumActiveRules++;
  1038.       }
  1039.    }
  1040.    // We handle the 3 possible cases separately: 1) Left Edge, 2) Right Edge, 
  1041.    // and 3) Non-Edge.
  1042.    if( uRuleToDel == nLeftEdge )
  1043.    {
  1044.       // Left edge case
  1045.       // Modify the next rule(s) to the right so that it's > value is 0.
  1046.       // But only if this is the only rule covering uRuleToDel's bw range.
  1047.       if( CheckCurrentRangeEmpty( uRuleToDel ) == TRUE )
  1048.       {
  1049.          for( ii=uRuleToDel+1; ii<m_unNumRules; ii++ )
  1050.          {
  1051.             if( !m_pDeletedRulesArray[ ii ] && (
  1052.                 ( m_pRules[ ii ].m_pRuleExpression->GetLeft() == m_pRules[ uRuleToDel ].m_pRuleExpression->GetRight() ) ) )
  1053.             {
  1054.                m_pRules[ ii ].m_pRuleExpression->SetLeft( 0 );
  1055.             }
  1056.          }
  1057.       }
  1058.    }
  1059.    else if( uRuleToDel >= nRightEdge )
  1060.    {
  1061.       // Right edge case
  1062.       // Set the right value (less than x) to infinity
  1063.       // But only if this is the only rule covering uRuleToDel's bw range.
  1064.       if( CheckCurrentRangeEmpty( uRuleToDel ) == TRUE )
  1065.       {
  1066.          for( ii=uRuleToDel-1; ii>=0; ii-- )
  1067.          {
  1068.             if( !m_pDeletedRulesArray[ ii ] && (
  1069.                 ( m_pRules[ ii ].m_pRuleExpression->GetRight() == m_pRules[ uRuleToDel ].m_pRuleExpression->GetRight() ) ) )
  1070.             {
  1071.                m_pRules[ ii ].m_pRuleExpression->SetRight( RULE_VAL_INFINITY );
  1072.             }
  1073.          }
  1074.       }
  1075.    }
  1076.    else if( uRuleToDel > nLeftEdge )
  1077.    {
  1078.       // Non-edge case
  1079.       // Set all "left-adjacent" rules "right-hand" value to nRight.
  1080.       // But only if this is the only rule covering uRuleToDel's bw range.
  1081.       if( CheckCurrentRangeEmpty( uRuleToDel ) == FALSE )
  1082.       {
  1083.          // Determine the value of our right-hand value.
  1084.          int nRight = (int) m_pRules[ uRuleToDel ].m_pRuleExpression->GetRight();
  1085.          for( ii=uRuleToDel-1; ii>=0; ii-- )
  1086.          {
  1087.             if( !m_pDeletedRulesArray[ ii ] && (
  1088.         ( m_pRules[ ii ].m_pRuleExpression->GetRight() == m_pRules[ uRuleToDel ].m_pRuleExpression->GetLeft() ) ) )
  1089.             {
  1090.                m_pRules[ ii ].m_pRuleExpression->SetRight( nRight );
  1091.             }
  1092.          }
  1093.       }
  1094.    }
  1095.    m_pDeletedRulesArray[uRuleToDel] = TRUE;
  1096.    return HXR_OK;
  1097. }
  1098. void
  1099. ASMRuleExpression::SetLeft( int nLeft )
  1100. {
  1101.    int nRight = ((IntegerNode*) ((VariableNode*)m_pHead->m_pRight))->m_Data;
  1102.    if( nRight == 1 )
  1103.    {
  1104.       ((IntegerNode*)(m_pHead->m_pLeft->m_pRight))->m_Data = nLeft;
  1105.    }
  1106. }
  1107. void
  1108. ASMRuleExpression::SetRight( int nRight )
  1109. {
  1110.    int nTmpRight = 0;
  1111.    if( m_pHead && m_pHead->m_pRight )
  1112.    {
  1113.       nTmpRight = ((IntegerNode*) ((VariableNode*)m_pHead->m_pRight))->m_Data;
  1114.    }
  1115.    if( nTmpRight == 1 )
  1116.    {
  1117.       ( (IntegerNode*)((VariableNode*) ((VariableNode*)m_pHead->m_pRight)->m_pRight) )->m_Data = nRight;
  1118.    }
  1119.    else if( nTmpRight != 0 )
  1120.    {
  1121.       ((VariableNode*)m_pHead->m_pRight)->m_Data = (char*)nRight;
  1122.    }
  1123. }
  1124. float
  1125. ASMRuleExpression::GetLeft()
  1126. {
  1127.    int nLeft = 0;
  1128.    int nRight = 0;
  1129.    if( m_pHead && m_pHead->m_pRight )
  1130.    {
  1131.       nRight = ((IntegerNode*) ((VariableNode*)m_pHead->m_pRight))->m_Data;
  1132.    }
  1133.    if( nRight == 1 )
  1134.    {
  1135.       nLeft = ((IntegerNode*) ((VariableNode*)m_pHead->m_pLeft->m_pRight))->m_Data;
  1136.    }
  1137.    return (float)nLeft;
  1138. }
  1139. float
  1140. ASMRuleExpression::GetRight()
  1141. {
  1142.    int nRight = 0;
  1143.    if( m_pHead && m_pHead->m_pRight )
  1144.    {
  1145.       nRight = ((IntegerNode*) ((VariableNode*)(m_pHead->m_pRight)))->m_Data;
  1146.    }
  1147.    if( nRight == 1 )
  1148.    {
  1149.       nRight = ((IntegerNode*) ((VariableNode*)m_pHead->m_pRight->m_pRight))->m_Data;
  1150.    }
  1151.    return (float)nRight;
  1152. }
  1153. int
  1154. ASMRuleExpression::GetOperatorAsInt()
  1155. {
  1156.    return (int) ((OperatorNode*) m_pHead)->m_Data;
  1157. }
  1158. // This function checks to see if the current rule's operator is GREATER or
  1159. // GREATEROREQUAL, both of which would suggest that we are the "right edge"
  1160. // rule.
  1161. BOOL
  1162. ASMRuleExpression::IsRightEdge()
  1163. {
  1164.    if( m_pHead )
  1165.    {
  1166.       switch(((OperatorNode*)m_pHead)->m_Data)
  1167.       {
  1168.   case HX_RE_GREATER:
  1169.   case HX_RE_GREATEREQUAL:
  1170.       return TRUE;
  1171.       break;
  1172.           default:
  1173.       return FALSE;
  1174.       break;
  1175.       }
  1176.    }
  1177.    else
  1178.    {
  1179.       return FALSE;
  1180.    }
  1181. }
  1182. HX_RESULT
  1183. ASMRuleBook::Reset()
  1184. {
  1185.     int i = 0;
  1186.     { //XXXSMPNOW
  1187. BOOL bSeenExpression = 0;
  1188. //printf ("******* Rule %dn", i);
  1189. const char* pRuleBook = m_pRuleBook;
  1190. while (*pRuleBook)
  1191. {
  1192.     char pTemp[2048 + 1];
  1193.     int  n  = 0;
  1194.     BOOL bSingleQuote   = 0;
  1195.     BOOL bDoubleQuote  = 0;
  1196.     for (;((*pRuleBook) && (bDoubleQuote || ((*pRuleBook != ',') && (*pRuleBook != ';')))); pRuleBook++)
  1197.     {
  1198. if ((*pRuleBook == ''') && (!bDoubleQuote))
  1199.     bSingleQuote = !bSingleQuote;
  1200. if ((*pRuleBook == '"') && (!bSingleQuote))
  1201.     bDoubleQuote = !bDoubleQuote;
  1202. // Kill whitespace outside of quotes
  1203. if (bSingleQuote || bDoubleQuote || (
  1204. (*pRuleBook != ' ') &&
  1205. (*pRuleBook != 'n') &&
  1206. (*pRuleBook != 'r') &&
  1207. (*pRuleBook != 't')))
  1208. {
  1209.     pTemp[n++] = *pRuleBook;
  1210.     if (n >= 2048)
  1211.     {
  1212. //printf ("Panic: Rule Property %d too longn", i);
  1213. HX_ASSERT(0);
  1214. break;
  1215.     }
  1216. }
  1217.     }
  1218.     pTemp[n] = 0;
  1219.     if ((*pRuleBook == ',') || (*pRuleBook == ';'))
  1220.     {
  1221. // Rule is Valid!
  1222.      if (*pTemp == '#')
  1223. {
  1224.     // This part of the rule is an expression
  1225.     if (!bSeenExpression)
  1226.     {
  1227. m_pRules[i].SetExpression(pTemp + 1);
  1228. m_pRules[i].Dump();
  1229. bSeenExpression = 1;
  1230. m_ulNumThresholds += m_pRules[i].m_pRuleExpression->GetNumThresholds();
  1231.     }
  1232.     else
  1233.     {
  1234. //printf ("Panic: Two expressions in Rule %dn", i);
  1235. HX_ASSERT(0);
  1236.     }
  1237. }
  1238. else
  1239. {
  1240.                     char *pProp;
  1241.                     char *pValue;
  1242.                     pProp  = pTemp;
  1243.                     pValue = pTemp;
  1244.                     while ((*pValue != '=') && (pValue-pTemp < ((int) strlen(pTemp))))
  1245.                     pValue++;
  1246.                     if (*pValue == '=')
  1247.                     {
  1248.                         *pValue++ = '';
  1249.                     }
  1250.                     else
  1251.                     {
  1252.                         pValue = NULL;
  1253.                     }
  1254.                     if (pValue)
  1255.                     {
  1256.                         IHXBuffer* pBuffer = new CHXBuffer;
  1257.                         if(!pBuffer)
  1258.                         {
  1259.                             return HXR_OUTOFMEMORY;
  1260.                         }
  1261.                         pBuffer->AddRef();
  1262.                         /* Strip Outside Quotes */
  1263.                         if (*pValue == '"')
  1264.                         {
  1265.                             pValue++;
  1266.                             int end = (strlen(pValue) ? strlen(pValue)-1 : 0);
  1267.                             HX_ASSERT(pValue[end] == '"');
  1268.                             pValue[end] = 0;
  1269.                         }
  1270.                         HX_RESULT theErr = 
  1271.                         pBuffer->Set((const unsigned char *)pValue,
  1272.                         strlen(pValue) + 1);
  1273.                         if( theErr == HXR_OUTOFMEMORY )
  1274.                         {
  1275.                             pBuffer->Release();
  1276.                             return theErr;
  1277.                         }
  1278.                         //printf ("Property '%s'--'%s'n", pProp, pValue);
  1279.                         if( m_pRules[i].m_pRuleProps )
  1280.                         {
  1281.                             m_pRules[i].m_pRuleProps->
  1282.                             SetPropertyCString(pProp, pBuffer);
  1283.                         }
  1284.                         pBuffer->Release();
  1285.                     }
  1286. }
  1287. if (*pRuleBook == ';')
  1288. {
  1289.     i++;
  1290.     bSeenExpression = 0;
  1291.                     if (i >= m_unNumRules)
  1292.                     {
  1293.                         break;
  1294.                     }
  1295.     //printf ("******* Rule %dn", i);
  1296. }
  1297. pRuleBook++;
  1298.     }
  1299. }
  1300.     }
  1301.     return InitRulesArray();
  1302. }
  1303. BOOL
  1304. ASMRuleBook::CheckCurrentRangeEmpty( int uRuleToDel )
  1305. {
  1306.     for( int ii=0; ii<m_unNumRules; ii++ )
  1307.     {
  1308.         // But only if this is the only rule covering uRuleToDel's bw range.
  1309.         if( uRuleToDel != ii && !m_pDeletedRulesArray[ ii ] &&
  1310.             ( m_pRules[ ii ].m_pRuleExpression->GetLeft() == m_pRules[ uRuleToDel ].m_pRuleExpression->GetLeft() ) &&
  1311.             ( m_pRules[ ii ].m_pRuleExpression->GetRight() == m_pRules[ uRuleToDel ].m_pRuleExpression->GetRight() ) &&
  1312.             ( m_pRules[ ii ].m_pRuleExpression->GetOperatorAsInt() == m_pRules[ uRuleToDel ].m_pRuleExpression->GetOperatorAsInt() ) )
  1313.         {
  1314.             return FALSE;
  1315.         }
  1316.     }
  1317.     return TRUE;
  1318. }