source: icXML/icXML-devel/src/xercesc/util/regx/RegularExpression.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 52.4 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: RegularExpression.cpp 822158 2009-10-06 07:52:59Z amassari $
20 */
21
22// ---------------------------------------------------------------------------
23//  Includes
24// ---------------------------------------------------------------------------
25#include <icxercesc/util/regx/RegularExpression.hpp>
26#include <icxercesc/util/PlatformUtils.hpp>
27#include <xercesc/util/regx/Match.hpp>
28#include <xercesc/util/regx/RangeToken.hpp>
29#include <xercesc/util/regx/RegxDefs.hpp>
30#include <xercesc/util/regx/XMLUniCharacter.hpp>
31#include <xercesc/util/regx/ParserForXMLSchema.hpp>
32#include <xercesc/util/Janitor.hpp>
33#include <xercesc/util/ParseException.hpp>
34#include <xercesc/util/IllegalArgumentException.hpp>
35#include <icxercesc/framework/XMLBuffer.hpp>
36#include <xercesc/util/OutOfMemoryException.hpp>
37#include <xercesc/util/XMLInitializer.hpp>
38#include <xercesc/util/XMLUniDefs.hpp>
39#include <xercesc/util/ValueStackOf.hpp>
40
41XERCES_CPP_NAMESPACE_BEGIN
42
43// ---------------------------------------------------------------------------
44//  Static member data initialization
45// ---------------------------------------------------------------------------
46const unsigned int RegularExpression::IGNORE_CASE = 2;
47const unsigned int RegularExpression::SINGLE_LINE = 4;
48const unsigned int RegularExpression::MULTIPLE_LINE = 8;
49const unsigned int RegularExpression::EXTENDED_COMMENT = 16;
50const unsigned int RegularExpression::PROHIBIT_HEAD_CHARACTER_OPTIMIZATION = 128;
51const unsigned int RegularExpression::PROHIBIT_FIXED_STRING_OPTIMIZATION = 256;
52const unsigned int RegularExpression::XMLSCHEMA_MODE = 512;
53RangeToken*        RegularExpression::fWordRange = 0;
54
55bool RegularExpression::matchIgnoreCase(const XMLInt32 ch1,
56                                        const XMLInt32 ch2) const
57{
58    if (ch1 >= 0x10000)
59    {
60        XMLCh string1[2];
61        XMLCh string2[2];
62
63        RegxUtil::decomposeToSurrogates(ch1, string1[0], string1[1]);
64
65        if (ch2 >= 0x10000)
66        {
67            RegxUtil::decomposeToSurrogates(ch2, string2[0], string2[1]);
68        }
69        else
70        {
71            // XMLString::compareNIString is broken, because it assume the
72            // two strings must be of the same length.  Note that two strings
73            // of different length could compare as equal, because there is no
74            // guarantee that a Unicode code point that is encoded in UTF-16 as
75            // a surrogate pair does not have a case mapping to a code point
76            // that is not in the surrogate range.  Just to be safe, we pad the
77            // shorter string with a space, which cannot hvae a case mapping.
78            string2[0] = (XMLCh)ch2;
79            string2[1] = chSpace;
80        }
81
82        return (0==XMLString::compareNIString(string1, string2, 2));
83    }
84    else if (ch2 >= 0x10000)
85    {
86        const XMLCh string1[2] = { (XMLCh)ch1, chSpace };
87        XMLCh string2[2];
88
89        RegxUtil::decomposeToSurrogates(ch2, string2[0], string2[1]);
90
91        return (0==XMLString::compareNIString(string1, string2, 2));
92    }
93    else
94    {
95        const XMLCh  char1 = (XMLCh)ch1;
96        const XMLCh  char2 = (XMLCh)ch2;
97
98        return (0==XMLString::compareNIString(&char1, &char2, 1));
99    }
100}
101
102
103
104// ---------------------------------------------------------------------------
105//  RegularExpression::Context: Constructors and Destructor
106// ---------------------------------------------------------------------------
107RegularExpression::Context::Context(MemoryManager* const manager) :
108    fAdoptMatch(false)
109    , fStart(0)
110    , fLimit(0)
111    , fLength(0)
112    , fSize(0)
113    , fStringMaxLen(0)
114    , fOffsets(0)
115    , fMatch(0)
116    , fString(0)
117    , fOptions(0)
118    , fMemoryManager(manager)
119{
120}
121
122RegularExpression::Context::Context(Context* src) :
123    fAdoptMatch(false)
124    , fStart(src->fStart)
125    , fLimit(src->fLimit)
126    , fLength(src->fLength)
127    , fSize(src->fSize)
128    , fStringMaxLen(src->fStringMaxLen)
129    , fOffsets(0)
130    , fMatch(0)
131    , fString(src->fString)
132    , fOptions(src->fOptions)
133    , fMemoryManager(src->fMemoryManager)
134{
135    if(src->fOffsets)
136    {
137        fOffsets = (int*) fMemoryManager->allocate(fSize* sizeof(int));
138        for (int i = 0; i< fSize; i++)
139            fOffsets[i] = src->fOffsets[i];
140    }
141    if(src->fMatch)
142    {
143        fMatch=new (fMemoryManager) Match(*src->fMatch);
144        fAdoptMatch=true;
145    }
146}
147
148RegularExpression::Context& RegularExpression::Context::operator=(const RegularExpression::Context& other)
149{
150    if (this != &other)
151    {
152        fStart=other.fStart;
153        fLimit=other.fLimit;
154        fLength=other.fLength;
155        fStringMaxLen=other.fStringMaxLen;
156        fString=other.fString;
157        fOptions=other.fOptions;
158
159        // if offset and match are already allocated with the right size, reuse them
160        // (fMatch can be provided by the user to get the data back)
161        if(fMatch && other.fMatch && fMatch->getNoGroups()==other.fMatch->getNoGroups())
162            *fMatch=*other.fMatch;
163        else
164        {
165            if (fAdoptMatch)
166                delete fMatch;
167            fMatch=0;
168            if(other.fMatch)
169            {
170                fMatch=new (other.fMemoryManager) Match(*other.fMatch);
171                fAdoptMatch=true;
172            }
173        }
174
175        if (fOffsets && other.fOffsets && fSize==other.fSize)
176        {
177            for (int i = 0; i< fSize; i++)
178                fOffsets[i] = other.fOffsets[i];
179        }
180        else
181        {
182            if(fOffsets)
183                fMemoryManager->deallocate(fOffsets);//delete [] fOffsets;
184            fOffsets=0;
185            fSize=other.fSize;
186            if(other.fOffsets)
187            {
188                fOffsets = (int*) other.fMemoryManager->allocate(fSize* sizeof(int));
189                for (int i = 0; i< fSize; i++)
190                    fOffsets[i] = other.fOffsets[i];
191            }
192        }
193
194        fMemoryManager=other.fMemoryManager;
195    }
196
197    return *this;
198}
199
200RegularExpression::Context::~Context()
201{
202    if (fOffsets)
203        fMemoryManager->deallocate(fOffsets);//delete [] fOffsets;
204
205    if (fAdoptMatch)
206        delete fMatch;
207}
208
209// ---------------------------------------------------------------------------
210//  RegularExpression::Context: Public methods
211// ---------------------------------------------------------------------------
212void RegularExpression::Context::reset(const XMLCh* const string
213                                       , const XMLSize_t stringLen
214                                       , const XMLSize_t start
215                                       , const XMLSize_t limit
216                                       , const int noClosures
217                                       , const unsigned int options)
218{
219    fString = string;
220    fStringMaxLen = stringLen;
221    fStart = start;
222    fLimit = limit;
223    fLength = fLimit - fStart;
224    if (fAdoptMatch)
225        delete fMatch;
226    fMatch = 0;
227
228    if (fSize != noClosures) {
229        if (fOffsets)
230            fMemoryManager->deallocate(fOffsets);//delete [] fOffsets;
231        fOffsets = (int*) fMemoryManager->allocate(noClosures * sizeof(int));//new int[noClosures];
232    }
233
234    fSize = noClosures;
235    fOptions = options;
236
237    for (int i = 0; i< fSize; i++)
238        fOffsets[i] = -1;
239}
240
241bool RegularExpression::Context::nextCh(XMLInt32& ch, XMLSize_t& offset)
242{
243    ch = fString[offset];
244
245    if (RegxUtil::isHighSurrogate(ch)) {
246        if ((offset + 1 < fLimit) && RegxUtil::isLowSurrogate(fString[offset+1])) {
247            ch = RegxUtil::composeFromSurrogate(ch, fString[++offset]);
248        }
249        else return false;
250    }
251    else if (RegxUtil::isLowSurrogate(ch)) {
252        return false;
253    }
254
255    return true;
256}
257
258// ---------------------------------------------------------------------------
259//  RegularExpression: Constructors and Destructors
260// ---------------------------------------------------------------------------
261
262typedef JanitorMemFunCall<RegularExpression>    CleanupType;
263
264RegularExpression::RegularExpression(const char* const pattern,
265                                     MemoryManager* const manager)
266    :fHasBackReferences(false),
267     fFixedStringOnly(false),
268     fNoGroups(0),
269     fMinLength(0),
270     fNoClosures(0),
271     fOptions(0),
272     fBMPattern(0),
273     fPattern(0),
274     fFixedString(0),
275     fOperations(0),
276     fTokenTree(0),
277     fFirstChar(0),
278     fOpFactory(manager),
279     fTokenFactory(0),
280     fMemoryManager(manager)
281{
282    CleanupType cleanup(this, &RegularExpression::cleanUp);
283
284    try {
285
286        XMLCh* tmpBuf = XMLString::transcode(pattern, fMemoryManager);
287        ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
288        setPattern(tmpBuf);
289    }
290    catch(const OutOfMemoryException&)
291    {
292        cleanup.release();
293
294        throw;
295    }
296
297    cleanup.release();
298}
299
300RegularExpression::RegularExpression(const char* const pattern,
301                                     const char* const options,
302                                     MemoryManager* const manager)
303    :fHasBackReferences(false),
304     fFixedStringOnly(false),
305     fNoGroups(0),
306     fMinLength(0),
307     fNoClosures(0),
308     fOptions(0),
309     fBMPattern(0),
310     fPattern(0),
311     fFixedString(0),
312     fOperations(0),
313     fTokenTree(0),
314     fFirstChar(0),
315     fOpFactory(manager),
316     fTokenFactory(0),
317     fMemoryManager(manager)
318{
319    CleanupType cleanup(this, &RegularExpression::cleanUp);
320
321    try {
322
323        XMLCh* tmpBuf = XMLString::transcode(pattern, fMemoryManager);
324        ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
325        XMLCh* tmpOptions = XMLString::transcode(options, fMemoryManager);
326        ArrayJanitor<XMLCh> janOps(tmpOptions, fMemoryManager);
327        setPattern(tmpBuf, tmpOptions);
328    }
329    catch(const OutOfMemoryException&)
330    {
331        cleanup.release();
332
333        throw;
334    }
335
336    cleanup.release();
337}
338
339
340RegularExpression::RegularExpression(const XMLCh* const pattern,
341                                     MemoryManager* const manager)
342    :fHasBackReferences(false),
343     fFixedStringOnly(false),
344     fNoGroups(0),
345     fMinLength(0),
346     fNoClosures(0),
347     fOptions(0),
348     fBMPattern(0),
349     fPattern(0),
350     fFixedString(0),
351     fOperations(0),
352     fTokenTree(0),
353     fFirstChar(0),
354     fOpFactory(manager),
355     fTokenFactory(0),
356     fMemoryManager(manager)
357{
358    CleanupType cleanup(this, &RegularExpression::cleanUp);
359
360    try {
361
362        setPattern(pattern);
363    }
364    catch(const OutOfMemoryException&)
365    {
366        cleanup.release();
367
368        throw;
369    }
370
371    cleanup.release();
372}
373
374RegularExpression::RegularExpression(const XMLCh* const pattern,
375                                     const XMLCh* const options,
376                                     MemoryManager* const manager)
377    :fHasBackReferences(false),
378     fFixedStringOnly(false),
379     fNoGroups(0),
380     fMinLength(0),
381     fNoClosures(0),
382     fOptions(0),
383     fBMPattern(0),
384     fPattern(0),
385     fFixedString(0),
386     fOperations(0),
387     fTokenTree(0),
388     fFirstChar(0),
389     fOpFactory(manager),
390     fTokenFactory(0),
391     fMemoryManager(manager)
392{
393    CleanupType cleanup(this, &RegularExpression::cleanUp);
394
395    try {
396
397        setPattern(pattern, options);
398    }
399    catch(const OutOfMemoryException&)
400    {
401        cleanup.release();
402
403        throw;
404    }
405
406    cleanup.release();
407}
408
409RegularExpression::~RegularExpression() {
410
411    cleanUp();
412}
413
414// ---------------------------------------------------------------------------
415//  RegularExpression: Setter methods
416// ---------------------------------------------------------------------------
417
418RegxParser* RegularExpression::getRegexParser(const int options, MemoryManager* const manager)
419{
420    // the following construct causes an error in an Intel 7.1 32 bit compiler for
421    // red hat linux 7.2
422    // (when an exception is thrown the wrong object is deleted)
423    //RegxParser* regxParser = isSet(fOptions, XMLSCHEMA_MODE)
424    //    ? new (fMemoryManager) ParserForXMLSchema(fMemoryManager)
425    //    : new (fMemoryManager) RegxParser(fMemoryManager);
426    if (isSet(options, XMLSCHEMA_MODE))
427        return new (manager) ParserForXMLSchema(manager);
428
429    return new (manager) RegxParser(manager);
430}
431
432void RegularExpression::setPattern(const XMLCh* const pattern,
433                                   const XMLCh* const options)
434{
435
436    fTokenFactory = new (fMemoryManager) TokenFactory(fMemoryManager);
437    fOptions = parseOptions(options);
438    fPattern = XMLString::replicate(pattern, fMemoryManager);
439
440    RegxParser* regxParser=getRegexParser(fOptions, fMemoryManager);
441
442    if (regxParser)
443        regxParser->setTokenFactory(fTokenFactory);
444
445    Janitor<RegxParser> janRegxParser(regxParser);
446    fTokenTree = regxParser->parse(fPattern, fOptions);
447    fNoGroups = regxParser->getNoParen();
448    fHasBackReferences = regxParser->hasBackReferences();
449
450    prepare();
451}
452
453// ---------------------------------------------------------------------------
454//  RegularExpression: Matching methods
455// ---------------------------------------------------------------------------
456bool RegularExpression::matches(const char* const expression
457                                , MemoryManager* const manager) const
458{
459    XMLCh* tmpBuf = XMLString::transcode(expression, manager);
460    ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
461    return matches(tmpBuf, 0, XMLString::stringLen(tmpBuf), 0, manager);
462}
463
464bool RegularExpression::matches(const char* const expression
465                                , const XMLSize_t start, const XMLSize_t end
466                                , MemoryManager* const manager) const
467{
468
469    XMLCh* tmpBuf = XMLString::transcode(expression, manager);
470    ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
471    return matches(tmpBuf, start, end, 0, manager);
472}
473
474bool RegularExpression::matches(const char* const expression
475                                , Match* const match
476                                , MemoryManager* const manager) const
477{
478
479    XMLCh* tmpBuf = XMLString::transcode(expression, manager);
480    ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
481    return matches(tmpBuf, 0, XMLString::stringLen(tmpBuf), match, manager);
482}
483
484bool RegularExpression::matches(const char* const expression, const XMLSize_t start
485                                , const XMLSize_t end, Match* const pMatch
486                                , MemoryManager* const manager) const
487{
488
489    XMLCh* tmpBuf = XMLString::transcode(expression, manager);
490    ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
491    return matches(tmpBuf, start, end, pMatch, manager);
492}
493
494
495// ---------------------------------------------------------------------------
496//  RegularExpression: Matching methods - Wide char version
497// ---------------------------------------------------------------------------
498bool RegularExpression::matches(const XMLCh* const expression, MemoryManager* const manager) const
499{
500    return matches(expression, 0, XMLString::stringLen(expression), 0, manager);
501}
502
503bool RegularExpression::matches(const XMLCh* const expression
504                                , const XMLSize_t start, const XMLSize_t end
505                                , MemoryManager* const manager) const
506{
507    return matches(expression, start, end, 0, manager);
508}
509
510bool RegularExpression::matches(const XMLCh* const expression
511                                , Match* const match
512                                , MemoryManager* const manager) const
513{
514    return matches(expression, 0, XMLString::stringLen(expression), match, manager);
515}
516
517bool RegularExpression::matches(const XMLCh* const expression, const XMLSize_t start
518                                , const XMLSize_t end, Match* const pMatch
519                                , MemoryManager* const manager) const
520{
521
522    Context context(manager);
523    XMLSize_t strLength = XMLString::stringLen(expression);
524
525    context.reset(expression, strLength, start, end, fNoClosures, fOptions);
526
527    bool adoptMatch = false;
528    Match* lMatch = pMatch;
529
530    if (lMatch != 0) {
531        lMatch->setNoGroups(fNoGroups);
532    }
533    else if (fHasBackReferences) {
534        lMatch = new (manager) Match(manager);
535        lMatch->setNoGroups(fNoGroups);
536        adoptMatch = true;
537    }
538
539    if (context.fAdoptMatch)
540        delete context.fMatch;
541    context.fMatch = lMatch;
542    context.fAdoptMatch = adoptMatch;
543
544    if (isSet(fOptions, XMLSCHEMA_MODE)) {
545
546        int matchEnd = match(&context, fOperations, context.fStart);
547
548        if (matchEnd == (int)context.fLimit) {
549
550            if (context.fMatch != 0) {
551
552                context.fMatch->setStartPos(0, (int)context.fStart);
553                context.fMatch->setEndPos(0, matchEnd);
554            }
555            return true;
556        }
557
558        return false;
559    }
560
561    /*
562     * If the pattern has only fixed string, use Boyer-Moore
563     */
564    if (fFixedStringOnly) {
565
566        int ret = fBMPattern->matches(expression, context.fStart, context.fLimit);
567        if (ret >= 0) {
568
569            if (context.fMatch != 0) {
570                context.fMatch->setStartPos(0, ret);
571                context.fMatch->setEndPos(0, (int)(ret + XMLString::stringLen(fPattern)));
572            }
573            return true;
574        }
575        return false;
576    }
577
578    /*
579     * If the pattern contains a fixed string, we check with Boyer-Moore
580     * whether the text contains the fixed string or not. If not found
581     * return false
582     */
583    if (fFixedString != 0) {
584
585        int ret = fBMPattern->matches(expression, context.fStart, context.fLimit);
586
587        if (ret < 0) { // No match
588            return false;
589        }
590    }
591
592    // if the length is less than the minimum length, we cannot possibly match
593    if(context.fLimit<fMinLength)
594        return false;
595
596    XMLSize_t limit = context.fLimit - fMinLength;
597    XMLSize_t matchStart;
598    int matchEnd = -1;
599
600    /*
601     * Check whether the expression start with ".*"
602     */
603    if (fOperations != 0 && (fOperations->getOpType() == Op::O_CLOSURE || fOperations->getOpType() == Op::O_FINITE_CLOSURE)
604        && fOperations->getChild()->getOpType() == Op::O_DOT) {
605
606        if (isSet(fOptions, SINGLE_LINE)) {
607            matchStart = context.fStart;
608            matchEnd = match(&context, fOperations, matchStart);
609        }
610        else {
611            bool previousIsEOL = true;
612
613            for (matchStart=context.fStart; matchStart<=limit; matchStart++) {
614
615                XMLCh ch = expression[matchStart];
616                if (RegxUtil::isEOLChar(ch)) {
617                    previousIsEOL = true;
618                }
619                else {
620
621                    if (previousIsEOL) {
622                        if (0 <= (matchEnd = match(&context, fOperations,
623                                                   matchStart)))
624                            break;
625                    }
626
627                    previousIsEOL = false;
628                }
629            }
630        }
631    }
632    else {
633        /*
634         *    Optimization against the first char
635         */
636        if (fFirstChar != 0) {
637            bool ignoreCase = isSet(fOptions, IGNORE_CASE);
638            RangeToken* range = fFirstChar;
639
640            if (ignoreCase)
641                range = fFirstChar->getCaseInsensitiveToken(fTokenFactory);
642
643            for (matchStart=context.fStart; matchStart<=limit; matchStart++) {
644
645                XMLInt32 ch;
646
647                if (!context.nextCh(ch, matchStart))
648                    break;
649
650                if (!range->match(ch))
651                    continue;
652
653                if (0 <= (matchEnd = match(&context,fOperations,matchStart)))
654                    break;
655            }
656        }
657        else {
658
659            /*
660             *    Straightforward matching
661             */
662            for (matchStart=context.fStart; matchStart<=limit; matchStart++) {
663
664                if (0 <= (matchEnd = match(&context,fOperations,matchStart)))
665                    break;
666            }
667        }
668    }
669
670    if (matchEnd >= 0) {
671
672        if (context.fMatch != 0) {
673
674            context.fMatch->setStartPos(0, (int)matchStart);
675            context.fMatch->setEndPos(0, matchEnd);
676        }
677        return true;
678    }
679    return false;
680}
681
682// ---------------------------------------------------------------------------
683//  RegularExpression: Tokenize methods
684// ---------------------------------------------------------------------------
685RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const char* const expression,
686                                                     MemoryManager* const manager) const
687{
688
689  XMLCh* tmpBuf = XMLString::transcode(expression, manager);
690  ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
691  return tokenize(tmpBuf, 0, XMLString::stringLen(tmpBuf), manager);
692}
693
694RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const char* const expression,
695                                                     const XMLSize_t start, const XMLSize_t end,
696                                                     MemoryManager* const manager) const
697{
698
699  XMLCh* tmpBuf = XMLString::transcode(expression, manager);
700  ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
701  return tokenize(tmpBuf, start, end, manager);
702}
703
704
705
706// ---------------------------------------------------------------------------
707//  RegularExpression: Tokenize methods - Wide char version
708// ---------------------------------------------------------------------------
709RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const XMLCh* const expression,
710                                                     MemoryManager* const manager) const
711{
712    return tokenize(expression, 0, XMLString::stringLen(expression), manager);
713}
714
715RefArrayVectorOf<XMLCh>* RegularExpression::tokenize(const XMLCh* const matchString,
716                                                     const XMLSize_t start, const XMLSize_t end,
717                                                     MemoryManager* const manager) const
718{
719    // check if matches zero length string - throw error if so
720    if(matches(XMLUni::fgZeroLenString, manager)){
721        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Regex_RepPatMatchesZeroString, manager);
722    }
723
724    RefVectorOf<Match> *subEx = new (manager) RefVectorOf<Match>(10, true, manager);
725    Janitor<RefVectorOf<Match> > janSubEx(subEx);
726
727    allMatches(matchString, start, end, subEx, manager);
728
729    RefArrayVectorOf<XMLCh> *tokens = new (manager) RefArrayVectorOf<XMLCh>(16, true, manager);
730    XMLSize_t tokStart = start;
731
732    XMLSize_t i = 0;
733    for(; i < subEx->size(); ++i) {
734        Match *match = subEx->elementAt(i);
735        XMLSize_t matchStart = match->getStartPos(0);
736
737        XMLCh *token = (XMLCh*)manager->allocate((matchStart + 1 - tokStart) * sizeof(XMLCh));
738        XMLString::subString(token, matchString, tokStart, matchStart, manager);
739        tokens->addElement(token);
740
741        tokStart = match->getEndPos(0);
742    }
743
744    XMLCh *token = (XMLCh*)manager->allocate((end + 1 - tokStart) * sizeof(XMLCh));
745    XMLString::subString(token, matchString, tokStart, end, manager);
746    tokens->addElement(token);
747
748    return tokens;
749}
750
751void RegularExpression::allMatches(const XMLCh* const matchString, const XMLSize_t start, const XMLSize_t end,
752                                   RefVectorOf<Match> *subEx, MemoryManager* const manager) const
753{
754    Context context(manager);
755    context.reset(matchString, XMLString::stringLen(matchString), start, end, fNoClosures, fOptions);
756
757    context.fMatch = new (manager) Match(manager);
758    context.fMatch->setNoGroups(fNoGroups);
759    context.fAdoptMatch = true;
760
761    XMLSize_t matchStart = start;
762    while(matchStart <= end) {
763        XMLSize_t matchEnd = match(&context, fOperations, matchStart);
764        if(matchEnd != (XMLSize_t)-1) {
765            context.fMatch->setStartPos(0, (int)matchStart);
766            context.fMatch->setEndPos(0, (int)matchEnd);
767
768            subEx->addElement(context.fMatch);
769
770            context.fMatch = new (manager) Match(*(context.fMatch));
771            context.fAdoptMatch = true;
772
773            matchStart = matchEnd;
774        } else {
775            ++matchStart;
776        }
777    }
778}
779
780
781// -----------------------------------------------------------------------
782//  RegularExpression: Replace methods
783// -----------------------------------------------------------------------
784XMLCh* RegularExpression::replace(const char* const matchString,
785                                  const char* const replaceString,
786                                  MemoryManager* const manager) const
787{
788
789    XMLCh* tmpBuf = XMLString::transcode(matchString, manager);
790    ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
791    XMLCh* tmpBuf2 = XMLString::transcode(replaceString, manager);
792    ArrayJanitor<XMLCh> janBuf2(tmpBuf2, manager);
793
794    return replace(tmpBuf, tmpBuf2, 0, XMLString::stringLen(tmpBuf), manager);
795}
796
797XMLCh* RegularExpression::replace(const char* const matchString,
798                                  const char* const replaceString,
799                                  const XMLSize_t start, const XMLSize_t end,
800                                  MemoryManager* const manager) const
801{
802
803    XMLCh* tmpBuf = XMLString::transcode(matchString, manager);
804    ArrayJanitor<XMLCh> janBuf(tmpBuf, manager);
805    XMLCh* tmpBuf2 = XMLString::transcode(replaceString, manager);
806    ArrayJanitor<XMLCh> janBuf2(tmpBuf2, manager);
807
808    return replace(tmpBuf, tmpBuf2, start, end, manager);
809}
810
811
812// ---------------------------------------------------------------------------
813//  RegularExpression: Replace methods - Wide char version
814// ---------------------------------------------------------------------------
815XMLCh* RegularExpression::replace(const XMLCh* const matchString,
816                                  const XMLCh* const replaceString,
817                                  MemoryManager* const manager) const
818{
819
820    return replace(matchString, replaceString, 0,
821                   XMLString::stringLen(matchString), manager);
822}
823
824XMLCh* RegularExpression::replace(const XMLCh* const matchString,
825                                  const XMLCh* const replaceString,
826                                  const XMLSize_t start, const XMLSize_t end,
827                                  MemoryManager* const manager) const
828{
829    // check if matches zero length string - throw error if so
830    if(matches(XMLUni::fgZeroLenString, manager)){
831        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Regex_RepPatMatchesZeroString, manager);
832    }
833
834    RefVectorOf<Match> *subEx = new (manager) RefVectorOf<Match>(10, true, manager);
835    Janitor<RefVectorOf<Match> > janSubEx(subEx);
836
837    allMatches(matchString, start, end, subEx, manager);
838
839    XMLBuffer result(1023, manager);
840    int tokStart = (int)start;
841
842    XMLSize_t i = 0;
843    for(; i < subEx->size(); ++i) {
844        Match *match = subEx->elementAt(i);
845        int matchStart = match->getStartPos(0);
846
847        if(matchStart > tokStart)
848            result.append(matchString + tokStart, matchStart - tokStart);
849        subInExp(replaceString, matchString, match, result, manager);
850
851        tokStart = match->getEndPos(0);
852    }
853
854    if(end > (XMLSize_t)tokStart)
855        result.append(matchString + tokStart, end - tokStart);
856
857    return XMLString::replicate(result.getRawBuffer(), manager);
858}
859
860/*
861 * Helper for Replace. This method prepares the replacement string by substituting
862 * in actual values for parenthesized sub expressions.
863 *
864 * An error will be thrown if:
865 *  1) there is chBackSlash not followed by a chDollarSign or chBackSlash
866 *  2) there is an unescaped chDollarSign which is not followed by a digit
867 *
868 */
869void RegularExpression::subInExp(const XMLCh* const repString,
870                                 const XMLCh* const origString,
871                                 const Match* subEx,
872                                 XMLBuffer &result,
873                                 MemoryManager* const manager) const
874{
875    int numSubExp = subEx->getNoGroups() - 1;
876
877    for(const XMLCh *ptr = repString; *ptr != chNull; ++ptr) {
878        if(*ptr == chDollarSign) {
879            ++ptr;
880
881            // check that after the $ is a digit
882            if(!XMLString::isDigit(*ptr)) {
883                // invalid replace string - $ must be followed by a digit
884                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Regex_InvalidRepPattern, manager);
885            }
886
887            int index = *ptr - chDigit_0;
888
889            const XMLCh *dig = ptr + 1;
890            while(XMLString::isDigit(*dig)) {
891                int newIndex = index * 10 + (*dig - chDigit_0);
892                if(newIndex > numSubExp) break;
893
894                index = newIndex;
895                ptr = dig;
896                ++dig;
897            }
898
899            // now check that the index is legal
900            if(index <= numSubExp) {
901                int start = subEx->getStartPos(index);
902                int end = subEx->getEndPos(index);
903
904                // now copy the substring into the new string
905                if(start < end) {
906                    result.append(origString + start, end - start);
907                }
908            }
909
910        } else {
911            if(*ptr == chBackSlash) {
912                ++ptr;
913
914                // if you have a slash and then a character that's not a $ or /,
915                // then it's an invalid replace string
916                if(*ptr != chDollarSign && *ptr != chBackSlash) {
917                    ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Regex_InvalidRepPattern, manager);
918                }
919            }
920
921            result.append(*ptr);
922        }
923    }
924}
925
926
927// -----------------------------------------------------------------------
928//  Static initialize and cleanup methods
929// -----------------------------------------------------------------------
930void
931XMLInitializer::initializeRegularExpression()
932{
933    RegularExpression::staticInitialize(XMLPlatformUtils::fgMemoryManager);
934}
935
936void
937XMLInitializer::terminateRegularExpression()
938{
939    RegularExpression::staticCleanup();
940}
941
942void
943RegularExpression::staticInitialize(MemoryManager* memoryManager)
944{
945    fWordRange = TokenFactory::staticGetRange(fgUniIsWord, false);
946
947    if (fWordRange == 0)
948        ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Regex_RangeTokenGetError, fgUniIsWord, memoryManager);
949}
950
951// ---------------------------------------------------------------------------
952//  RegularExpression: Helpers methods
953// ---------------------------------------------------------------------------
954int RegularExpression::getOptionValue(const XMLCh ch) {
955
956    int ret = 0;
957
958    switch (ch) {
959
960        case chLatin_i:
961            ret = IGNORE_CASE;
962            break;
963        case chLatin_m:
964            ret = MULTIPLE_LINE;
965            break;
966        case chLatin_s:
967            ret = SINGLE_LINE;
968            break;
969        case chLatin_x:
970            ret = EXTENDED_COMMENT;
971            break;
972        case chLatin_F:
973            ret = PROHIBIT_FIXED_STRING_OPTIMIZATION;
974            break;
975        case chLatin_H:
976            ret = PROHIBIT_HEAD_CHARACTER_OPTIMIZATION;
977            break;
978        case chLatin_X:
979            ret = XMLSCHEMA_MODE;
980            break;
981        default:
982            break;
983    }
984
985    return ret;
986}
987
988struct RE_RuntimeContext {
989    const Op    *op_;
990    XMLSize_t   offs_;
991
992    RE_RuntimeContext(const Op *op, XMLSize_t offs) : op_(op), offs_(offs) { }
993};
994
995int RegularExpression::match(Context* const context, const Op* const operations,
996                             XMLSize_t offset) const
997{
998    ValueStackOf<RE_RuntimeContext>* opStack=NULL;
999    Janitor<ValueStackOf<RE_RuntimeContext> > janStack(NULL);
1000    if(context->fLimit > 256)
1001    {
1002        opStack=new ValueStackOf<RE_RuntimeContext>(16, context->fMemoryManager);
1003        janStack.reset(opStack);
1004    }
1005    const Op* tmpOp = operations;
1006    bool ignoreCase = isSet(context->fOptions, IGNORE_CASE);
1007    int doReturn;
1008
1009    while (tmpOp != 0) {
1010        // no one wants to return -5, only -1, 0, and greater
1011        doReturn = -5;
1012
1013        if (offset > context->fLimit || offset < context->fStart)
1014            doReturn = -1;
1015        else
1016        {
1017            switch(tmpOp->getOpType()) {
1018                case Op::O_CHAR:
1019                    if (!matchChar(context, tmpOp->getData(), offset, ignoreCase))
1020                        doReturn = -1;
1021                    else
1022                        tmpOp = tmpOp->getNextOp();
1023                    break;
1024                case Op::O_DOT:
1025                    if (!matchDot(context, offset))
1026                        doReturn = -1;
1027                    else
1028                        tmpOp = tmpOp->getNextOp();
1029                    break;
1030                case Op::O_RANGE:
1031                case Op::O_NRANGE:
1032                    if (!matchRange(context, tmpOp, offset, ignoreCase))
1033                        doReturn = -1;
1034                    else
1035                        tmpOp = tmpOp->getNextOp();
1036                    break;
1037                case Op::O_ANCHOR:
1038                    if (!matchAnchor(context, tmpOp->getData(), offset))
1039                        doReturn = -1;
1040                    else
1041                        tmpOp = tmpOp->getNextOp();
1042                    break;
1043                case Op::O_BACKREFERENCE:
1044                    if (!matchBackReference(context, tmpOp->getData(), offset,
1045                                            ignoreCase))
1046                        doReturn = -1;
1047                    else
1048                        tmpOp = tmpOp->getNextOp();
1049                    break;
1050                case Op::O_STRING:
1051                    if (!matchString(context, tmpOp->getLiteral(), offset, ignoreCase))
1052                        doReturn = -1;
1053                    else
1054                        tmpOp = tmpOp->getNextOp();
1055                    break;
1056                case Op::O_FINITE_CLOSURE:
1057                {
1058                    XMLInt32 id = tmpOp->getData();
1059                    // if id is not -1, it's a closure with a child token having a minumum length,
1060                    // where id is the index of the fOffsets array where its status is stored
1061                    if (id >= 0) {
1062                        int prevOffset = context->fOffsets[id];
1063                        if (prevOffset < 0 || prevOffset != (int)offset) {
1064                            context->fOffsets[id] = (int)offset;
1065                        }
1066                        else {
1067                            // the status didn't change, we haven't found other copies; move on to the next match
1068                            context->fOffsets[id] = -1;
1069                            tmpOp = tmpOp->getNextOp();
1070                            break;
1071                        }
1072                    }
1073
1074                    // match the subitems until they do
1075                    int ret;
1076                    while((ret = match(context, tmpOp->getChild(), offset)) != -1)
1077                    {
1078                        if(offset == (XMLSize_t)ret)
1079                            break;
1080                        offset = ret;
1081                    }
1082
1083                    if (id >= 0) {
1084                        // loop has ended, reset the status for this closure
1085                        context->fOffsets[id] = -1;
1086                    }
1087                    tmpOp = tmpOp->getNextOp();
1088                }
1089                break;
1090                case Op::O_FINITE_NONGREEDYCLOSURE:
1091                {
1092                    int ret = match(context,tmpOp->getNextOp(),offset);
1093                    if (ret >= 0)
1094                        doReturn = ret;
1095                    else
1096                    {
1097                        // match the subitems until they do
1098                        int ret;
1099                        while((ret = match(context, tmpOp->getChild(), offset)) != -1)
1100                        {
1101                            if(offset == (XMLSize_t)ret)
1102                                break;
1103                            offset = ret;
1104                        }
1105                        tmpOp = tmpOp->getNextOp();
1106                    }
1107                }
1108                break;
1109                case Op::O_CLOSURE:
1110                {
1111                    XMLInt32 id = tmpOp->getData();
1112                    // if id is not -1, it's a closure with a child token having a minumum length,
1113                    // where id is the index of the fOffsets array where its status is stored
1114                    if (id >= 0) {
1115                        int prevOffset = context->fOffsets[id];
1116                        if (prevOffset < 0 || prevOffset != (int)offset) {
1117                            context->fOffsets[id] = (int)offset;
1118                        }
1119                        else {
1120                            // the status didn't change, we haven't found other copies; move on to the next match
1121                            context->fOffsets[id] = -1;
1122                            tmpOp = tmpOp->getNextOp();
1123                            break;
1124                        }
1125                    }
1126
1127                    if(opStack!=NULL)
1128                    {
1129                        opStack->push(RE_RuntimeContext(tmpOp, offset));
1130                        tmpOp = tmpOp->getChild();
1131                    }
1132                    else
1133                    {
1134                        int ret = match(context, tmpOp->getChild(), offset);
1135                        if (id >= 0) {
1136                            context->fOffsets[id] = -1;
1137                        }
1138                        if (ret >= 0)
1139                            doReturn = ret;
1140                        else
1141                            tmpOp = tmpOp->getNextOp();
1142                    }
1143                }
1144                break;
1145                case Op::O_QUESTION:
1146                {
1147                    if(opStack!=NULL)
1148                    {
1149                        opStack->push(RE_RuntimeContext(tmpOp, offset));
1150                        tmpOp = tmpOp->getChild();
1151                    }
1152                    else
1153                    {
1154                        int ret = match(context, tmpOp->getChild(), offset);
1155                        if (ret >= 0)
1156                            doReturn = ret;
1157                        else
1158                            tmpOp = tmpOp->getNextOp();
1159                    }
1160                }
1161                break;
1162                case Op::O_NONGREEDYCLOSURE:
1163                case Op::O_NONGREEDYQUESTION:
1164                {
1165                    int ret = match(context,tmpOp->getNextOp(),offset);
1166                    if (ret >= 0)
1167                        doReturn = ret;
1168                    else
1169                        tmpOp = tmpOp->getChild();
1170                }
1171                break;
1172                case Op::O_UNION:
1173                    doReturn = matchUnion(context, tmpOp, offset);
1174                    break;
1175                case Op::O_CAPTURE:
1176                    if (context->fMatch != 0 && tmpOp->getData() != 0)
1177                        doReturn = matchCapture(context, tmpOp, offset);
1178                    else
1179                        tmpOp = tmpOp->getNextOp();
1180                    break;
1181            }
1182        }
1183        if (doReturn != -5) {
1184            if (opStack==NULL || opStack->size() == 0)
1185                return doReturn;
1186            RE_RuntimeContext ctx = opStack->pop();
1187            tmpOp = ctx.op_;
1188            offset = ctx.offs_;
1189            if (tmpOp->getOpType() == Op::O_CLOSURE) {
1190                XMLInt32 id = tmpOp->getData();
1191                if (id >= 0) {
1192                    // loop has ended, reset the status for this closure
1193                    context->fOffsets[id] = -1;
1194                }
1195            }
1196            if (tmpOp->getOpType() == Op::O_CLOSURE || tmpOp->getOpType() == Op::O_QUESTION) {
1197                if (doReturn >= 0)
1198                    return doReturn;
1199            }
1200            tmpOp = tmpOp->getNextOp();
1201        }
1202    }
1203
1204    return (int)offset;
1205}
1206
1207bool RegularExpression::matchChar(Context* const context,
1208                                  const XMLInt32 ch, XMLSize_t& offset,
1209                                  const bool ignoreCase) const
1210{
1211    if (offset >= context->fLimit)
1212        return false;
1213
1214    XMLInt32 strCh = 0;
1215
1216    if (!context->nextCh(strCh, offset))
1217        return false;
1218
1219    bool match = ignoreCase ? matchIgnoreCase(ch, strCh)
1220                            : (ch == strCh);
1221    if (!match)
1222        return false;
1223
1224    ++offset;
1225
1226    return true;
1227}
1228
1229bool RegularExpression::matchDot(Context* const context, XMLSize_t& offset) const
1230{
1231    if (offset >= context->fLimit)
1232        return false;
1233
1234    XMLInt32 strCh = 0;
1235
1236    if (!context->nextCh(strCh, offset))
1237        return false;
1238
1239    if (!isSet(context->fOptions, SINGLE_LINE)) {
1240
1241        if (RegxUtil::isEOLChar(strCh))
1242            return false;
1243    }
1244
1245    ++offset;
1246    return true;
1247}
1248
1249bool RegularExpression::matchRange(Context* const context, const Op* const op,
1250                                   XMLSize_t& offset, const bool ignoreCase) const
1251{
1252    if (offset >= context->fLimit)
1253        return false;
1254
1255    XMLInt32 strCh = 0;
1256
1257    if (!context->nextCh(strCh, offset))
1258        return false;
1259
1260    RangeToken* tok = (RangeToken *) op->getToken();
1261    bool match = false;
1262
1263    if (ignoreCase) {
1264        tok = tok->getCaseInsensitiveToken(fTokenFactory);
1265    }
1266
1267    match = tok->match(strCh);
1268
1269    if (!match)
1270        return false;
1271
1272    ++offset;
1273    return true;
1274}
1275
1276bool RegularExpression::matchAnchor(Context* const context, const XMLInt32 ch,
1277                                    const XMLSize_t offset) const
1278{
1279    switch ((XMLCh) ch) {
1280    case chDollarSign:
1281        if (isSet(context->fOptions, MULTIPLE_LINE)) {
1282            if (!(offset == context->fLimit || (offset < context->fLimit
1283                && RegxUtil::isEOLChar(context->fString[offset]))))
1284                return false;
1285        }
1286        else {
1287
1288            if (!(offset == context->fLimit
1289                || (offset+1 == context->fLimit
1290                    && RegxUtil::isEOLChar(context->fString[offset]))
1291                || (offset+2 == context->fLimit
1292                    && context->fString[offset] == chCR
1293                    && context->fString[offset+1] == chLF)))
1294                return false;
1295        }
1296        break;
1297    case chCaret:
1298        if (!isSet(context->fOptions, MULTIPLE_LINE)) {
1299
1300            if (offset != context->fStart)
1301                return false;
1302        }
1303        else {
1304
1305            if (!(offset == context->fStart || (offset > context->fStart
1306                && RegxUtil::isEOLChar(context->fString[offset-1]))))
1307                return false;
1308        }
1309        break;
1310    }
1311
1312    return true;
1313}
1314
1315bool RegularExpression::matchBackReference(Context* const context,
1316                                           const XMLInt32 refNo, XMLSize_t& offset,
1317                                           const bool ignoreCase) const
1318{
1319    if (refNo <=0 || refNo >= fNoGroups)
1320        ThrowXMLwithMemMgr(IllegalArgumentException, XMLExcepts::Regex_BadRefNo, context->fMemoryManager);
1321
1322    // If the group we're matching against wasn't matched,
1323    // the back reference matches the empty string
1324    if (context->fMatch->getStartPos(refNo) < 0 || context->fMatch->getEndPos(refNo) < 0)
1325        return true;
1326
1327    int start = context->fMatch->getStartPos(refNo);
1328    int length = context->fMatch->getEndPos(refNo) - start;
1329
1330    if (int(context->fLimit - offset) < length)
1331        return false;
1332
1333    bool match = ignoreCase ? XMLString::regionIMatches(context->fString,(int)offset,
1334                                                        context->fString,start,length)
1335                            : XMLString::regionMatches(context->fString, (int)offset,
1336                                                       context->fString, start,length);
1337
1338    if (match) offset += length;
1339    return match;
1340}
1341
1342bool RegularExpression::matchString(Context* const context,
1343                                    const XMLCh* const literal, XMLSize_t& offset,
1344                                    const bool ignoreCase) const
1345{
1346    XMLSize_t length = XMLString::stringLen(literal);
1347
1348    if (context->fLimit - offset < length)
1349        return false;
1350
1351    bool match = ignoreCase ? XMLString::regionIMatches(context->fString, (int)offset,
1352                                                        literal, 0, length)
1353                            : XMLString::regionMatches(context->fString, (int)offset,
1354                                                       literal, 0, length);
1355    if (match) offset += length;
1356    return match;
1357}
1358
1359int RegularExpression::matchCapture(Context* const context, const Op* const op,
1360                                    XMLSize_t offset) const
1361{
1362    // No check is made for nullness of fMatch as the function is only called if
1363    // fMatch is not null.
1364    XMLInt32 index = op->getData();
1365    int save = (index > 0) ? context->fMatch->getStartPos(index)
1366                           : context->fMatch->getEndPos(-index);
1367
1368    if (index > 0) {
1369        context->fMatch->setStartPos(index, (int)offset);
1370        int ret = match(context, op->getNextOp(), offset);
1371        if (ret < 0)
1372            context->fMatch->setStartPos(index, save);
1373        return ret;
1374    }
1375
1376    context->fMatch->setEndPos(-index, (int)offset);
1377    int ret = match(context, op->getNextOp(), offset);
1378    if (ret < 0)
1379        context->fMatch->setEndPos(-index, save);
1380    return ret;
1381}
1382
1383int RegularExpression::matchUnion(Context* const context,
1384                                   const Op* const op, XMLSize_t offset) const
1385{
1386    XMLSize_t opSize = op->getSize();
1387
1388    Context bestResultContext;
1389    int bestResult=-1;
1390    for(XMLSize_t i=0; i < opSize; i++) {
1391        Context tmpContext(context);
1392        int ret = match(&tmpContext, op->elementAt(i), offset);
1393        if (ret >= 0 && (XMLSize_t)ret <= context->fLimit && ret>bestResult)
1394        {
1395            bestResult=ret;
1396            bestResultContext=tmpContext;
1397            // exit early, if we reached the end of the string
1398            if((XMLSize_t)ret == context->fLimit)
1399                break;
1400        }
1401    }
1402    if(bestResult!=-1)
1403        *context=bestResultContext;
1404    return bestResult;
1405}
1406
1407
1408int RegularExpression::parseOptions(const XMLCh* const options)
1409{
1410
1411    if (options == 0)
1412        return 0;
1413
1414    int opts = 0;
1415    XMLSize_t length = XMLString::stringLen(options);
1416
1417    for (XMLSize_t i=0; i < length; i++) {
1418
1419        int v = getOptionValue(options[i]);
1420
1421        if (v == 0)
1422            ThrowXMLwithMemMgr1(ParseException, XMLExcepts::Regex_UnknownOption, options, fMemoryManager);
1423
1424        opts |= v;
1425    }
1426
1427    return opts;
1428}
1429
1430void RegularExpression::compile(const Token* const token) {
1431
1432    if (fOperations != 0)
1433        return;
1434
1435    fNoClosures = 0;
1436    fOperations = compile(token, 0, false);
1437}
1438
1439Op* RegularExpression::compile(const Token* const token, Op* const next,
1440                               const bool reverse)
1441{
1442
1443    Op* ret = 0;
1444
1445    const Token::tokType tokenType = token->getTokenType();
1446
1447    switch(tokenType) {
1448    case Token::T_DOT:
1449        ret = fOpFactory.createDotOp();
1450        ret->setNextOp(next);
1451        break;
1452    case Token::T_CHAR:
1453        ret = fOpFactory.createCharOp(token->getChar());
1454        ret->setNextOp(next);
1455        break;
1456    case Token::T_ANCHOR:
1457        ret = fOpFactory.createAnchorOp(token->getChar());
1458        ret->setNextOp(next);
1459        break;
1460    case Token::T_RANGE:
1461    case Token::T_NRANGE:
1462        ret = fOpFactory.createRangeOp(token);
1463        ret->setNextOp(next);
1464        break;
1465    case Token::T_STRING:
1466        ret = fOpFactory.createStringOp(token->getString());
1467        ret->setNextOp(next);
1468        break;
1469    case Token::T_BACKREFERENCE:
1470        ret = fOpFactory.createBackReferenceOp(token->getReferenceNo());
1471        ret->setNextOp(next);
1472        break;
1473    case Token::T_EMPTY:
1474        ret = next;
1475        break;
1476    case Token::T_CONCAT:
1477        ret = compileConcat(token, next, reverse);
1478        break;
1479    case Token::T_UNION:
1480        ret = compileUnion(token, next, reverse);
1481        break;
1482    case Token::T_CLOSURE:
1483    case Token::T_NONGREEDYCLOSURE:
1484        ret = compileClosure(token, next, reverse, tokenType);
1485        break;
1486    case Token::T_PAREN:
1487        ret = compileParenthesis(token, next, reverse);
1488        break;
1489    default:
1490        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Regex_UnknownTokenType, fMemoryManager);
1491        break; // this line to be deleted
1492    }
1493
1494    return ret;
1495}
1496
1497/*
1498 * Prepares for matching. This method is called during construction.
1499 */
1500void RegularExpression::prepare() {
1501
1502    compile(fTokenTree);
1503
1504    fMinLength = fTokenTree->getMinLength();
1505    fFirstChar = 0;
1506
1507    if (!isSet(fOptions, PROHIBIT_HEAD_CHARACTER_OPTIMIZATION) &&
1508        !isSet(fOptions, XMLSCHEMA_MODE))                            {
1509
1510        RangeToken* rangeTok = fTokenFactory->createRange();
1511        Token::firstCharacterOptions result = fTokenTree->analyzeFirstCharacter(rangeTok, fOptions, fTokenFactory);
1512
1513        if (result == Token::FC_TERMINAL) {
1514
1515            rangeTok->compactRanges();
1516            fFirstChar = rangeTok;
1517        }
1518
1519        rangeTok->createMap();
1520
1521        if (isSet(fOptions, IGNORE_CASE))
1522        {
1523            rangeTok->getCaseInsensitiveToken(fTokenFactory);
1524        }
1525    }
1526
1527    if (fOperations != 0 && fOperations->getNextOp() == 0 &&
1528        (fOperations->getOpType() == Op::O_STRING ||
1529         fOperations->getOpType() == Op::O_CHAR) &&
1530         !isSet(fOptions, IGNORE_CASE) )                      {
1531
1532        fFixedStringOnly = true;
1533
1534        if (fOperations->getOpType() == Op::O_STRING) {
1535            fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
1536            fFixedString = XMLString::replicate(fOperations->getLiteral(), fMemoryManager);
1537        }
1538        else{
1539
1540            XMLInt32 ch = fOperations->getData();
1541
1542            if ( ch >= 0x10000) { // add as constant
1543                fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
1544                fFixedString = RegxUtil::decomposeToSurrogates(ch, fMemoryManager);
1545            }
1546            else {
1547
1548                XMLCh* dummyStr = (XMLCh*) fMemoryManager->allocate(2 * sizeof(XMLCh));//new XMLCh[2];
1549                dummyStr[0] = (XMLCh) fOperations->getData();
1550                dummyStr[1] = chNull;
1551                fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
1552                fFixedString = dummyStr;
1553            }
1554        }
1555
1556        fBMPattern = new (fMemoryManager) BMPattern(fFixedString, 256,
1557                                                    isSet(fOptions, IGNORE_CASE), fMemoryManager);
1558    }
1559    else if (!isSet(fOptions, XMLSCHEMA_MODE) &&
1560             !isSet(fOptions, PROHIBIT_FIXED_STRING_OPTIMIZATION) &&
1561             !isSet(fOptions, IGNORE_CASE)) {
1562
1563        int fixedOpts = 0;
1564        Token* tok = fTokenTree->findFixedString(fOptions, fixedOpts);
1565
1566        fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
1567
1568        fFixedString = (tok == 0) ? 0
1569            : XMLString::replicate(tok->getString(), fMemoryManager);
1570
1571        if (fFixedString != 0 && XMLString::stringLen(fFixedString) < 2) {
1572
1573            fMemoryManager->deallocate(fFixedString);//delete [] fFixedString;
1574            fFixedString = 0;
1575        }
1576
1577        if (fFixedString != 0) {
1578
1579            fBMPattern = new (fMemoryManager) BMPattern(fFixedString, 256,
1580                                                        isSet(fixedOpts, IGNORE_CASE), fMemoryManager);
1581        }
1582    }
1583}
1584
1585bool RegularExpression::doTokenOverlap(const Op* op, Token* token)
1586{
1587    if(op->getOpType()==Op::O_RANGE)
1588    {
1589        RangeToken* t1=(RangeToken*)op->getToken();
1590        switch(token->getTokenType())
1591        {
1592        case Token::T_CHAR:
1593            return t1->match(token->getChar());
1594        case Token::T_STRING:
1595            return t1->match(*token->getString());
1596        case Token::T_RANGE:
1597            {
1598                try
1599                {
1600                    RangeToken tempRange(Token::T_RANGE, fMemoryManager);
1601                    tempRange.mergeRanges(t1);
1602                    tempRange.intersectRanges((RangeToken*)token);
1603                    return !tempRange.empty();
1604                }
1605                catch(RuntimeException&)
1606                {
1607                }
1608                break;
1609            }
1610        default:
1611            break;
1612        }
1613        return true;
1614    }
1615
1616    XMLInt32 ch=0;
1617    if(op->getOpType()==Op::O_CHAR)
1618        ch=op->getData();
1619    else if(op->getOpType()==Op::O_STRING)
1620        ch=*op->getLiteral();
1621
1622    if(ch!=0)
1623    {
1624        switch(token->getTokenType())
1625        {
1626        case Token::T_CHAR:
1627            return token->getChar()==ch;
1628        case Token::T_STRING:
1629            return *token->getString()==ch;
1630        case Token::T_RANGE:
1631        case Token::T_NRANGE:
1632            return ((RangeToken*)token)->match(ch);
1633        default:
1634            break;
1635        }
1636    }
1637    // in any other case, there is the chance that they overlap
1638    return true;
1639}
1640
1641XERCES_CPP_NAMESPACE_END
1642
1643/**
1644  *    End of file RegularExpression.cpp
1645  */
Note: See TracBrowser for help on using the repository browser.