RegularExpression.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:48k
源码类别:

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 2001, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Log: RegularExpression.cpp,v $
  58.  * Revision 1.13  2003/05/25 21:42:41  knoaman
  59.  * Allocate/Deallocate Context::xxx only when necessary.
  60.  *
  61.  * Revision 1.12  2003/05/18 14:02:06  knoaman
  62.  * Memory manager implementation: pass per instance manager.
  63.  *
  64.  * Revision 1.11  2003/05/16 21:37:00  knoaman
  65.  * Memory manager implementation: Modify constructors to pass in the memory manager.
  66.  *
  67.  * Revision 1.10  2003/05/16 06:01:57  knoaman
  68.  * Partial implementation of the configurable memory manager.
  69.  *
  70.  * Revision 1.9  2003/05/16 00:03:10  knoaman
  71.  * Partial implementation of the configurable memory manager.
  72.  *
  73.  * Revision 1.8  2003/05/15 18:42:54  knoaman
  74.  * Partial implementation of the configurable memory manager.
  75.  *
  76.  * Revision 1.7  2003/05/12 10:08:22  gareth
  77.  * The correct file this time.
  78.  *
  79.  * Revision 1.5  2002/12/18 13:01:02  gareth
  80.  * New functionality - tokenize and replace. Fixed REVISIT for case insensitive match. Patch by Jennifer Schachter.
  81.  *
  82.  * Revision 1.4  2002/11/04 15:17:00  tng
  83.  * C++ Namespace Support.
  84.  *
  85.  * Revision 1.3  2002/10/15 18:56:02  knoaman
  86.  * [Bug 13604] while loop never terminates.
  87.  *
  88.  * Revision 1.2  2002/03/18 19:29:53  knoaman
  89.  * Change constant names to eliminate possible conflict with user defined ones.
  90.  *
  91.  * Revision 1.1.1.1  2002/02/01 22:22:30  peiyongz
  92.  * sane_include
  93.  *
  94.  * Revision 1.6  2002/01/02 20:09:11  knoaman
  95.  * Fix for regular expression patterns that begin with ".".
  96.  *
  97.  * Revision 1.5  2001/10/09 12:20:25  tng
  98.  * Leak fix: Need to delete fMatch if adopted.
  99.  *
  100.  * Revision 1.4  2001/05/11 21:50:58  knoaman
  101.  * Schema updates and fixes.
  102.  *
  103.  * Revision 1.3  2001/05/11 13:26:46  tng
  104.  * Copyright update.
  105.  *
  106.  * Revision 1.2  2001/05/03 18:17:42  knoaman
  107.  * Some design changes:
  108.  * o Changed the TokenFactory from a single static instance, to a
  109.  *    normal class. Each RegularExpression object will have its own
  110.  *    instance of TokenFactory, and that instance will be passed to
  111.  *    other classes that need to use a TokenFactory to create Token
  112.  *    objects (with the exception of RangeTokenMap).
  113.  * o Added a new class RangeTokenMap to map a the different ranges
  114.  *    in a given category to a specific RangeFactory object. In the old
  115.  *    design RangeFactory had dual functionality (act as a Map, and as
  116.  *    a factory for creating RangeToken(s)). The RangeTokenMap will
  117.  *    have its own copy of the TokenFactory. There will be only one
  118.  *    instance of the RangeTokenMap class, and that instance will be
  119.  *    lazily deleted when XPlatformUtils::Terminate is called.
  120.  *
  121.  * Revision 1.1  2001/03/02 19:22:52  knoaman
  122.  * Schema: Regular expression handling part I
  123.  *
  124.  */
  125. // ---------------------------------------------------------------------------
  126. //  Includes
  127. // ---------------------------------------------------------------------------
  128. #include <xercesc/util/regx/RegularExpression.hpp>
  129. #include <xercesc/util/PlatformUtils.hpp>
  130. #include <xercesc/util/regx/RegxUtil.hpp>
  131. #include <xercesc/util/regx/Match.hpp>
  132. #include <xercesc/util/regx/RangeToken.hpp>
  133. #include <xercesc/util/regx/RegxDefs.hpp>
  134. #include <xercesc/util/regx/XMLUniCharacter.hpp>
  135. #include <xercesc/util/regx/ParserForXMLSchema.hpp>
  136. #include <xercesc/util/Janitor.hpp>
  137. #include <xercesc/util/ParseException.hpp>
  138. #include <xercesc/util/IllegalArgumentException.hpp>
  139. #include <xercesc/framework/XMLBuffer.hpp>
  140. XERCES_CPP_NAMESPACE_BEGIN
  141. // ---------------------------------------------------------------------------
  142. //  Static member data initialization
  143. // ---------------------------------------------------------------------------
  144. const unsigned int RegularExpression::MARK_PARENS = 1;
  145. const unsigned int RegularExpression::IGNORE_CASE = 2;
  146. const unsigned int RegularExpression::SINGLE_LINE = 4;
  147. const unsigned int RegularExpression::MULTIPLE_LINE = 8;
  148. const unsigned int RegularExpression::EXTENDED_COMMENT = 16;
  149. const unsigned int RegularExpression::USE_UNICODE_CATEGORY = 32;
  150. const unsigned int RegularExpression::UNICODE_WORD_BOUNDARY = 64;
  151. const unsigned int RegularExpression::PROHIBIT_HEAD_CHARACTER_OPTIMIZATION = 128;
  152. const unsigned int RegularExpression::PROHIBIT_FIXED_STRING_OPTIMIZATION = 256;
  153. const unsigned int RegularExpression::XMLSCHEMA_MODE = 512;
  154. const unsigned int RegularExpression::SPECIAL_COMMA = 1024;
  155. const unsigned short RegularExpression::WT_IGNORE = 0;
  156. const unsigned short RegularExpression::WT_LETTER = 1;
  157. const unsigned short RegularExpression::WT_OTHER = 2;
  158. RangeToken*          RegularExpression::fWordRange = 0;
  159. // ---------------------------------------------------------------------------
  160. //  RegularExpression::Context: Constructors and Destructor
  161. // ---------------------------------------------------------------------------
  162. RegularExpression::Context::Context(MemoryManager* const manager) :
  163.     fInUse(false)
  164. , fAdoptMatch(false)
  165.     , fStart(0)
  166. , fLimit(0)
  167. , fLength(0)
  168. , fSize(0)
  169. , fOffsets(0)
  170. , fMatch(0)
  171. , fString(0)
  172.     , fMemoryManager(manager)
  173. {
  174. }
  175. RegularExpression::Context::~Context()
  176. {
  177. if (fOffsets)
  178.         fMemoryManager->deallocate(fOffsets);//delete [] fOffsets;
  179.     fMemoryManager->deallocate(fString);//delete [] fString;
  180. if (fAdoptMatch)
  181. delete fMatch;
  182. }
  183. // ---------------------------------------------------------------------------
  184. //  RegularExpression::Context: Public methods
  185. // ---------------------------------------------------------------------------
  186. void RegularExpression::Context::reset(const XMLCh* const string
  187.                                        , const int start, const int limit
  188.                                        , const int noClosures)
  189. {
  190.     if (fString)
  191.         fMemoryManager->deallocate(fString);//delete [] fString;
  192.     fString = XMLString::replicate(string, fMemoryManager);
  193. fStart = start;
  194. fLimit = limit;
  195. fLength = fLimit - fStart;
  196. fInUse = true;
  197. if (fAdoptMatch)
  198. delete fMatch;
  199. fMatch = 0;
  200. if (fSize != noClosures) {
  201. if (fOffsets)
  202.             fMemoryManager->deallocate(fOffsets);//delete [] fOffsets;
  203. fOffsets = (int*) fMemoryManager->allocate(noClosures * sizeof(int));//new int[noClosures];
  204. }
  205. fSize = noClosures;
  206. for (int i = 0; i< fSize; i++)
  207. fOffsets[i] = -1;
  208. }
  209. bool RegularExpression::Context::nextCh(XMLInt32& ch, int& offset,
  210. const short direction)
  211. {
  212. ch = fString[offset];
  213. if (RegxUtil::isHighSurrogate(ch)) {
  214. if ((offset + 1 < fLimit) && (direction > 0) &&
  215. RegxUtil::isLowSurrogate(fString[offset+1])) {
  216. ch = RegxUtil::composeFromSurrogate(ch, fString[++offset]);
  217. }
  218. else
  219. return false;
  220. }
  221. else if (RegxUtil::isLowSurrogate(ch)) {
  222. if ((offset - 1 >= 0) && (direction <= 0) &&
  223. RegxUtil::isHighSurrogate(fString[offset-1])) {
  224. ch = RegxUtil::composeFromSurrogate(fString[--offset], ch);
  225. }
  226. else
  227. return false;
  228. }
  229. return true;
  230. }
  231. // ---------------------------------------------------------------------------
  232. //  RegularExpression: Constructors and Destructors
  233. // ---------------------------------------------------------------------------
  234. RegularExpression::RegularExpression(const char* const pattern,
  235.                                      MemoryManager* const manager)
  236. :fHasBackReferences(false),
  237.  fFixedStringOnly(false),
  238.  fNoGroups(0),
  239.  fMinLength(0),
  240.  fNoClosures(0),
  241.  fOptions(0),
  242.  fContext(0),
  243.  fBMPattern(0),
  244.  fPattern(0),
  245.  fFixedString(0),
  246.  fOperations(0),
  247.  fTokenTree(0),
  248.  fFirstChar(0),
  249.      fOpFactory(manager),
  250.      fTokenFactory(0),
  251.      fMemoryManager(manager)
  252. {
  253. try {
  254. XMLCh* tmpBuf = XMLString::transcode(pattern, fMemoryManager);
  255.         ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  256. setPattern(tmpBuf);
  257. }
  258. catch (...) {
  259. cleanUp();
  260. throw;
  261. }
  262. }
  263. RegularExpression::RegularExpression(const char* const pattern,
  264.  const char* const options,
  265.                                      MemoryManager* const manager)
  266. :fHasBackReferences(false),
  267.  fFixedStringOnly(false),
  268.  fNoGroups(0),
  269.  fMinLength(0),
  270.  fNoClosures(0),
  271.  fOptions(0),
  272.  fContext(0),
  273.  fBMPattern(0),
  274.  fPattern(0),
  275.  fFixedString(0),
  276.  fOperations(0),
  277.  fTokenTree(0),
  278.  fFirstChar(0),
  279.      fOpFactory(manager),
  280.      fTokenFactory(0),
  281.      fMemoryManager(manager)
  282. {
  283. try {
  284. XMLCh* tmpBuf = XMLString::transcode(pattern, fMemoryManager);
  285. ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  286. XMLCh* tmpOptions = XMLString::transcode(options, fMemoryManager);
  287. ArrayJanitor<XMLCh> janOps(tmpOptions, fMemoryManager);
  288. setPattern(tmpBuf, tmpOptions);
  289. }
  290. catch (...) {
  291. cleanUp();
  292. throw;
  293. }
  294. }
  295. RegularExpression::RegularExpression(const XMLCh* const pattern,
  296.                                      MemoryManager* const manager)
  297. :fHasBackReferences(false),
  298.  fFixedStringOnly(false),
  299.  fNoGroups(0),
  300.  fMinLength(0),
  301.  fNoClosures(0),
  302.  fOptions(0),
  303.  fContext(0),
  304.  fBMPattern(0),
  305.  fPattern(0),
  306.  fFixedString(0),
  307.  fOperations(0),
  308.  fTokenTree(0),
  309.  fFirstChar(0),
  310.      fOpFactory(manager),
  311.      fTokenFactory(0),
  312.      fMemoryManager(manager)
  313. {
  314. try {
  315. setPattern(pattern);
  316. }
  317. catch (...) {
  318. cleanUp();
  319. throw;
  320. }
  321. }
  322. RegularExpression::RegularExpression(const XMLCh* const pattern,
  323.  const XMLCh* const options,
  324.                                      MemoryManager* const manager)
  325. :fHasBackReferences(false),
  326.  fFixedStringOnly(false),
  327.  fNoGroups(0),
  328.  fMinLength(0),
  329.  fNoClosures(0),
  330.  fOptions(0),
  331.  fContext(0),
  332.  fBMPattern(0),
  333.  fPattern(0),
  334.  fFixedString(0),
  335.  fOperations(0),
  336.  fTokenTree(0),
  337.  fFirstChar(0),
  338.      fOpFactory(manager),
  339.      fTokenFactory(0),
  340.      fMemoryManager(manager)
  341. {
  342. try {
  343. setPattern(pattern, options);
  344. }
  345. catch (...) {
  346. cleanUp();
  347. throw;
  348. }
  349. }
  350. RegularExpression::~RegularExpression() {
  351. cleanUp();
  352. }
  353. // ---------------------------------------------------------------------------
  354. //  RegularExpression: Setter methods
  355. // ---------------------------------------------------------------------------
  356. void RegularExpression::setPattern(const XMLCh* const pattern,
  357.    const XMLCh* const options) {
  358.     fTokenFactory = new (fMemoryManager) TokenFactory(fMemoryManager);
  359. fOptions = parseOptions(options);
  360. fPattern = XMLString::replicate(pattern, fMemoryManager);
  361. RegxParser* regxParser = isSet(fOptions, XMLSCHEMA_MODE)
  362. ? new (fMemoryManager) ParserForXMLSchema(fMemoryManager) 
  363.         : new (fMemoryManager) RegxParser(fMemoryManager);
  364.     if (regxParser) {
  365.         regxParser->setTokenFactory(fTokenFactory);
  366.     }
  367. Janitor<RegxParser> janRegxParser(regxParser);
  368. fTokenTree = regxParser->parse(fPattern, fOptions);
  369. fNoGroups = regxParser->getNoParen();
  370. fHasBackReferences = regxParser->hasBackReferences();
  371. }
  372. // ---------------------------------------------------------------------------
  373. //  RegularExpression: Matching methods
  374. // ---------------------------------------------------------------------------
  375. bool RegularExpression::matches(const char* const expression) {
  376.     XMLCh* tmpBuf = XMLString::transcode(expression, fMemoryManager);
  377.     ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  378. return matches(tmpBuf, 0, XMLString::stringLen(tmpBuf), 0);
  379. }
  380. bool RegularExpression::matches(const char* const expression,
  381. const int start, const int end) {
  382. XMLCh* tmpBuf = XMLString::transcode(expression, fMemoryManager);
  383.     ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  384. return matches(tmpBuf, start, end, 0);
  385. }
  386. bool RegularExpression::matches(const char* const expression,
  387. Match* const match) {
  388. XMLCh* tmpBuf = XMLString::transcode(expression, fMemoryManager);
  389.     ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  390. return matches(tmpBuf, 0, XMLString::stringLen(tmpBuf), match);
  391. }
  392. bool RegularExpression::matches(const char* const expression, const int start,
  393.                                 const int end, Match* const pMatch) {
  394. XMLCh* tmpBuf = XMLString::transcode(expression, fMemoryManager);
  395.     ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  396. return matches(tmpBuf, start, end, pMatch);
  397. }
  398. // ---------------------------------------------------------------------------
  399. //  RegularExpression: Matching methods - Wide char version
  400. // ---------------------------------------------------------------------------
  401. bool RegularExpression::matches(const XMLCh* const expression) {
  402. return matches(expression, 0, XMLString::stringLen(expression), 0);
  403. }
  404. bool RegularExpression::matches(const XMLCh* const expression,
  405. const int start, const int end) {
  406. return matches(expression, start, end, 0);
  407. }
  408. bool RegularExpression::matches(const XMLCh* const expression,
  409. Match* const match) {
  410. return matches(expression, 0, XMLString::stringLen(expression), match);
  411. }
  412. bool RegularExpression::matches(const XMLCh* const expression, const int start,
  413.                                 const int end, Match* const pMatch) {
  414. if (fOperations == 0)
  415. prepare();
  416. Context* context = 0;
  417. Context* tmpContext = 0;
  418. int  strLength = XMLString::stringLen(expression);
  419. {
  420. XMLMutexLock lockInit(&fMutex);
  421. if (fContext == 0)
  422. fContext = new (fMemoryManager) Context(fMemoryManager);
  423. if (fContext->fInUse) {
  424. context = new (fMemoryManager) Context(fMemoryManager);
  425. tmpContext = context;
  426. }
  427. else {
  428. context = fContext;
  429. }
  430. context->reset(expression, start, end, fNoClosures);
  431. }
  432. Janitor<Context> janContext(tmpContext);
  433. bool adoptMatch = false;
  434. Match* lMatch = pMatch;
  435. if (lMatch != 0) {
  436. lMatch->setNoGroups(fNoGroups);
  437. }
  438. else if (fHasBackReferences) {
  439. lMatch = new (fMemoryManager) Match(fMemoryManager);
  440. lMatch->setNoGroups(fNoGroups);
  441. adoptMatch = true;
  442. }
  443. if (context->fAdoptMatch)
  444. delete context->fMatch;
  445.     context->fMatch = lMatch;
  446. context->fAdoptMatch = adoptMatch;
  447. if (isSet(fOptions, XMLSCHEMA_MODE)) {
  448. int matchEnd = match(context, fOperations, context->fStart, 1);
  449. if (matchEnd == context->fLimit) {
  450. if (context->fMatch != 0) {
  451. context->fMatch->setStartPos(0, context->fStart);
  452. context->fMatch->setEndPos(0, matchEnd);
  453. }
  454. context->fInUse = false;
  455. return true;
  456. }
  457. return false;
  458. }
  459. /*
  460.  * If the pattern has only fixed string, use Boyer-Moore
  461.  */
  462. if (fFixedStringOnly) {
  463. int ret = fBMPattern->matches(expression, context->fStart,
  464.                           context->fLimit);
  465. if (ret >= 0) {
  466. if (context->fMatch != 0) {
  467. context->fMatch->setStartPos(0, ret);
  468. context->fMatch->setEndPos(0, ret + strLength);
  469. }
  470. context->fInUse = false;
  471. return true;
  472. }
  473. context->fInUse = false;
  474. return false;
  475. }
  476. /*
  477.  * If the pattern contains a fixed string, we check with Boyer-Moore
  478.  * whether the text contains the fixed string or not. If not found
  479.  * return false
  480.  */
  481. if (fFixedString != 0) {
  482. int ret = fBMPattern->matches(expression, context->fStart,
  483.                                       context->fLimit);
  484. if (ret < 0) { // No match
  485. context->fInUse = false;
  486. return false;
  487. }
  488. }
  489. int limit = context->fLimit - fMinLength;
  490. int matchStart;
  491. int matchEnd = -1;
  492. /*
  493.  * Check whether the expression start with ".*"
  494.  */
  495. if (fOperations != 0 && fOperations->getOpType() == Op::O_CLOSURE
  496.         && fOperations->getChild()->getOpType() == Op::O_DOT) {
  497. if (isSet(fOptions, SINGLE_LINE)) {
  498. matchStart = context->fStart;
  499. matchEnd = match(context, fOperations, matchStart, 1);
  500. }
  501. else {
  502. bool previousIsEOL = true;
  503. for (matchStart=context->fStart; matchStart<=limit; matchStart++) {
  504. XMLCh ch = expression[matchStart];
  505. if (RegxUtil::isEOLChar(ch)) {
  506. previousIsEOL = true;
  507. }
  508. else {
  509. if (previousIsEOL) {
  510. if (0 <= (matchEnd = match(context, fOperations,
  511.                                                    matchStart, 1)))
  512.                             break;
  513. }
  514. previousIsEOL = false;
  515. }
  516. }
  517. }
  518. }
  519. else {
  520.         /*
  521.          * Optimization against the first char
  522.          */
  523. if (fFirstChar != 0) {
  524. bool ignoreCase = isSet(fOptions, IGNORE_CASE);
  525. RangeToken* range = fFirstChar;
  526. if (ignoreCase)
  527. range = fFirstChar->getCaseInsensitiveToken(fTokenFactory);
  528. for (matchStart=context->fStart; matchStart<=limit; matchStart++) {
  529.                 XMLInt32 ch;
  530. if (!context->nextCh(ch, matchStart, 1))
  531. break;
  532. if (!range->match(ch)) {
  533. if (!ignoreCase)
  534. continue;
  535. // Perform case insensitive match
  536. // REVISIT
  537. continue;
  538. }
  539. if (0 <= (matchEnd = match(context,fOperations,matchStart,1)))
  540. break;
  541.             }
  542. }
  543. else {
  544.             /*
  545.              * Straightforward matching
  546.              */
  547. for (matchStart=context->fStart; matchStart<=limit; matchStart++) {
  548. if (0 <= (matchEnd = match(context,fOperations,matchStart,1)))
  549. break;
  550. }
  551. }
  552. }
  553. if (matchEnd >= 0) {
  554. if (context->fMatch != 0) {
  555. context->fMatch->setStartPos(0, matchStart);
  556. context->fMatch->setEndPos(0, matchEnd);
  557. }
  558. context->fInUse = false;
  559. return true;
  560. }
  561. context->fInUse = false;
  562. return false;
  563. }
  564. // ---------------------------------------------------------------------------
  565. //  RegularExpression: Tokenize methods
  566. // ---------------------------------------------------------------------------
  567. RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const char* const expression) {
  568.   XMLCh* tmpBuf = XMLString::transcode(expression);
  569.   ArrayJanitor<XMLCh> janBuf(tmpBuf);
  570.   return tokenize(tmpBuf, 0, XMLString::stringLen(tmpBuf));
  571. }
  572. RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const char* const expression,
  573. const int start, const int end) {
  574.   XMLCh* tmpBuf = XMLString::transcode(expression);
  575.   ArrayJanitor<XMLCh> janBuf(tmpBuf);
  576.   return tokenize(tmpBuf, start, end);
  577. }
  578. // ---------------------------------------------------------------------------
  579. //  RegularExpression: Tokenize methods - Wide char version
  580. // ---------------------------------------------------------------------------
  581. RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const XMLCh* const expression) {
  582.   return tokenize(expression, 0, XMLString::stringLen(expression), 0);
  583. }
  584. RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const XMLCh* const expression,
  585.                                      const int start, const int end)
  586. {
  587.   return tokenize(expression, start, end, 0);
  588. }
  589. RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const XMLCh* const expression, 
  590.                                                      const int start, const int end,
  591.                                                      RefVectorOf<Match> *subEx){
  592.   
  593.   if (fOperations == 0)
  594.   prepare();
  595.   RefArrayVectorOf<XMLCh>* tokenStack = new (fMemoryManager) RefArrayVectorOf<XMLCh>(16, true, fMemoryManager);
  596.   Context* context = 0;
  597.   Context* tmpContext = 0;
  598.   int  strLength = XMLString::stringLen(expression);
  599.  
  600.   {
  601.      XMLMutexLock lockInit(&fMutex);
  602.      if (fContext == 0)
  603.        fContext = new (fMemoryManager) Context(fMemoryManager);
  604.      if (fContext->fInUse) {
  605.        context = new (fMemoryManager) Context(fMemoryManager);
  606.        tmpContext = context;
  607.      }
  608.      else {
  609.        context = fContext;
  610.      }
  611.      context->reset(expression, start, end, fNoClosures);
  612.   }
  613.   Janitor<Context> janContext(tmpContext);
  614.   Match* lMatch = 0;
  615.   bool adoptMatch = false;
  616.   if (subEx || fHasBackReferences) {
  617.     lMatch = new (fMemoryManager) Match(fMemoryManager);
  618.     adoptMatch = true;
  619.     lMatch->setNoGroups(fNoGroups);
  620.   }
  621.   if (context->fAdoptMatch)
  622.     delete context->fMatch;
  623.   
  624.   context->fMatch = lMatch;
  625.   context->fAdoptMatch = adoptMatch;
  626.   int tokStart = start;
  627.   int matchStart = start;
  628.   for (; matchStart <= end; matchStart++) { 
  629.   
  630.     int matchEnd = match(context, fOperations, matchStart, 1);
  631.   
  632.     if (matchEnd != -1) {
  633.       if (context->fMatch != 0) {
  634.         context->fMatch->setStartPos(0, context->fStart);
  635.         context->fMatch->setEndPos(0, matchEnd);
  636.       }
  637.       if (subEx){
  638.         subEx->addElement(lMatch);
  639.         lMatch = new (fMemoryManager) Match(*(context->fMatch));
  640.         adoptMatch = true;
  641.         
  642.         context->fAdoptMatch = adoptMatch;
  643.         context->fMatch = lMatch;
  644.       }
  645.   
  646.       context->fInUse = false;
  647.       XMLCh* token;
  648.       if (tokStart == matchStart){
  649.   
  650.         if (tokStart == strLength){
  651.           tokStart--;
  652.           break;  
  653.         }
  654.         token = (XMLCh*) fMemoryManager->allocate(sizeof(XMLCh));//new XMLCh[1];
  655.         token[0] = chNull;
  656.         // When you tokenize using zero string, will return each
  657.         // token in the string. Since the zero string will also 
  658.         // match the start/end characters, resulting in empty 
  659.         // tokens, we ignore them and do not add them to the stack. 
  660.         if (!XMLString::equals(fPattern, &chNull)) 
  661.           tokenStack->addElement(token); 
  662.         else
  663.             fMemoryManager->deallocate(token);//delete[] token;
  664.       } else {
  665.         token = (XMLCh*) fMemoryManager->allocate
  666.         (
  667.             (matchStart + 1 - tokStart) * sizeof(XMLCh)
  668.         );//new XMLCh[matchStart + 1 - tokStart];
  669.         XMLString::subString(token, expression, tokStart, matchStart);
  670.         tokenStack->addElement(token);
  671.       } 
  672.       tokStart = matchEnd;
  673.       //decrement matchStart as will increment it at the top of the loop
  674.       if (matchStart < matchEnd - 1) 
  675.         matchStart = matchEnd - 1;      
  676.     }
  677.   }
  678.  
  679.   XMLCh* token;
  680.  
  681.   if (matchStart == tokStart + 1){
  682.     token = (XMLCh*) fMemoryManager->allocate(sizeof(XMLCh));//new XMLCh[1];
  683.     token[0] = chNull;
  684.   
  685.   } else {
  686.     token = (XMLCh*) fMemoryManager->allocate
  687.     (
  688.         (strLength + 1 - tokStart) * sizeof(XMLCh)
  689.     );//new XMLCh[strLength + 1 - tokStart];
  690.     XMLString::subString(token, expression, tokStart, strLength);
  691.   }  
  692.   if (!XMLString::equals(fPattern, &chNull)) 
  693.     tokenStack->addElement(token);
  694.   else
  695.     fMemoryManager->deallocate(token);//delete[] token;
  696.   return tokenStack;
  697. }
  698. // -----------------------------------------------------------------------
  699. //  RegularExpression: Replace methods
  700. // -----------------------------------------------------------------------
  701. XMLCh* RegularExpression::replace(const char* const matchString, 
  702.                                   const char* const replaceString){
  703. XMLCh* tmpBuf = XMLString::transcode(matchString);
  704.     ArrayJanitor<XMLCh> janBuf(tmpBuf);
  705. XMLCh* tmpBuf2 = XMLString::transcode(replaceString);
  706.     ArrayJanitor<XMLCh> janBuf2(tmpBuf2);
  707. return replace(tmpBuf, tmpBuf2, 0, XMLString::stringLen(tmpBuf));
  708. }
  709. XMLCh* RegularExpression::replace(const char* const matchString, 
  710.                                   const char* const replaceString,
  711.                                   const int start, const int end){
  712.   XMLCh* tmpBuf = XMLString::transcode(matchString);
  713.     ArrayJanitor<XMLCh> janBuf(tmpBuf);
  714.   XMLCh* tmpBuf2 = XMLString::transcode(replaceString);
  715.     ArrayJanitor<XMLCh> janBuf2(tmpBuf2);
  716.   
  717.   return replace(tmpBuf, tmpBuf2, start, end);
  718. }
  719. // ---------------------------------------------------------------------------
  720. //  RegularExpression: Replace methods - Wide char version
  721. // ---------------------------------------------------------------------------
  722. XMLCh* RegularExpression::replace(const XMLCh* const matchString, 
  723.                                   const XMLCh* const replaceString){
  724.   return replace(matchString, replaceString, 0, 
  725.                  XMLString::stringLen(matchString));
  726. }
  727. XMLCh* RegularExpression::replace(const XMLCh* const matchString,  
  728.                                   const XMLCh* const replaceString,
  729.                                   const int start, const int end)
  730. {
  731.   //check if matches zero length string - throw error if so
  732.   if (matches(XMLUni::fgZeroLenString)){
  733. ThrowXML(RuntimeException, XMLExcepts::Regex_RepPatMatchesZeroString);
  734.   }
  735.       
  736.   RefVectorOf<Match> *subEx = new (fMemoryManager) RefVectorOf<Match>(10, true, fMemoryManager);
  737.   Janitor<RefVectorOf<Match> > janSubEx(subEx);
  738.   //Call to tokenize with Match vector so that we keep track of the locations
  739.   //of the subExpression within each of the matches
  740.   RefArrayVectorOf<XMLCh>* tokenStack = tokenize(matchString, start, end, subEx);
  741.   Janitor<RefArrayVectorOf<XMLCh> > janTokStack(tokenStack);
  742.     
  743.   XMLBuffer result(1023, fMemoryManager);
  744.   
  745.   int numSubEx = 0;
  746.   
  747.   if (subEx && subEx->size() > 0)
  748.     numSubEx = subEx->elementAt(0)->getNoGroups() - 1;
  749.   
  750.   int tokStackSize = tokenStack->size();
  751.   const XMLCh* curRepString = XMLString::replicate(replaceString);
  752.     
  753.   for (int i = 0; i < tokStackSize; i++){
  754.       
  755.     result.append(tokenStack->elementAt(i));
  756.   
  757.     if (i != tokStackSize - 1) {
  758.        
  759.       //if there are subExpressions, then determine the string we want to 
  760.       //substitute in.
  761.         if (numSubEx != 0) {
  762.             delete[] (XMLCh*)curRepString;
  763.             curRepString = subInExp(replaceString, matchString, subEx->elementAt(i));     
  764.         }
  765.       result.append(curRepString);
  766.     }
  767.   }  
  768.     
  769.   delete[] (XMLCh*)curRepString;
  770.   return XMLString::replicate(result.getRawBuffer()); 
  771.     
  772. }
  773. // ---------------------------------------------------------------------------
  774. //  RegularExpression: Helpers methods
  775. // ---------------------------------------------------------------------------
  776. int RegularExpression::getOptionValue(const XMLCh ch) {
  777. int ret = 0;
  778. switch (ch) {
  779. case chLatin_i:
  780. ret = IGNORE_CASE;
  781. break;
  782. case chLatin_m:
  783. ret = MULTIPLE_LINE;
  784. break;
  785. case chLatin_s:
  786. ret = SINGLE_LINE;
  787. break;
  788. case chLatin_x:
  789. ret = EXTENDED_COMMENT;
  790. break;
  791. case chLatin_u:
  792. ret = USE_UNICODE_CATEGORY;
  793. break;
  794. case chLatin_w:
  795. ret = UNICODE_WORD_BOUNDARY;
  796. break;
  797. case chLatin_F:
  798. ret = PROHIBIT_FIXED_STRING_OPTIMIZATION;
  799. break;
  800. case chLatin_H:
  801. ret = PROHIBIT_HEAD_CHARACTER_OPTIMIZATION;
  802. break;
  803. case chLatin_X:
  804. ret = XMLSCHEMA_MODE;
  805. break;
  806. case chComma:
  807. ret = SPECIAL_COMMA;
  808. break;
  809. default:
  810. break;
  811. }
  812. return ret;
  813. }
  814. int RegularExpression::match(Context* const context, const Op* const operations
  815.  , int offset, const short direction)
  816. {
  817. const Op* tmpOp = operations;
  818. bool ignoreCase = isSet(fOptions, IGNORE_CASE);
  819. while (true) {
  820. if (tmpOp == 0)
  821. break;
  822. if (offset > context->fLimit || offset < context->fStart)
  823. return -1;
  824. switch(tmpOp->getOpType()) {
  825. case Op::O_CHAR:
  826. if (!matchChar(context, tmpOp->getData(), offset, direction,
  827.    ignoreCase))
  828. return -1;
  829. tmpOp = tmpOp->getNextOp();
  830. break;
  831. case Op::O_DOT:
  832. if (!matchDot(context, offset, direction))
  833. return -1;
  834. tmpOp = tmpOp->getNextOp();
  835. break;
  836. case Op::O_RANGE:
  837. case Op::O_NRANGE:
  838. if (!matchRange(context, tmpOp, offset, direction, ignoreCase))
  839. return -1;
  840. tmpOp = tmpOp->getNextOp();
  841. break;
  842. case Op::O_ANCHOR:
  843. if (!matchAnchor(context, tmpOp->getData(), offset))
  844. return -1;
  845. tmpOp = tmpOp->getNextOp();
  846. break;
  847. case Op::O_BACKREFERENCE:
  848. if (!matchBackReference(context, tmpOp->getData(), offset,
  849. direction, ignoreCase))
  850. return -1;
  851. tmpOp = tmpOp->getNextOp();
  852. break;
  853. case Op::O_STRING:
  854. if (!matchString(context, tmpOp->getLiteral(), offset, direction,
  855.  ignoreCase))
  856. return -1;
  857. tmpOp = tmpOp->getNextOp();
  858. break;
  859. case Op::O_CLOSURE:
  860. {
  861. XMLInt32 id = tmpOp->getData();
  862. if (id >= 0) {
  863. int prevOffset = context->fOffsets[id];
  864. if (prevOffset < 0 || prevOffset != offset) {
  865. context->fOffsets[id] = offset;
  866. }
  867. else {
  868. context->fOffsets[id] = -1;
  869. tmpOp = tmpOp->getNextOp();
  870. break;
  871. }
  872. }
  873. int ret = match(context, tmpOp->getChild(), offset, direction);
  874. if (id >= 0) {
  875. context->fOffsets[id] = -1;
  876. }
  877. if (ret >= 0)
  878. return ret;
  879. tmpOp = tmpOp->getNextOp();
  880. }
  881. break;
  882. case Op::O_QUESTION:
  883. {
  884. int ret = match(context, tmpOp->getChild(), offset, direction);
  885. if (ret >= 0)
  886. return ret;
  887. tmpOp = tmpOp->getNextOp();
  888. }
  889. break;
  890. case Op::O_NONGREEDYCLOSURE:
  891. case Op::O_NONGREEDYQUESTION:
  892. {
  893. int ret = match(context,tmpOp->getNextOp(),offset,direction);
  894. if (ret >= 0)
  895. return ret;
  896. tmpOp = tmpOp->getChild();
  897. }
  898. break;
  899. case Op::O_UNION:
  900. {
  901. return matchUnion(context, tmpOp, offset, direction);
  902. }
  903. case Op::O_CAPTURE:
  904. if (context->fMatch != 0 && tmpOp->getData() != 0)
  905. return matchCapture(context, tmpOp, offset, direction);
  906. tmpOp = tmpOp->getNextOp();
  907. break;
  908. case Op::O_LOOKAHEAD:
  909. if (0 > match(context, tmpOp->getChild(), offset, 1))
  910. return -1;
  911. tmpOp = tmpOp->getNextOp();
  912. break;
  913. case Op::O_NEGATIVELOOKAHEAD:
  914. if (0 <= match(context, tmpOp->getChild(), offset, 1))
  915. return -1;
  916. tmpOp = tmpOp->getNextOp();
  917. break;
  918. case Op::O_LOOKBEHIND:
  919. if (0 > match(context, tmpOp->getChild(), offset, -1))
  920. return - 1;
  921. tmpOp = tmpOp->getNextOp();
  922. break;
  923. case Op::O_NEGATIVELOOKBEHIND:
  924. if (0 <= match(context, tmpOp->getChild(), offset, -1))
  925. return -1;
  926. tmpOp = tmpOp->getNextOp();
  927. break;
  928. case Op::O_INDEPENDENT:
  929.         case Op::O_MODIFIER:
  930. {
  931. int ret = (tmpOp->getOpType() == Op::O_INDEPENDENT)
  932.    ? match(context, tmpOp->getChild(), offset, direction)
  933.                        : matchModifier(context, tmpOp, offset, direction);
  934.                 if (ret < 0)
  935.                     return ret;
  936. offset = ret;
  937. tmpOp = tmpOp->getNextOp();
  938. }
  939. break;
  940. case Op::O_CONDITION:
  941. if (tmpOp->getRefNo() >= fNoGroups)
  942. return -1;
  943. if (matchCondition(context, tmpOp, offset, direction))
  944. tmpOp = tmpOp->getYesFlow();
  945. else
  946. if (tmpOp->getNoFlow() != 0)
  947.                     tmpOp = tmpOp->getNoFlow();
  948.                 else
  949.                     tmpOp = tmpOp->getNextOp();
  950. break;
  951. }
  952. }
  953. return offset;
  954. }
  955. bool RegularExpression::matchChar(Context* const context,
  956.   const XMLInt32 ch, int& offset,
  957.   const short direction, const bool ignoreCase)
  958. {
  959. int tmpOffset = direction > 0 ? offset : offset - 1;
  960. if (tmpOffset >= context->fLimit || tmpOffset < 0)
  961. return false;
  962. XMLInt32 strCh = 0;
  963. if (!context->nextCh(strCh, tmpOffset, direction))
  964. return false;
  965. bool match = ignoreCase ? matchIgnoreCase(ch, strCh)
  966.                     : (ch == strCh);
  967. if (!match)
  968. return false;
  969. offset = (direction > 0) ? ++tmpOffset : tmpOffset;
  970. return true;
  971. }
  972. bool RegularExpression::matchDot(Context* const context, int& offset,
  973.  const short direction)
  974. {
  975. int tmpOffset = direction > 0 ? offset : offset - 1;
  976. if (tmpOffset >= context->fLimit || tmpOffset < 0)
  977. return false;
  978. XMLInt32 strCh = 0;
  979. if (!context->nextCh(strCh, tmpOffset, direction))
  980. return false;
  981. if (!isSet(fOptions, SINGLE_LINE)) {
  982. if (direction > 0 && RegxUtil::isEOLChar(strCh))
  983. return false;
  984. if (direction <= 0 && !RegxUtil::isEOLChar(strCh) )
  985. return false;
  986. }
  987.     offset = (direction > 0) ? ++tmpOffset : tmpOffset;
  988. return true;
  989. }
  990. bool RegularExpression::matchRange(Context* const context, const Op* const op,
  991.    int& offset, const short direction,
  992.    const bool ignoreCase)
  993. {
  994. int tmpOffset = direction > 0 ? offset : offset - 1;
  995. if (tmpOffset >= context->fLimit || tmpOffset < 0)
  996. return false;
  997. XMLInt32 strCh = 0;
  998. if (!context->nextCh(strCh, tmpOffset, direction))
  999. return false;
  1000. RangeToken* tok = (RangeToken *) op->getToken();
  1001. bool match = false;
  1002. if (ignoreCase) {
  1003. //REVISIT we should match ignoring case, but for now
  1004. //we will do a normal match
  1005. //tok = tok->getCaseInsensitiveToken();
  1006. //if (!token->match(strCh)) {
  1007. // if (strCh > 0x10000)
  1008. // return -1;
  1009. // Do case insensitive matching - uppercase match
  1010. // or lowercase match
  1011. //}
  1012. match = tok->match(strCh);
  1013. }
  1014. else
  1015. match = tok->match(strCh);
  1016. if (!match)
  1017. return false;
  1018. offset = (direction > 0) ? ++tmpOffset : tmpOffset;
  1019. return true;
  1020. }
  1021. bool RegularExpression::matchAnchor(Context* const context, const XMLInt32 ch,
  1022. const int offset)
  1023. {
  1024. switch ((XMLCh) ch) {
  1025. case chLatin_A:
  1026. if (offset != context->fStart)
  1027. return false;
  1028. break;
  1029. case chLatin_B:
  1030. if (context->fLength == 0)
  1031. break;
  1032. {
  1033. int after = getWordType(context->fString, context->fStart,
  1034. context->fLimit, offset);
  1035. if (after == WT_IGNORE
  1036. || after == getPreviousWordType(context->fString,
  1037. context->fStart,
  1038. context->fLimit, offset))
  1039. break;
  1040. }
  1041. return false;
  1042. case chLatin_b:
  1043. if (context->fLength == 0)
  1044. return false;
  1045. {
  1046. int after = getWordType(context->fString, context->fStart,
  1047. context->fLimit, offset);
  1048. if (after == WT_IGNORE
  1049. || after == getPreviousWordType(context->fString,
  1050. context->fStart
  1051. , context->fLimit, offset))
  1052. return false;
  1053. }
  1054. break;
  1055. case chLatin_Z:
  1056. case chDollarSign:
  1057. if ( (XMLCh) ch == chDollarSign && isSet(fOptions, MULTIPLE_LINE)) {
  1058. if (!(offset == context->fLimit || (offset < context->fLimit
  1059. && RegxUtil::isEOLChar(context->fString[offset]))))
  1060. return false;
  1061. }
  1062. else {
  1063. if (!(offset == context->fLimit
  1064. || (offset+1 == context->fLimit
  1065.     && RegxUtil::isEOLChar(context->fString[offset]))
  1066. || (offset+2 == context->fLimit
  1067.     && context->fString[offset] == chCR
  1068. && context->fString[offset+1] == chLF)))
  1069. return false;
  1070. }
  1071. break;
  1072. case chLatin_z:
  1073. if (offset != context->fLimit)
  1074. return false;
  1075. break;
  1076. case chAt:
  1077. case chCaret:
  1078. if ( (XMLCh) ch == chCaret && !isSet(fOptions, MULTIPLE_LINE)) {
  1079. if (offset != context->fStart)
  1080. return false;
  1081. }
  1082. else {
  1083. if (!(offset == context->fStart || (offset > context->fStart
  1084.       && RegxUtil::isEOLChar(context->fString[offset-1]))))
  1085. return false;
  1086. }
  1087. break;
  1088. case chOpenAngle:
  1089. if (context->fLength == 0 || offset == context->fLimit)
  1090. return false;
  1091. if (getWordType(context->fString, context->fStart, context->fLimit,
  1092. offset) != WT_LETTER
  1093. || getPreviousWordType(context->fString, context->fStart,
  1094.    context->fLimit, offset) != WT_OTHER)
  1095. return false;
  1096. break;
  1097. case chCloseAngle:
  1098. if (context->fLength == 0 || offset == context->fStart)
  1099. return false;
  1100. if (getWordType(context->fString, context->fStart, context->fLimit,
  1101. offset) != WT_OTHER
  1102. || getPreviousWordType(context->fString, context->fStart,
  1103.    context->fLimit, offset) != WT_LETTER)
  1104. return false;
  1105. break;
  1106. }
  1107. return true;
  1108. }
  1109. bool RegularExpression::matchBackReference(Context* const context,
  1110.    const XMLInt32 refNo, int& offset,
  1111.    const short direction,
  1112.    const bool ignoreCase)
  1113. {
  1114. if (refNo <=0 || refNo >= fNoGroups)
  1115. ThrowXML(IllegalArgumentException, XMLExcepts::Regex_BadRefNo);
  1116. if (context->fMatch->getStartPos(refNo) < 0
  1117. || context->fMatch->getEndPos(refNo) < 0)
  1118. return false;
  1119. int start = context->fMatch->getStartPos(refNo);
  1120. int length = context->fMatch->getEndPos(refNo) - start;
  1121. int tmpOffset = (direction > 0) ? offset : offset - length;
  1122. if (context->fLimit - tmpOffset < length)
  1123. return false;
  1124. bool match = ignoreCase
  1125. ? XMLString::regionIMatches(context->fString,tmpOffset,
  1126. context->fString,start,length)
  1127. : XMLString::regionMatches(context->fString, tmpOffset,
  1128.    context->fString, start,length);
  1129. if (!match)
  1130. return false;
  1131. offset = (direction > 0) ? offset + length : offset - length;
  1132. return true;
  1133. }
  1134. bool RegularExpression::matchString(Context* const context,
  1135. const XMLCh* const literal, int& offset,
  1136. const short direction, const bool ignoreCase)
  1137. {
  1138. int length = XMLString::stringLen(literal);
  1139. int tmpOffset = (direction > 0) ? offset : offset - length;
  1140. if (context->fLimit - tmpOffset < length)
  1141. return false;
  1142. bool match = ignoreCase
  1143. ? XMLString::regionIMatches(context->fString, tmpOffset,
  1144. literal, 0, length)
  1145. : XMLString::regionMatches(context->fString, tmpOffset,
  1146.    literal, 0, length);
  1147. if (match) {
  1148.     offset = direction > 0 ? offset + length : offset - length;
  1149.     }
  1150. return match;
  1151. }
  1152. int RegularExpression::matchCapture(Context* const context, const Op* const op,
  1153.                                     int offset, const short direction)
  1154. {
  1155. // No check is made for nullness of fMatch as the function is only called if
  1156. // fMatch is not null.
  1157. XMLInt32 index = op->getData();
  1158. int save = (index > 0) ? context->fMatch->getStartPos(index)
  1159.                            : context->fMatch->getEndPos(-index);
  1160. if (index > 0) {
  1161. context->fMatch->setStartPos(index, offset);
  1162. int ret = match(context, op->getNextOp(), offset, direction);
  1163. if (ret < 0)
  1164. context->fMatch->setStartPos(index, save);
  1165. return ret;
  1166. }
  1167. context->fMatch->setEndPos(-index, offset);
  1168. int ret = match(context, op->getNextOp(), offset, direction);
  1169. if (ret < 0)
  1170. context->fMatch->setEndPos(-index, save);
  1171. return ret;
  1172. }
  1173. bool RegularExpression::matchCondition(Context* const context,
  1174.                                               const Op* const op, int offset,
  1175.                                               const short direction)
  1176. {
  1177. int refNo = op->getRefNo();
  1178. if ( refNo > 0)
  1179. return (context->fMatch->getStartPos(refNo) >= 0
  1180.                 && context->fMatch->getEndPos(refNo) >= 0);
  1181. return (0 <= match(context, op->getConditionFlow(), offset, direction));
  1182. }
  1183. int RegularExpression::parseOptions(const XMLCh* const options)
  1184. {
  1185. if (options == 0)
  1186. return 0;
  1187. int opts = 0;
  1188. int length = XMLString::stringLen(options);
  1189. for (int i=0; i < length; i++) {
  1190. int v = getOptionValue(options[i]);
  1191. if (v == 0)
  1192. ThrowXML1(ParseException, XMLExcepts::Regex_UnknownOption, options);
  1193. opts |= v;
  1194. }
  1195. return opts;
  1196. }
  1197. void RegularExpression::compile(const Token* const token) {
  1198. if (fOperations != 0)
  1199. return;
  1200. fNoClosures = 0;
  1201. fOperations = compile(token, 0, false);
  1202. }
  1203. Op* RegularExpression::compile(const Token* const token, Op* const next,
  1204.    const bool reverse) {
  1205. Op* ret = 0;
  1206. const unsigned short tokenType = token->getTokenType();
  1207. switch(tokenType) {
  1208. case Token::T_DOT:
  1209. case Token::T_CHAR:
  1210. case Token::T_ANCHOR:
  1211. case Token::T_RANGE:
  1212. case Token::T_NRANGE:
  1213. case Token::T_STRING:
  1214. case Token::T_BACKREFERENCE:
  1215. case Token::T_EMPTY:
  1216. ret = compileSingle(token, next, tokenType);
  1217. break;
  1218. case Token::T_CONCAT:
  1219. ret = compileConcat(token, next, reverse);
  1220. break;
  1221. case Token::T_UNION:
  1222. ret = compileUnion(token, next, reverse);
  1223. break;
  1224. case Token::T_CLOSURE:
  1225. case Token::T_NONGREEDYCLOSURE:
  1226. ret = compileClosure(token, next, reverse, tokenType);
  1227. break;
  1228. case Token::T_PAREN:
  1229. ret = compileParenthesis(token, next, reverse);
  1230. break;
  1231. case Token::T_LOOKAHEAD:
  1232. case Token::T_NEGATIVELOOKAHEAD:
  1233. ret = compileLook(token, next, false, tokenType);
  1234. break;
  1235. case Token::T_LOOKBEHIND:
  1236. case Token::T_NEGATIVELOOKBEHIND:
  1237. ret = compileLook(token, next, true, tokenType);
  1238. break;
  1239. case Token::T_INDEPENDENT:
  1240. case Token::T_MODIFIERGROUP:
  1241. ret = compileLook(token, next, reverse, tokenType);
  1242. break;
  1243. case Token::T_CONDITION:
  1244. ret = compileCondition(token, next, reverse);
  1245. break;
  1246. default:
  1247. ThrowXML(RuntimeException, XMLExcepts::Regex_UnknownTokenType);
  1248. break; // this line to be deleted
  1249. }
  1250. return ret;
  1251. }
  1252. /*
  1253.  * Helper for Replace. This method prepares the replacement string by substituting
  1254.  * in actual values for parenthesized sub expressions. 
  1255.  *
  1256.  * An error will be thrown if:
  1257.  *  1) repString references an undefined subExpression
  1258.  *  2) there is an unescaped chDollar which is not followed by a digit
  1259.  *
  1260.  */
  1261. const XMLCh* RegularExpression::subInExp(const XMLCh* const repString, 
  1262.                                          const XMLCh* const origString, 
  1263.                                          const Match* subEx){
  1264.   int numSubExp = subEx->getNoGroups() - 1;
  1265.   if (numSubExp == 0)
  1266.     return XMLString::replicate(repString);
  1267.   
  1268.   bool notEscaped = true;                 
  1269.   
  1270.   XMLBuffer newString(1023, fMemoryManager);                   
  1271.   
  1272.   XMLCh indexStr[2]; //holds the string rep of a 
  1273.   indexStr[1] = chNull;
  1274.   int index = -1;
  1275.   for (const XMLCh* ptr = repString; *ptr != chNull; ptr++){
  1276.     if ((*ptr == chDollarSign) && notEscaped) {
  1277.       
  1278.       ptr++;
  1279.       
  1280.       //check that after the $ is a digit 
  1281.       if (!XMLString::isDigit(*ptr)){
  1282.        
  1283.         //invalid replace string - $ must be followed by a digit
  1284. ThrowXML(RuntimeException, XMLExcepts::Regex_InvalidRepPattern);
  1285.       }
  1286.         
  1287.       indexStr[0] = *ptr;                     //get the digit 
  1288.       index = XMLString::parseInt(indexStr);  //convert it to an int
  1289.       //now check that the index is legal
  1290.       if (index > numSubExp){
  1291. ThrowXML(RuntimeException, XMLExcepts::Regex_InvalidRepPattern);
  1292.       }
  1293.         
  1294.       int start = subEx->getStartPos(index);
  1295.       int end = subEx->getEndPos(index);
  1296.       //now copy the substring into the new string
  1297.       for (int i=start; i<end; i++){
  1298.         newString.append(origString[i]);
  1299.       }
  1300.           
  1301.     } else {
  1302.  
  1303.       //if you have a slash and then a character that's not a $ or /, 
  1304.       //then it's an invalid replace string  
  1305.       if (!notEscaped && (*ptr != chDollarSign && *ptr != chBackSlash)){
  1306. ThrowXML(RuntimeException, XMLExcepts::Regex_InvalidRepPattern);
  1307.       }
  1308.       
  1309.       if (*ptr == chBackSlash){
  1310.         notEscaped = false;
  1311.         continue;
  1312.         
  1313.       }else   
  1314.         notEscaped = true;  
  1315.       newString.append(*ptr);
  1316.     }
  1317.   }
  1318.   return XMLString::replicate(newString.getRawBuffer());
  1319.        
  1320. }
  1321. /*
  1322.  * Prepares for matching. This method is called just before starting matching
  1323.  */
  1324. void RegularExpression::prepare() {
  1325. XMLMutexLock lockInit(&fMutex);
  1326. compile(fTokenTree);
  1327. fMinLength = fTokenTree->getMinLength();
  1328. fFirstChar = 0;
  1329. if (!isSet(fOptions, PROHIBIT_HEAD_CHARACTER_OPTIMIZATION) &&
  1330. !isSet(fOptions, XMLSCHEMA_MODE)) {
  1331. RangeToken* rangeTok = fTokenFactory->createRange();
  1332. int result = fTokenTree->analyzeFirstCharacter(rangeTok, fOptions, fTokenFactory);
  1333. if (result == Token::FC_TERMINAL) {
  1334. rangeTok->compactRanges();
  1335. fFirstChar = rangeTok;
  1336. }
  1337. }
  1338. if (fOperations != 0 && fOperations->getNextOp() == 0 &&
  1339. (fOperations->getOpType() == Op::O_STRING ||
  1340.  fOperations->getOpType() == Op::O_CHAR) )  {
  1341. fFixedStringOnly = true;
  1342. if (fOperations->getOpType() == Op::O_STRING) {
  1343. fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
  1344. fFixedString = XMLString::replicate(fOperations->getLiteral(), fMemoryManager);
  1345. }
  1346. else{
  1347. XMLInt32 ch = fOperations->getData();
  1348. if ( ch >= 0x10000) { // add as constant
  1349. fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
  1350. fFixedString = RegxUtil::decomposeToSurrogates(ch, fMemoryManager);
  1351. }
  1352. else {
  1353. XMLCh* dummyStr = (XMLCh*) fMemoryManager->allocate(2 * sizeof(XMLCh));//new XMLCh[2];
  1354. dummyStr[0] = (XMLCh) fOperations->getData();
  1355. dummyStr[1] = chNull;
  1356. fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
  1357. fFixedString = dummyStr;
  1358. }
  1359. }
  1360. fBMPattern = new (fMemoryManager) BMPattern(fFixedString, 256,
  1361.   isSet(fOptions, IGNORE_CASE));
  1362. }
  1363. else if (!isSet(fOptions, XMLSCHEMA_MODE) &&
  1364.  !isSet(fOptions, PROHIBIT_FIXED_STRING_OPTIMIZATION)) {
  1365. int fixedOpts = 0;
  1366. Token* tok = fTokenTree->findFixedString(fOptions, fixedOpts);
  1367. fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
  1368. fFixedString = (tok == 0) ? 0
  1369. : XMLString::replicate(tok->getString(), fMemoryManager);
  1370. if (fFixedString != 0 && XMLString::stringLen(fFixedString) < 2) {
  1371. fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
  1372. fFixedString = 0;
  1373. }
  1374. if (fFixedString != 0) {
  1375. fBMPattern = new (fMemoryManager) BMPattern(fFixedString, 256,
  1376.    isSet(fixedOpts, IGNORE_CASE));
  1377. }
  1378. }
  1379. }
  1380. unsigned short RegularExpression::getCharType(const XMLCh ch) {
  1381.     if (!isSet(fOptions, UNICODE_WORD_BOUNDARY)) {
  1382. if (isSet(fOptions, USE_UNICODE_CATEGORY)) {
  1383. if (fWordRange == 0) {
  1384. fWordRange = fTokenFactory->getRange(fgUniIsWord);
  1385. if (fWordRange == 0)
  1386. ThrowXML1(RuntimeException, XMLExcepts::Regex_RangeTokenGetError, fgUniIsWord);
  1387. }
  1388. return fWordRange->match(ch) ? WT_LETTER : WT_OTHER;
  1389. }
  1390. return RegxUtil::isWordChar(ch);
  1391.     }
  1392. switch (XMLUniCharacter::getType(ch)) {
  1393. case XMLUniCharacter::UPPERCASE_LETTER:
  1394. case XMLUniCharacter::LOWERCASE_LETTER:
  1395. case XMLUniCharacter::TITLECASE_LETTER:
  1396. case XMLUniCharacter::MODIFIER_LETTER:
  1397. case XMLUniCharacter::OTHER_LETTER:
  1398. case XMLUniCharacter::LETTER_NUMBER:
  1399. case XMLUniCharacter::DECIMAL_DIGIT_NUMBER:
  1400. case XMLUniCharacter::OTHER_NUMBER:
  1401. case XMLUniCharacter::COMBINING_SPACING_MARK:
  1402. return WT_LETTER;
  1403. case XMLUniCharacter::FORMAT:
  1404. case XMLUniCharacter::NON_SPACING_MARK:
  1405. case XMLUniCharacter::ENCLOSING_MARK:
  1406. return WT_IGNORE;
  1407. case XMLUniCharacter::CONTROL:
  1408. switch (ch) {
  1409. case chHTab:
  1410. case chLF:
  1411. case chVTab:
  1412. case chFF:
  1413. case chCR:
  1414. return WT_OTHER;
  1415. default:
  1416. return WT_IGNORE;
  1417. }
  1418. }
  1419.     return WT_OTHER;
  1420. }
  1421. XERCES_CPP_NAMESPACE_END
  1422. /**
  1423.   * End of file RegularExpression.cpp
  1424.   */