RegularExpression.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:33k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2001 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.5  2001/10/09 12:20:25  tng
  59.  * Leak fix: Need to delete fMatch if adopted.
  60.  *
  61.  * Revision 1.4  2001/05/11 21:50:58  knoaman
  62.  * Schema updates and fixes.
  63.  *
  64.  * Revision 1.3  2001/05/11 13:26:46  tng
  65.  * Copyright update.
  66.  *
  67.  * Revision 1.2  2001/05/03 18:17:42  knoaman
  68.  * Some design changes:
  69.  * o Changed the TokenFactory from a single static instance, to a
  70.  *    normal class. Each RegularExpression object will have its own
  71.  *    instance of TokenFactory, and that instance will be passed to
  72.  *    other classes that need to use a TokenFactory to create Token
  73.  *    objects (with the exception of RangeTokenMap).
  74.  * o Added a new class RangeTokenMap to map a the different ranges
  75.  *    in a given category to a specific RangeFactory object. In the old
  76.  *    design RangeFactory had dual functionality (act as a Map, and as
  77.  *    a factory for creating RangeToken(s)). The RangeTokenMap will
  78.  *    have its own copy of the TokenFactory. There will be only one
  79.  *    instance of the RangeTokenMap class, and that instance will be
  80.  *    lazily deleted when XPlatformUtils::Terminate is called.
  81.  *
  82.  * Revision 1.1  2001/03/02 19:22:52  knoaman
  83.  * Schema: Regular expression handling part I
  84.  *
  85.  */
  86. // ---------------------------------------------------------------------------
  87. //  Includes
  88. // ---------------------------------------------------------------------------
  89. #include <util/regx/RegularExpression.hpp>
  90. #include <util/XMLString.hpp>
  91. #include <util/PlatformUtils.hpp>
  92. #include <util/regx/RegxUtil.hpp>
  93. #include <util/regx/Match.hpp>
  94. #include <util/regx/RangeToken.hpp>
  95. #include <util/regx/RegxDefs.hpp>
  96. #include <util/regx/XMLUniCharacter.hpp>
  97. #include <util/regx/ParserForXMLSchema.hpp>
  98. #include <util/Janitor.hpp>
  99. #include <util/ParseException.hpp>
  100. // ---------------------------------------------------------------------------
  101. //  Static member data initialization
  102. // ---------------------------------------------------------------------------
  103. const unsigned int RegularExpression::MARK_PARENS = 1;
  104. const unsigned int RegularExpression::IGNORE_CASE = 2;
  105. const unsigned int RegularExpression::SINGLE_LINE = 4;
  106. const unsigned int RegularExpression::MULTIPLE_LINE = 8;
  107. const unsigned int RegularExpression::EXTENDED_COMMENT = 16;
  108. const unsigned int RegularExpression::USE_UNICODE_CATEGORY = 32;
  109. const unsigned int RegularExpression::UNICODE_WORD_BOUNDARY = 64;
  110. const unsigned int RegularExpression::PROHIBIT_HEAD_CHARACTER_OPTIMIZATION = 128;
  111. const unsigned int RegularExpression::PROHIBIT_FIXED_STRING_OPTIMIZATION = 256;
  112. const unsigned int RegularExpression::XMLSCHEMA_MODE = 512;
  113. const unsigned int RegularExpression::SPECIAL_COMMA = 1024;
  114. const unsigned short RegularExpression::WT_IGNORE = 0;
  115. const unsigned short RegularExpression::WT_LETTER = 1;
  116. const unsigned short RegularExpression::WT_OTHER = 2;
  117. RangeToken*          RegularExpression::fWordRange = 0;
  118. // ---------------------------------------------------------------------------
  119. //  RegularExpression::Context: Constructors and Destructor
  120. // ---------------------------------------------------------------------------
  121. RegularExpression::Context::Context() :
  122.     fInUse(false)
  123. , fAdoptMatch(false)
  124.     , fStart(0)
  125. , fLimit(0)
  126. , fLength(0)
  127. , fSize(0)
  128. , fOffsets(0)
  129. , fMatch(0)
  130. , fString(0)
  131. {
  132. }
  133. RegularExpression::Context::~Context()
  134. {
  135. delete [] fOffsets;
  136.     delete [] fString;
  137. if (fAdoptMatch)
  138. delete fMatch;
  139. }
  140. // ---------------------------------------------------------------------------
  141. //  RegularExpression::Context: Public methods
  142. // ---------------------------------------------------------------------------
  143. void RegularExpression::Context::reset(const XMLCh* const string
  144.                                        , const int start, const int limit
  145.                                        , const int noClosures)
  146. {
  147.     delete [] fString;
  148.     fString = XMLString::replicate(string);
  149. fStart = start;
  150. fLimit = limit;
  151. fLength = fLimit - fStart;
  152. fInUse = true;
  153. if (fAdoptMatch)
  154. delete fMatch;
  155. fMatch = 0;
  156. if (fOffsets == 0 || fSize != noClosures) {
  157. delete [] fOffsets;
  158. fOffsets = new int[noClosures];
  159. }
  160. fSize = noClosures;
  161. for (int i = 0; i< fSize; i++)
  162. fOffsets[i] = -1;
  163. }
  164. bool RegularExpression::Context::nextCh(XMLInt32& ch, int& offset,
  165. const short direction)
  166. {
  167. ch = fString[offset];
  168. if (RegxUtil::isHighSurrogate(ch)) {
  169. if ((offset + 1 < fLimit) && (direction > 0) &&
  170. RegxUtil::isLowSurrogate(fString[offset+1])) {
  171. ch = RegxUtil::composeFromSurrogate(ch, fString[++offset]);
  172. }
  173. else
  174. return false;
  175. }
  176. else if (RegxUtil::isLowSurrogate(ch)) {
  177. if ((offset - 1 >= 0) && (direction <= 0) &&
  178. RegxUtil::isHighSurrogate(fString[offset-1])) {
  179. ch = RegxUtil::composeFromSurrogate(fString[--offset], ch);
  180. }
  181. else
  182. return false;
  183. }
  184. return true;
  185. }
  186. // ---------------------------------------------------------------------------
  187. //  RegularExpression: Constructors and Destructors
  188. // ---------------------------------------------------------------------------
  189. RegularExpression::RegularExpression(const char* const pattern)
  190. :fHasBackReferences(false),
  191.  fFixedStringOnly(false),
  192.  fNoGroups(0),
  193.  fMinLength(0),
  194.  fNoClosures(0),
  195.  fOptions(0),
  196.  fContext(0),
  197.  fBMPattern(0),
  198.  fPattern(0),
  199.  fFixedString(0),
  200.  fOperations(0),
  201.  fTokenTree(0),
  202.  fFirstChar(0),
  203.      fTokenFactory(0)
  204. {
  205. try {
  206. XMLCh* tmpBuf = XMLString::transcode(pattern);
  207.         ArrayJanitor<XMLCh> janBuf(tmpBuf);
  208. setPattern(tmpBuf);
  209. }
  210. catch (...) {
  211. cleanUp();
  212. throw;
  213. }
  214. }
  215. RegularExpression::RegularExpression(const char* const pattern,
  216.  const char* const options)
  217. :fHasBackReferences(false),
  218.  fFixedStringOnly(false),
  219.  fNoGroups(0),
  220.  fMinLength(0),
  221.  fNoClosures(0),
  222.  fOptions(0),
  223.  fContext(0),
  224.  fBMPattern(0),
  225.  fPattern(0),
  226.  fFixedString(0),
  227.  fOperations(0),
  228.  fTokenTree(0),
  229.  fFirstChar(0)
  230. {
  231. try {
  232. XMLCh* tmpBuf = XMLString::transcode(pattern);
  233. ArrayJanitor<XMLCh> janBuf(tmpBuf);
  234. XMLCh* tmpOptions = XMLString::transcode(options);
  235. ArrayJanitor<XMLCh> janOps(tmpOptions);
  236. setPattern(tmpBuf, tmpOptions);
  237. }
  238. catch (...) {
  239. cleanUp();
  240. throw;
  241. }
  242. }
  243. RegularExpression::RegularExpression(const XMLCh* const pattern)
  244. :fHasBackReferences(false),
  245.  fFixedStringOnly(false),
  246.  fNoGroups(0),
  247.  fMinLength(0),
  248.  fNoClosures(0),
  249.  fOptions(0),
  250.  fContext(0),
  251.  fBMPattern(0),
  252.  fPattern(0),
  253.  fFixedString(0),
  254.  fOperations(0),
  255.  fTokenTree(0),
  256.  fFirstChar(0)
  257. {
  258. try {
  259. setPattern(pattern);
  260. }
  261. catch (...) {
  262. cleanUp();
  263. throw;
  264. }
  265. }
  266. RegularExpression::RegularExpression(const XMLCh* const pattern,
  267.  const XMLCh* const options)
  268. :fHasBackReferences(false),
  269.  fFixedStringOnly(false),
  270.  fNoGroups(0),
  271.  fMinLength(0),
  272.  fNoClosures(0),
  273.  fOptions(0),
  274.  fContext(0),
  275.  fBMPattern(0),
  276.  fPattern(0),
  277.  fFixedString(0),
  278.  fOperations(0),
  279.  fTokenTree(0),
  280.  fFirstChar(0)
  281. {
  282. try {
  283. setPattern(pattern, options);
  284. }
  285. catch (...) {
  286. cleanUp();
  287. throw;
  288. }
  289. }
  290. RegularExpression::~RegularExpression() {
  291. cleanUp();
  292. }
  293. // ---------------------------------------------------------------------------
  294. //  RegularExpression: Setter methods
  295. // ---------------------------------------------------------------------------
  296. void RegularExpression::setPattern(const XMLCh* const pattern,
  297.    const XMLCh* const options) {
  298.     fTokenFactory = new TokenFactory();
  299. fOptions = parseOptions(options);
  300. fPattern = XMLString::replicate(pattern);
  301. RegxParser* regxParser = isSet(fOptions, XMLSCHEMA_MODE)
  302. ? new ParserForXMLSchema() : new RegxParser();
  303.     if (regxParser) {
  304.         regxParser->setTokenFactory(fTokenFactory);
  305.     }
  306. Janitor<RegxParser> janRegxParser(regxParser);
  307. fTokenTree = regxParser->parse(fPattern, fOptions);
  308. fNoGroups = regxParser->getNoParen();
  309. fHasBackReferences = regxParser->hasBackReferences();
  310. }
  311. // ---------------------------------------------------------------------------
  312. //  RegularExpression: Matching methods
  313. // ---------------------------------------------------------------------------
  314. bool RegularExpression::matches(const char* const expression) {
  315.     XMLCh* tmpBuf = XMLString::transcode(expression);
  316.     ArrayJanitor<XMLCh> janBuf(tmpBuf);
  317. return matches(tmpBuf, 0, XMLString::stringLen(tmpBuf), 0);
  318. }
  319. bool RegularExpression::matches(const char* const expression,
  320. const int start, const int end) {
  321. XMLCh* tmpBuf = XMLString::transcode(expression);
  322.     ArrayJanitor<XMLCh> janBuf(tmpBuf);
  323. return matches(tmpBuf, start, end, 0);
  324. }
  325. bool RegularExpression::matches(const char* const expression,
  326. Match* const match) {
  327. XMLCh* tmpBuf = XMLString::transcode(expression);
  328.     ArrayJanitor<XMLCh> janBuf(tmpBuf);
  329. return matches(tmpBuf, 0, XMLString::stringLen(tmpBuf), match);
  330. }
  331. bool RegularExpression::matches(const char* const expression, const int start,
  332.                                 const int end, Match* const pMatch) {
  333. XMLCh* tmpBuf = XMLString::transcode(expression);
  334.     ArrayJanitor<XMLCh> janBuf(tmpBuf);
  335. return matches(tmpBuf, start, end, pMatch);
  336. }
  337. // ---------------------------------------------------------------------------
  338. //  RegularExpression: Matching methods - Wide char version
  339. // ---------------------------------------------------------------------------
  340. bool RegularExpression::matches(const XMLCh* const expression) {
  341. return matches(expression, 0, XMLString::stringLen(expression), 0);
  342. }
  343. bool RegularExpression::matches(const XMLCh* const expression,
  344. const int start, const int end) {
  345. return matches(expression, start, end, 0);
  346. }
  347. bool RegularExpression::matches(const XMLCh* const expression,
  348. Match* const match) {
  349. return matches(expression, 0, XMLString::stringLen(expression), match);
  350. }
  351. bool RegularExpression::matches(const XMLCh* const expression, const int start,
  352.                                 const int end, Match* const pMatch) {
  353. if (fOperations == 0)
  354. prepare();
  355. Context* context = 0;
  356. Context* tmpContext = 0;
  357. int  strLength = XMLString::stringLen(expression);
  358. {
  359. XMLMutexLock lockInit(&fMutex);
  360. if (fContext == 0)
  361. fContext = new Context();
  362. if (fContext->fInUse) {
  363. context = new Context();
  364. tmpContext = context;
  365. }
  366. else {
  367. context = fContext;
  368. }
  369. context->reset(expression, start, end, fNoClosures);
  370. }
  371. Janitor<Context> janContext(tmpContext);
  372. bool adoptMatch = false;
  373. Match* lMatch = pMatch;
  374. if (lMatch != 0) {
  375. lMatch->setNoGroups(fNoGroups);
  376. }
  377. else if (fHasBackReferences) {
  378. lMatch = new Match();
  379. lMatch->setNoGroups(fNoGroups);
  380. adoptMatch = true;
  381. }
  382. if (context->fAdoptMatch)
  383. delete context->fMatch;
  384.     context->fMatch = lMatch;
  385. context->fAdoptMatch = adoptMatch;
  386. if (isSet(fOptions, XMLSCHEMA_MODE)) {
  387. int matchEnd = match(context, fOperations, context->fStart, 1);
  388. if (matchEnd == context->fLimit) {
  389. if (context->fMatch != 0) {
  390. context->fMatch->setStartPos(0, context->fStart);
  391. context->fMatch->setEndPos(0, matchEnd);
  392. }
  393. context->fInUse = false;
  394. return true;
  395. }
  396. return false;
  397. }
  398. /*
  399.  * If the pattern has only fixed string, use Boyer-Moore
  400.  */
  401. if (fFixedStringOnly) {
  402. int ret = fBMPattern->matches(expression, context->fStart,
  403.                           context->fLimit);
  404. if (ret >= 0) {
  405. if (context->fMatch != 0) {
  406. context->fMatch->setStartPos(0, ret);
  407. context->fMatch->setEndPos(0, ret + strLength);
  408. }
  409. context->fInUse = false;
  410. return true;
  411. }
  412. context->fInUse = false;
  413. return false;
  414. }
  415. /*
  416.  * If the pattern contains a fixed string, we check with Boyer-Moore
  417.  * whether the text contains the fixed string or not. If not found
  418.  * return false
  419.  */
  420. if (fFixedString != 0) {
  421. int ret = fBMPattern->matches(expression, context->fStart,
  422.                                       context->fLimit);
  423. if (ret < 0) { // No match
  424. context->fInUse = false;
  425. return false;
  426. }
  427. }
  428. int limit = context->fLimit - fMinLength;
  429. int matchStart;
  430. int matchEnd = -1;
  431. /*
  432.  * Check whether the expression start with ".*"
  433.  */
  434. if (fOperations != 0 && fOperations->getOpType() == Op::CLOSURE
  435.         && fOperations->getChild()->getOpType() == Op::DOT) {
  436. if (isSet(fOptions, SINGLE_LINE)) {
  437. matchStart = context->fStart;
  438. matchEnd = match(context, fOperations, matchStart, 1);
  439. }
  440. else {
  441. bool previousIsEOL = true;
  442. for (matchStart=context->fStart; matchStart<=limit; matchStart++) {
  443. XMLCh ch = expression[matchStart];
  444. if (RegxUtil::isEOLChar(ch)) {
  445. previousIsEOL = true;
  446. }
  447. else {
  448. if (previousIsEOL) {
  449. if (0 <= (matchEnd = match(context, fOperations,
  450.                                                    matchStart, 1)))
  451.                             break;
  452. }
  453. previousIsEOL = false;
  454. }
  455. }
  456. }
  457. }
  458. else {
  459.         /*
  460.          * Optimization against the first char
  461.          */
  462. if (fFirstChar != 0) {
  463. bool ignoreCase = isSet(fOptions, IGNORE_CASE);
  464. RangeToken* range = fFirstChar;
  465. if (ignoreCase)
  466. range = fFirstChar->getCaseInsensitiveToken(fTokenFactory);
  467. for (matchStart=context->fStart; matchStart<=limit; matchStart++) {
  468.                 XMLInt32 ch;
  469. if (!context->nextCh(ch, matchStart, 1))
  470. break;
  471. if (!range->match(ch)) {
  472. if (!ignoreCase)
  473. continue;
  474. // Perform case insensitive match
  475. // REVISIT
  476. continue;
  477. }
  478. if (0 <= (matchEnd = match(context,fOperations,matchStart,1)))
  479. break;
  480.             }
  481. }
  482. else {
  483.             /*
  484.              * Straightforward matching
  485.              */
  486. for (matchStart=context->fStart; matchStart<=limit; matchStart++) {
  487. if (0 <= (matchEnd = match(context,fOperations,matchStart,1)))
  488. break;
  489. }
  490. }
  491. }
  492. if (matchEnd >= 0) {
  493. if (context->fMatch != 0) {
  494. context->fMatch->setStartPos(0, matchStart);
  495. context->fMatch->setEndPos(0, matchEnd);
  496. }
  497. context->fInUse = false;
  498. return true;
  499. }
  500. context->fInUse = false;
  501. return false;
  502. }
  503. // ---------------------------------------------------------------------------
  504. //  RegularExpression: Helpers methods
  505. // ---------------------------------------------------------------------------
  506. int RegularExpression::getOptionValue(const XMLCh ch) {
  507. int ret = 0;
  508. switch (ch) {
  509. case chLatin_i:
  510. ret = IGNORE_CASE;
  511. break;
  512. case chLatin_m:
  513. ret = MULTIPLE_LINE;
  514. break;
  515. case chLatin_s:
  516. ret = SINGLE_LINE;
  517. break;
  518. case chLatin_x:
  519. ret = EXTENDED_COMMENT;
  520. break;
  521. case chLatin_u:
  522. ret = USE_UNICODE_CATEGORY;
  523. break;
  524. case chLatin_w:
  525. ret = UNICODE_WORD_BOUNDARY;
  526. break;
  527. case chLatin_F:
  528. ret = PROHIBIT_FIXED_STRING_OPTIMIZATION;
  529. break;
  530. case chLatin_H:
  531. ret = PROHIBIT_HEAD_CHARACTER_OPTIMIZATION;
  532. break;
  533. case chLatin_X:
  534. ret = XMLSCHEMA_MODE;
  535. break;
  536. case chComma:
  537. ret = SPECIAL_COMMA;
  538. break;
  539. default:
  540. break;
  541. }
  542. return ret;
  543. }
  544. int RegularExpression::match(Context* const context, const Op* const operations
  545.  , int offset, const short direction)
  546. {
  547. const Op* tmpOp = operations;
  548. bool ignoreCase = isSet(fOptions, IGNORE_CASE);
  549. while (true) {
  550. if (tmpOp == 0)
  551. break;
  552. if (offset > context->fLimit || offset < context->fStart)
  553. return -1;
  554. switch(tmpOp->getOpType()) {
  555. case Op::CHAR:
  556. if (!matchChar(context, tmpOp->getData(), offset, direction,
  557.    ignoreCase))
  558. return -1;
  559. tmpOp = tmpOp->getNextOp();
  560. break;
  561. case Op::DOT:
  562. if (!matchDot(context, offset, direction))
  563. return -1;
  564. tmpOp = tmpOp->getNextOp();
  565. break;
  566. case Op::RANGE:
  567. case Op::NRANGE:
  568. if (!matchRange(context, tmpOp, offset, direction, ignoreCase))
  569. return -1;
  570. tmpOp = tmpOp->getNextOp();
  571. break;
  572. case Op::ANCHOR:
  573. if (!matchAnchor(context, tmpOp->getData(), offset))
  574. return -1;
  575. tmpOp->getNextOp();
  576. break;
  577. case Op::BACKREFERENCE:
  578. if (!matchBackReference(context, tmpOp->getData(), offset,
  579. direction, ignoreCase))
  580. return -1;
  581. tmpOp->getNextOp();
  582. break;
  583. case Op::STRING:
  584. if (!matchString(context, tmpOp->getLiteral(), offset, direction,
  585.  ignoreCase))
  586. return -1;
  587. tmpOp = tmpOp->getNextOp();
  588. break;
  589. case Op::CLOSURE:
  590. {
  591. XMLInt32 id = tmpOp->getData();
  592. if (id >= 0) {
  593. int prevOffset = context->fOffsets[id];
  594. if (prevOffset < 0 || prevOffset != offset) {
  595. context->fOffsets[id] = offset;
  596. }
  597. else {
  598. context->fOffsets[id] = -1;
  599. tmpOp = tmpOp->getNextOp();
  600. break;
  601. }
  602. }
  603. int ret = match(context, tmpOp->getChild(), offset, direction);
  604. if (id >= 0) {
  605. context->fOffsets[id] = -1;
  606. }
  607. if (ret >= 0)
  608. return ret;
  609. tmpOp = tmpOp->getNextOp();
  610. }
  611. break;
  612. case Op::QUESTION:
  613. {
  614. int ret = match(context, tmpOp->getChild(), offset, direction);
  615. if (ret >= 0)
  616. return ret;
  617. tmpOp = tmpOp->getNextOp();
  618. }
  619. break;
  620. case Op::NONGREEDYCLOSURE:
  621. case Op::NONGREEDYQUESTION:
  622. {
  623. int ret = match(context,tmpOp->getNextOp(),offset,direction);
  624. if (ret >= 0)
  625. return ret;
  626. tmpOp = tmpOp->getChild();
  627. }
  628. break;
  629. case Op::UNION:
  630. {
  631. return matchUnion(context, tmpOp, offset, direction);
  632. }
  633. case Op::CAPTURE:
  634. if (context->fMatch != 0 && tmpOp->getData() != 0)
  635. return matchCapture(context, tmpOp, offset, direction);
  636. tmpOp = tmpOp->getNextOp();
  637. break;
  638. case Op::LOOKAHEAD:
  639. if (0 > match(context, tmpOp->getChild(), offset, 1))
  640. return -1;
  641. tmpOp = tmpOp->getNextOp();
  642. break;
  643. case Op::NEGATIVELOOKAHEAD:
  644. if (0 <= match(context, tmpOp->getChild(), offset, 1))
  645. return -1;
  646. tmpOp = tmpOp->getNextOp();
  647. break;
  648. case Op::LOOKBEHIND:
  649. if (0 > match(context, tmpOp->getChild(), offset, -1))
  650. return - 1;
  651. tmpOp = tmpOp->getNextOp();
  652. break;
  653. case Op::NEGATIVELOOKBEHIND:
  654. if (0 <= match(context, tmpOp->getChild(), offset, -1))
  655. return -1;
  656. tmpOp = tmpOp->getNextOp();
  657. break;
  658. case Op::INDEPENDENT:
  659.         case Op::MODIFIER:
  660. {
  661. int ret = (tmpOp->getOpType() == Op::INDEPENDENT)
  662.    ? match(context, tmpOp->getChild(), offset, direction)
  663.                        : matchModifier(context, tmpOp, offset, direction);
  664.                 if (ret < 0)
  665.                     return ret;
  666. offset = ret;
  667. tmpOp = tmpOp->getNextOp();
  668. }
  669. break;
  670. case Op::CONDITION:
  671. if (tmpOp->getRefNo() >= fNoGroups)
  672. return -1;
  673. if (matchCondition(context, tmpOp, offset, direction))
  674. tmpOp = tmpOp->getYesFlow();
  675. else
  676. if (tmpOp->getNoFlow() != 0)
  677.                     tmpOp = tmpOp->getNoFlow();
  678.                 else
  679.                     tmpOp = tmpOp->getNextOp();
  680. break;
  681. }
  682. }
  683. return offset;
  684. }
  685. bool RegularExpression::matchChar(Context* const context,
  686.   const XMLInt32 ch, int& offset,
  687.   const short direction, const bool ignoreCase)
  688. {
  689. int tmpOffset = direction > 0 ? offset : offset - 1;
  690. if (tmpOffset >= context->fLimit || tmpOffset < 0)
  691. return false;
  692. XMLInt32 strCh = 0;
  693. if (!context->nextCh(strCh, tmpOffset, direction))
  694. return false;
  695. bool match = ignoreCase ? matchIgnoreCase(ch, strCh)
  696.                     : (ch == strCh);
  697. if (!match)
  698. return false;
  699. offset = (direction > 0) ? ++tmpOffset : tmpOffset;
  700. return true;
  701. }
  702. bool RegularExpression::matchDot(Context* const context, int& offset,
  703.  const short direction)
  704. {
  705. int tmpOffset = direction > 0 ? offset : offset - 1;
  706. if (tmpOffset >= context->fLimit || tmpOffset < 0)
  707. return false;
  708. XMLInt32 strCh = 0;
  709. if (!context->nextCh(strCh, tmpOffset, direction))
  710. return false;
  711. if (!isSet(fOptions, SINGLE_LINE)) {
  712. if (direction > 0 && RegxUtil::isEOLChar(strCh))
  713. return false;
  714. if (direction <= 0 && !RegxUtil::isEOLChar(strCh) )
  715. return false;
  716. }
  717.     offset = (direction > 0) ? ++tmpOffset : tmpOffset;
  718. return true;
  719. }
  720. bool RegularExpression::matchRange(Context* const context, const Op* const op,
  721.    int& offset, const short direction,
  722.    const bool ignoreCase)
  723. {
  724. int tmpOffset = direction > 0 ? offset : offset - 1;
  725. if (tmpOffset >= context->fLimit || tmpOffset < 0)
  726. return false;
  727. XMLInt32 strCh = 0;
  728. if (!context->nextCh(strCh, tmpOffset, direction))
  729. return false;
  730. RangeToken* tok = (RangeToken *) op->getToken();
  731. bool match = false;
  732. if (ignoreCase) {
  733. //REVISIT we should match ignoring case, but for now
  734. //we will do a normal match
  735. //tok = tok->getCaseInsensitiveToken();
  736. //if (!token->match(strCh)) {
  737. // if (strCh > 0x10000)
  738. // return -1;
  739. // Do case insensitive matching - uppercase match
  740. // or lowercase match
  741. //}
  742. match = tok->match(strCh);
  743. }
  744. else
  745. match = tok->match(strCh);
  746. if (!match)
  747. return false;
  748. offset = (direction > 0) ? ++tmpOffset : tmpOffset;
  749. return true;
  750. }
  751. bool RegularExpression::matchAnchor(Context* const context, const XMLInt32 ch,
  752. const int offset)
  753. {
  754. switch ((XMLCh) ch) {
  755. case chLatin_A:
  756. if (offset != context->fStart)
  757. return false;
  758. break;
  759. case chLatin_B:
  760. if (context->fLength == 0)
  761. break;
  762. {
  763. int after = getWordType(context->fString, context->fStart,
  764. context->fLimit, offset);
  765. if (after == WT_IGNORE
  766. || after == getPreviousWordType(context->fString,
  767. context->fStart,
  768. context->fLimit, offset))
  769. break;
  770. }
  771. return false;
  772. case chLatin_b:
  773. if (context->fLength == 0)
  774. return false;
  775. {
  776. int after = getWordType(context->fString, context->fStart,
  777. context->fLimit, offset);
  778. if (after == WT_IGNORE
  779. || after == getPreviousWordType(context->fString,
  780. context->fStart
  781. , context->fLimit, offset))
  782. return false;
  783. }
  784. break;
  785. case chLatin_Z:
  786. case chDollarSign:
  787. if ( (XMLCh) ch == chDollarSign && isSet(fOptions, MULTIPLE_LINE)) {
  788. if (!(offset == context->fLimit || (offset < context->fLimit
  789. && RegxUtil::isEOLChar(context->fString[offset]))))
  790. return false;
  791. }
  792. else {
  793. if (!(offset == context->fLimit
  794. || (offset+1 == context->fLimit
  795.     && RegxUtil::isEOLChar(context->fString[offset]))
  796. || (offset+2 == context->fLimit
  797.     && context->fString[offset] == chCR
  798. && context->fString[offset+1] == chLF)))
  799. return false;
  800. }
  801. break;
  802. case chLatin_z:
  803. if (offset != context->fLimit)
  804. return false;
  805. break;
  806. case chAt:
  807. case chCaret:
  808. if ( (XMLCh) ch == chCaret && !isSet(fOptions, MULTIPLE_LINE)) {
  809. if (offset != context->fStart)
  810. return false;
  811. }
  812. else {
  813. if (!(offset == context->fStart || (offset > context->fStart
  814.       && RegxUtil::isEOLChar(context->fString[offset-1]))))
  815. return false;
  816. }
  817. break;
  818. case chOpenAngle:
  819. if (context->fLength == 0 || offset == context->fLimit)
  820. return false;
  821. if (getWordType(context->fString, context->fStart, context->fLimit,
  822. offset) != WT_LETTER
  823. || getPreviousWordType(context->fString, context->fStart,
  824.    context->fLimit, offset) != WT_OTHER)
  825. return false;
  826. break;
  827. case chCloseAngle:
  828. if (context->fLength == 0 || offset == context->fStart)
  829. return false;
  830. if (getWordType(context->fString, context->fStart, context->fLimit,
  831. offset) != WT_OTHER
  832. || getPreviousWordType(context->fString, context->fStart,
  833.    context->fLimit, offset) != WT_LETTER)
  834. return false;
  835. break;
  836. }
  837. return true;
  838. }
  839. bool RegularExpression::matchBackReference(Context* const context,
  840.    const XMLInt32 refNo, int& offset,
  841.    const short direction,
  842.    const bool ignoreCase)
  843. {
  844. if (refNo <=0 || refNo >= fNoGroups)
  845. ThrowXML(IllegalArgumentException, XMLExcepts::Regex_BadRefNo);
  846. if (context->fMatch->getStartPos(refNo) < 0
  847. || context->fMatch->getEndPos(refNo) < 0)
  848. return false;
  849. int start = context->fMatch->getStartPos(refNo);
  850. int length = context->fMatch->getEndPos(refNo) - start;
  851. int tmpOffset = (direction > 0) ? offset : offset - length;
  852. if (context->fLimit - tmpOffset < length)
  853. return false;
  854. bool match = ignoreCase
  855. ? XMLString::regionIMatches(context->fString,tmpOffset,
  856. context->fString,start,length)
  857. : XMLString::regionMatches(context->fString, tmpOffset,
  858.    context->fString, start,length);
  859. if (!match)
  860. return false;
  861. offset = (direction > 0) ? offset + length : offset - length;
  862. return true;
  863. }
  864. bool RegularExpression::matchString(Context* const context,
  865. const XMLCh* const literal, int& offset,
  866. const short direction, const bool ignoreCase)
  867. {
  868. int length = XMLString::stringLen(literal);
  869. int tmpOffset = (direction > 0) ? offset : offset - length;
  870. if (context->fLimit - tmpOffset < length)
  871. return false;
  872. bool match = ignoreCase
  873. ? XMLString::regionIMatches(context->fString, tmpOffset,
  874. literal, 0, length)
  875. : XMLString::regionMatches(context->fString, tmpOffset,
  876.    literal, 0, length);
  877. if (match) {
  878.     offset = direction > 0 ? offset + length : offset - length;
  879.     }
  880. return match;
  881. }
  882. int RegularExpression::matchCapture(Context* const context, const Op* const op,
  883.                                     int offset, const short direction)
  884. {
  885. // No check is made for nullness of fMatch as the function is only called if
  886. // fMatch is not null.
  887. XMLInt32 index = op->getData();
  888. int save = (index > 0) ? context->fMatch->getStartPos(index)
  889.                            : context->fMatch->getEndPos(-index);
  890. if (index > 0) {
  891. context->fMatch->setStartPos(index, offset);
  892. int ret = match(context, op->getNextOp(), offset, direction);
  893. if (ret < 0)
  894. context->fMatch->setStartPos(index, save);
  895. return ret;
  896. }
  897. context->fMatch->setEndPos(-index, offset);
  898. int ret = match(context, op->getNextOp(), offset, direction);
  899. if (ret < 0)
  900. context->fMatch->setEndPos(-index, save);
  901. return ret;
  902. }
  903. bool RegularExpression::matchCondition(Context* const context,
  904.                                               const Op* const op, int offset,
  905.                                               const short direction)
  906. {
  907. int refNo = op->getRefNo();
  908. if ( refNo > 0)
  909. return (context->fMatch->getStartPos(refNo) >= 0
  910.                 && context->fMatch->getEndPos(refNo) >= 0);
  911. return (0 <= match(context, op->getConditionFlow(), offset, direction));
  912. }
  913. int RegularExpression::parseOptions(const XMLCh* const options)
  914. {
  915. if (options == 0)
  916. return 0;
  917. int opts = 0;
  918. int length = XMLString::stringLen(options);
  919. for (int i=0; i < length; i++) {
  920. int v = getOptionValue(options[i]);
  921. if (v == 0)
  922. ThrowXML1(ParseException, XMLExcepts::Regex_UnknownOption, options);
  923. opts |= v;
  924. }
  925. return opts;
  926. }
  927. void RegularExpression::compile(const Token* const token) {
  928. if (fOperations != 0)
  929. return;
  930. fNoClosures = 0;
  931. fOperations = compile(token, 0, false);
  932. }
  933. Op* RegularExpression::compile(const Token* const token, Op* const next,
  934.    const bool reverse) {
  935. Op* ret = 0;
  936. const unsigned short tokenType = token->getTokenType();
  937. switch(tokenType) {
  938. case Token::DOT:
  939. case Token::CHAR:
  940. case Token::ANCHOR:
  941. case Token::RANGE:
  942. case Token::NRANGE:
  943. case Token::STRING:
  944. case Token::BACKREFERENCE:
  945. case Token::EMPTY:
  946. ret = compileSingle(token, next, tokenType);
  947. break;
  948. case Token::CONCAT:
  949. ret = compileConcat(token, next, reverse);
  950. break;
  951. case Token::UNION:
  952. ret = compileUnion(token, next, reverse);
  953. break;
  954. case Token::CLOSURE:
  955. case Token::NONGREEDYCLOSURE:
  956. ret = compileClosure(token, next, reverse, tokenType);
  957. break;
  958. case Token::PAREN:
  959. ret = compileParenthesis(token, next, reverse);
  960. break;
  961. case Token::LOOKAHEAD:
  962. case Token::NEGATIVELOOKAHEAD:
  963. ret = compileLook(token, next, false, tokenType);
  964. break;
  965. case Token::LOOKBEHIND:
  966. case Token::NEGATIVELOOKBEHIND:
  967. ret = compileLook(token, next, true, tokenType);
  968. break;
  969. case Token::INDEPENDENT:
  970. case Token::MODIFIERGROUP:
  971. ret = compileLook(token, next, reverse, tokenType);
  972. break;
  973. case Token::CONDITION:
  974. ret = compileCondition(token, next, reverse);
  975. break;
  976. default:
  977. ThrowXML(RuntimeException, XMLExcepts::Regex_UnknownTokenType);
  978. break; // this line to be deleted
  979. }
  980. return ret;
  981. }
  982. /*
  983.  * Prepares for matching. This method is called just before starting matching
  984.  */
  985. void RegularExpression::prepare() {
  986. XMLMutexLock lockInit(&fMutex);
  987. compile(fTokenTree);
  988. if (fOperations->getOpType() == Op::CLOSURE &&
  989. fOperations->getChild()->getOpType() == Op::DOT) {
  990. Op* anchor = fOpFactory.createAnchorOp(isSet(fOptions, SINGLE_LINE) ? chLatin_A
  991.  : chAt);
  992. anchor->setNextOp(fOperations);
  993. fOperations = anchor;
  994. }
  995. fMinLength = fTokenTree->getMinLength();
  996. fFirstChar = 0;
  997. if (!isSet(fOptions, PROHIBIT_HEAD_CHARACTER_OPTIMIZATION) &&
  998. !isSet(fOptions, XMLSCHEMA_MODE)) {
  999. RangeToken* rangeTok = fTokenFactory->createRange();
  1000. int result = fTokenTree->analyzeFirstCharacter(rangeTok, fOptions, fTokenFactory);
  1001. if (result == Token::FC_TERMINAL) {
  1002. rangeTok->compactRanges();
  1003. fFirstChar = rangeTok;
  1004. }
  1005. }
  1006. if (fOperations != 0 && fOperations->getNextOp() == 0 &&
  1007. (fOperations->getOpType() == Op::STRING ||
  1008.  fOperations->getOpType() == Op::CHAR) )  {
  1009. fFixedStringOnly = true;
  1010. if (fOperations->getOpType() == Op::STRING) {
  1011. delete [] fFixedString;
  1012. fFixedString = XMLString::replicate(fOperations->getLiteral());
  1013. }
  1014. else{
  1015. XMLInt32 ch = fOperations->getData();
  1016. if ( ch >= 0x10000) { // add as constant
  1017. delete [] fFixedString;
  1018. fFixedString = RegxUtil::decomposeToSurrogates(ch);
  1019. }
  1020. else {
  1021. XMLCh* dummyStr = new XMLCh[2];
  1022. dummyStr[0] = (XMLCh) fOperations->getData();
  1023. dummyStr[1] = chNull;
  1024. delete [] fFixedString;
  1025. fFixedString = dummyStr;
  1026. }
  1027. }
  1028. fBMPattern = new BMPattern(fFixedString, 256,
  1029.   isSet(fOptions, IGNORE_CASE));
  1030. }
  1031. else if (!isSet(fOptions, XMLSCHEMA_MODE) &&
  1032.  !isSet(fOptions, PROHIBIT_FIXED_STRING_OPTIMIZATION)) {
  1033. int fixedOpts = 0;
  1034. Token* tok = fTokenTree->findFixedString(fOptions, fixedOpts);
  1035. delete [] fFixedString;
  1036. fFixedString = (tok == 0) ? 0
  1037. : XMLString::replicate(tok->getString());
  1038. if (fFixedString != 0 && XMLString::stringLen(fFixedString) < 2) {
  1039. delete [] fFixedString;
  1040. fFixedString = 0;
  1041. }
  1042. if (fFixedString != 0) {
  1043. fBMPattern = new BMPattern(fFixedString, 256,
  1044.    isSet(fixedOpts, IGNORE_CASE));
  1045. }
  1046. }
  1047. }
  1048. unsigned short RegularExpression::getCharType(const XMLCh ch) {
  1049.     if (!isSet(fOptions, UNICODE_WORD_BOUNDARY)) {
  1050. if (isSet(fOptions, USE_UNICODE_CATEGORY)) {
  1051. if (fWordRange == 0) {
  1052. fWordRange = fTokenFactory->getRange(fgUniIsWord);
  1053. if (fWordRange == 0)
  1054. ThrowXML1(RuntimeException, XMLExcepts::Regex_RangeTokenGetError, fgUniIsWord);
  1055. }
  1056. return fWordRange->match(ch) ? WT_LETTER : WT_OTHER;
  1057. }
  1058. return RegxUtil::isWordChar(ch);
  1059.     }
  1060. switch (XMLUniCharacter::getType(ch)) {
  1061. case XMLUniCharacter::UPPERCASE_LETTER:
  1062. case XMLUniCharacter::LOWERCASE_LETTER:
  1063. case XMLUniCharacter::TITLECASE_LETTER:
  1064. case XMLUniCharacter::MODIFIER_LETTER:
  1065. case XMLUniCharacter::OTHER_LETTER:
  1066. case XMLUniCharacter::LETTER_NUMBER:
  1067. case XMLUniCharacter::DECIMAL_DIGIT_NUMBER:
  1068. case XMLUniCharacter::OTHER_NUMBER:
  1069. case XMLUniCharacter::COMBINING_SPACING_MARK:
  1070. return WT_LETTER;
  1071. case XMLUniCharacter::FORMAT:
  1072. case XMLUniCharacter::NON_SPACING_MARK:
  1073. case XMLUniCharacter::ENCLOSING_MARK:
  1074. return WT_IGNORE;
  1075. case XMLUniCharacter::CONTROL:
  1076. switch (ch) {
  1077. case chHTab:
  1078. case chLF:
  1079. case chVTab:
  1080. case chFF:
  1081. case chCR:
  1082. return WT_OTHER;
  1083. default:
  1084. return WT_IGNORE;
  1085. }
  1086. }
  1087.     return WT_OTHER;
  1088. }
  1089. /**
  1090.   * End of file RegularExpression.cpp
  1091.   */