source: icXML/icXML-devel/src/icxmlc/XMLReferenceTable.c @ 2720

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

Initial check-in of icXML 0.8 source files

File size: 21.2 KB
Line 
1/*
2 *  Copyright © 2012 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icXML is a trademark of International Characters.
5 */
6
7/*
8 * @author Nigel Medforth, nigelm -at- interational-characters.com
9 * @version $Id: XMLReferenceTable.c nigelm $
10 *
11 */
12#if !defined(XMLREFERENCETABLE_C)
13// NOTE: it's necessary to guard this ".c" file because it's included at the bottom of the UTF8 and UTF16 CharacterSetAdapters
14// but because this uses the UTF16 CharacterSetAdapter, that means it's possible for this file to be included twice in the UTF8
15// version.
16#define XMLREFERENCETABLE_C
17
18#include <xercesc/util/XMLUTF16Transcoder.hpp>
19#include <xercesc/internal/XMLScanner.hpp>
20#include <icxmlc/XMLReferenceTable.hpp>
21#include <icxmlc/XMLSymbolTable.hpp>
22#include <icxmlc/XMLParserDefs.hpp>
23#include <icxmlc/XMLScanIterator.hpp>
24#include <icxmlc/XMLConfig.hpp>
25#include <cstddef>
26
27XERCES_CPP_NAMESPACE_BEGIN
28
29/// ----------------------------------------------------------------------------------------------------
30
31template<unsigned int CodeUnitSize>
32void XMLReferenceTable::findAndExpandRefs
33(
34        const ubitblock                                 refMarkers
35        , const XMLByte *                               source
36        , const size_t                                  sourceOffset
37        , const ubitblock                               refStart
38        , const size_t                                  refStartOffset
39        , const ubitblock                               delCount
40        , const ubitblock                               attValSpan
41
42        ,               XMLScanner *                    scanner
43        ,               XMLSymbolTable *                symbolTable
44
45        ,               ContentStream &                 contentStream
46        ,       XMLCh * &                               contentStreamPtr
47        ,               StringPtrArray &                stringEndArray
48        , const XMLCh     ** &                  stringEndPtr
49        ,       unsigned int &                  markupCount
50        ,               unsigned int &                  symbolCount
51        ,               XMLComplexRefArray &    complexRefArray
52        ,               XMLSize_t &                             complexRefCount
53)
54{
55        gid_t refArray[BLOCK_SIZE / 3 + 1] = {0};
56        size_t refPosArray[BLOCK_SIZE / 3 + 2] = {0};
57
58        XMLStreamIterator refMarkItr(refMarkers, CONST_LOG_2(CodeUnitSize), sourceOffset);
59        XMLStreamIterator refStartItr(refStart, CONST_LOG_2(1));
60
61        bool resumeRef = 0;
62        size_t startPosition = fStartPosition;
63        size_t endPosition;
64        size_t refPosition = fRefStartPosition;
65
66        XMLSize_t refCount = 0;
67        XMLSize_t sumOfRefLengths = 0;
68        XMLSize_t sumOfStringEndCount = 0;
69        XMLCh * contentStream0 = &contentStream[0];
70
71        switch (fResumeRef)
72        {
73                case 0: while (refMarkItr.next(startPosition))
74                                {
75                                        refStartItr.next(refPosition);
76                                        refPosition = (refPosition - delCount._8[refPosition >> 3]) + refStartOffset;
77
78                case 1:     if (unlikely(!refMarkItr.next(endPosition)))
79                                        {
80                                                fStartPosition = startPosition;
81                                                fRefStartPosition = refPosition;
82                                                resumeRef = 1;
83                                                break;
84                                        }
85
86                                        // note: we cannot be sure that the start character is within this bitblock; but we can be sure
87                                        // that the end position is; ergo we must check whether the end of the ref is within the attValSpan.
88                                        #ifdef __ARCH_64
89                                        uint64_t tempAttVal = attValSpan._64[(endPosition & (BLOCK_SIZE - 1)) >> CONST_LOG_2(64)];
90                                        bool inAttVal = tempAttVal & (static_cast<uint64_t>(1) << (endPosition & 63));
91                                        #else
92                                        uint32_t tempAttVal = attValSpan._32[(endPosition & (BLOCK_SIZE - 1)) >> CONST_LOG_2(32)];
93                                        bool inAttVal = tempAttVal & (static_cast<uint32_t>(1) << (endPosition & 31));
94                                        #endif
95
96                                        startPosition += CodeUnitSize; // skip past the opening & to the first character of the ref and chop off the closing ;
97
98                                        gid_t refId = addOrFind<CodeUnitSize>(&source[startPosition], endPosition - startPosition, inAttVal, scanner, symbolTable);
99
100                                        // scan through and perform any single character replacements; find any non-single
101                                        // character replacements and store their position and any associated information.
102
103                                        const XMLReference & ref = fEntityTable[refId];
104
105                                        if (likely(ref.getType() == XMLReference::Single))
106                                        {
107                                                contentStream0[refPosition] = ref.getContent()[0];
108                                        }
109                                        else
110                                        {
111                                                refArray[refCount] = refId;
112                                                refPosArray[refCount] = refPosition;
113
114                                                if (unlikely(ref.getType() == XMLReference::Complex))
115                                                {
116                                                        markupCount += ref.getMarkupCount();
117                                                        symbolCount += ref.getSymbolCount();
118                                                        // add this ref and the src pos so that we can insert the symbols later ...
119                                                        if (unlikely(complexRefCount == complexRefArray.capacity()))
120                                                        {
121                                                                complexRefArray.expand(complexRefArray.capacity());
122                                                        }
123                                                        XMLComplexRef & ref = complexRefArray[complexRefCount];
124                                                        ref.gid = refId;
125                                                        ref.pos = startPosition;
126                                                        complexRefCount++;
127                                                }
128
129                                                sumOfRefLengths += ref.getContentLength();
130                                                sumOfStringEndCount += ref.getStringEndCount();
131
132                                                refCount++;
133                                        }
134                                }
135        }
136
137        fResumeRef = resumeRef;
138
139        if (unlikely(refCount != 0))
140        {
141                // copy the new content over and insert the refs
142                refPosArray[refCount] = contentStreamPtr - contentStream0 + 1;
143
144                updateContentStream
145                (
146                        refArray
147                        , refPosArray
148                        , refCount
149                        , sumOfRefLengths
150                        , sumOfStringEndCount
151                        , contentStream
152                        , contentStreamPtr
153                        , stringEndArray
154                        , stringEndPtr
155                );
156
157                // update the end pointer of the content stream
158                contentStreamPtr += sumOfRefLengths - refCount;
159                // adjust the last ref start position to account for the new content
160                fRefStartPosition += sumOfRefLengths - refCount;
161        }
162}
163
164/// ----------------------------------------------------------------------------------------------------
165
166void XMLReferenceTable::updateContentStream
167(
168        const gid_t *                                   refArray
169        , const size_t *                                refPosArray
170        , XMLSize_t                                             count
171        , XMLSize_t                                             sumOfRefLengths
172        , XMLSize_t                                             sumOfStringEndCount
173        ,               ContentStream &                 contentStream
174        ,       XMLCh * &                               contentStreamPtr
175        ,               StringPtrArray &                stringEndArray
176        , const XMLCh     ** &                  stringEndPtr
177)
178{
179        // if we had an actual expansion (not just a series of single char replacements) then
180        // scan through the expansions to determine what actions must be taken.
181
182        XMLCh * contentStream0 = &contentStream[0];
183
184        // do we have space for that in the content buffer?
185        if (unlikely(contentStreamPtr + sumOfRefLengths >= contentStream.limit()))
186        {
187                const size_t offset = contentStreamPtr - contentStream0;
188                const size_t reqSize = offset + sumOfRefLengths;
189
190                DEBUG_MESSAGE(" *** EXTENDING CONTENT BUFFER TO STORE EXPANDED REFS! offset=" << offset << " reqSize=" << reqSize << " ***")
191
192                contentStream.resizeToFit(offset, reqSize);
193                stringEndArray.adjust(0, stringEndPtr - &stringEndArray[0], contentStream0 - &contentStream[0]);
194                contentStreamPtr = &contentStream[offset];
195                contentStream0 = &contentStream[0];
196        }
197
198
199        if (likely(sumOfStringEndCount == 0))
200        {
201                // no new string ends are going to be inserted; thus just do a simple adjustment
202                // to the existing string end pointers.
203
204                const XMLCh ** origStringEndPtr = stringEndPtr - 1;
205
206                do
207                {
208                        const size_t refAdj = sumOfRefLengths - count;
209
210                        --count;
211
212                        const size_t size = refPosArray[count + 1] - refPosArray[count] - 1;
213
214                        const XMLReference & ref = fEntityTable[refArray[count]];
215
216                        const size_t len = ref.getContentLength();
217
218                        const size_t origRefStartPos = refPosArray[count] + 1;
219
220                        const size_t refEndPos = origRefStartPos + refAdj;
221
222                        const size_t refStartPos = refEndPos - len;
223
224                        sumOfRefLengths -= len;
225
226                        // move the existing content over to make room for the expanded entity then
227                        // copy the entity in.
228
229                        Array<XMLCh>::move(&contentStream0[origRefStartPos], &contentStream0[refEndPos], size);
230                        Array<XMLCh>::copy(ref.getContent(), &contentStream0[refStartPos], len);
231
232                        // update the string end positions to adjust for the ref replacement
233                        while (*origStringEndPtr >= &contentStream0[origRefStartPos])
234                        {
235                                *origStringEndPtr-- += refAdj;
236                        }
237                }
238                while (unlikely(count != 0));
239        }
240        else
241        {
242                // we're going to be inserting some number of new string end pointers; we know how
243                // many but not where. make sure the array has room for these new ones and then begin
244                // updating the content stream and string end array
245
246                if (unlikely(&stringEndPtr[sumOfStringEndCount] >= stringEndArray.limit()))
247                {
248                        DEBUG_MESSAGE(" *** EXTENDING STRING ARRAY BUFFER ***")
249                        size_t offset = stringEndPtr - &stringEndArray[0];
250                        stringEndArray.expand(offset);
251                        stringEndPtr = &stringEndArray[offset];
252                }
253
254                const XMLCh ** origStringEndPtr = stringEndPtr - 1;
255
256                const XMLCh ** adjustedStringEndPtr = origStringEndPtr + sumOfStringEndCount;
257
258                // scan through and see if any of the refs will end up inserting symbols; we need to
259                // store these in order but have to traverse through the content stream itself in
260                // reverse order.
261
262                do
263                {
264                        const size_t refAdj = sumOfRefLengths - count;
265
266                        --count;
267
268                        const size_t size = refPosArray[count + 1] - refPosArray[count] - 1;
269
270                        const XMLReference & ref = fEntityTable[refArray[count]];
271
272                        const size_t len = ref.getContentLength();
273
274                        const size_t origRefStartPos = refPosArray[count] + 1;
275
276                        const size_t refEndPos = origRefStartPos + refAdj;
277
278                        const size_t refStartPos = refEndPos - len;
279
280                        sumOfRefLengths -= len;
281
282                        // move the existing content over to make room for the expanded entity then
283                        // copy the entity in.
284
285                        Array<XMLCh>::move(&contentStream0[origRefStartPos], &contentStream0[refEndPos], size);
286                        Array<XMLCh>::copy(ref.getContent(), &contentStream0[refStartPos], len);
287
288                        // update the string end positions to adjust for the ref replacement and
289                        // place the adjusted pointers into the correct positions after accounting
290                        // for the new pointers yet to be added.
291                        while (*origStringEndPtr >= &contentStream0[origRefStartPos])
292                        {
293                                *adjustedStringEndPtr-- = *origStringEndPtr-- + refAdj;
294                        }
295
296                        XMLSize_t stringEndCount = ref.getStringEndCount();
297
298                        // fill in any of the "inserted" string end pointers (i.e., the ones that
299                        // are within the resolved reference itself.)
300                        if (stringEndCount)
301                        {
302                                const XMLSize_t * refStringEndArray = ref.getStringEndArray();
303                                const XMLCh * const baseAdjustedStringEnd = &contentStream0[refStartPos];
304
305                                do
306                                {
307                                        *adjustedStringEndPtr-- = baseAdjustedStringEnd + refStringEndArray[--stringEndCount];
308                                }
309                                while (stringEndCount);
310                        }
311                }
312                while (unlikely(count != 0));
313
314                // adjust the string end count
315                stringEndPtr += sumOfStringEndCount;
316        }
317}
318
319/// ----------------------------------------------------------------------------------------------------
320
321template<unsigned int CodeUnitSize>
322gid_t XMLReferenceTable::addOrFind(const XMLByte * entityName, const size_t length, const bool inAttVal, XMLScanner * scanner, XMLSymbolTable * symbolTable)
323{
324        const gid_t refId = fEntityRefTable[inAttVal].find(entityName, length);
325
326        if (unlikely(refId == -1))
327        {
328                return expandRef<CodeUnitSize>(entityName, length, inAttVal, scanner, symbolTable);
329        }
330        else
331        {
332                return fEntityRefTable[inAttVal][refId]->fId;
333        }
334}
335
336/// ----------------------------------------------------------------------------------------------------
337
338template<unsigned int CodeUnitSize>
339gid_t XMLReferenceTable::expandRef(const XMLByte * entityName, const size_t length, const bool inAttVal, XMLScanner * scanner, XMLSymbolTable * symbolTable)
340{
341    DEBUG_MESSAGE("expandRef<" << CodeUnitSize << ">(" << entityName << ',' << length << ',' << inAttVal << ",...)")
342
343    DEBUG_MESSAGE("fTranscoder=" << fTranscoder->getEncodingName());
344
345        // add the ref to the appropriate table
346        XMLTableRef tableRef;
347        tableRef.fKey = fEntityPool.insert(entityName, length);
348        tableRef.fLength = length;
349        tableRef.fId = fEntityCount;
350        fEntityRefTable[inAttVal].add(tableRef);
351
352        XMLReference entityRef;
353        // this ref hasn't been seen before; ask the scanner to expand it
354        XMLBuffer entity(1023, fMemoryManager);
355        // transcode the entity from the source document format to xerces' internal utf16 format
356        fTranscoder->transcodeFrom(entityName, length, entity);
357
358    DEBUG_MESSAGE("entity=" << entity.getRawBuffer());
359
360        XMLCh * entityRefName = XMLString::replicate(entity.getRawBuffer(), entity.getLen(), fMemoryManager);
361        entity.reset();
362
363    DEBUG_MESSAGE("entityRefName=" << entityRefName);
364
365        #ifdef PRINT_DEBUG_MESSAGE
366        entityRef.fRefNameString = XMLString::transcode(entityRefName);
367        #endif
368
369        // then attempt to expand the entity
370        if (likely(scanner->expandEntityRef(entityRefName, inAttVal, entity)))
371        {
372                // expansion succeeded; now we have to construct a content stream (and potentially a symbol gid stream)
373                parseRef(entity.getRawBuffer(), entity.getLen(), inAttVal, entityRef, scanner, symbolTable);
374        }
375        else
376        {
377                DEBUG_MESSAGE(" *** ENTITY EXPANSION ERROR! " << entityRefName);
378
379                entityRef.fType = XMLReference::Simple;
380                // if we encounter an error, construct the full ref name...
381                entity.reset();
382                entity.append(chAmpersand);
383                entity.append(entityRefName, length);
384                entity.append(chSemiColon);
385
386                // and then insert it into the table
387                entityRef.fContent = fContentPool.insert(entity.getRawBuffer(), length);
388                entityRef.fContentLength = length;
389        }
390
391        XMLString::release(&entityRefName, fMemoryManager);
392
393        if (unlikely(fEntityCount == fEntityTable.capacity()))
394        {
395                fEntityTable.expand(fEntityTable.capacity());
396        }
397        fEntityTable[fEntityCount] = entityRef;
398
399        return fEntityCount++;
400}
401
402/// ----------------------------------------------------------------------------------------------------
403
404void XMLReferenceTable::parseRef
405(
406        XMLCh *                         entity
407        , XMLSize_t                     length
408        , const bool            inAttVal
409        , XMLReference &        toFill
410        , XMLScanner *          scanner
411        , XMLSymbolTable *      symbolTable
412)
413{
414
415        if (inAttVal)
416        {
417                length = normalizeValue(entity, length, 1, scanner);
418        }
419
420        if (length < 2)
421        {
422                // if the length of this entity is < 2, then it must be a single replacement or empty
423                if (length == 1)
424                {
425                        toFill.fType = XMLReference::Single;
426                        toFill.fContentLength = 1;
427                        toFill.fContent = fContentPool.insert(entity, 1);
428                }
429                else
430                {
431                        toFill.fType = XMLReference::Empty;
432                        toFill.fContentLength = 0;
433                }
434        }
435        else
436        {
437                if (inAttVal)
438                {
439                        toFill.fType = XMLReference::Simple;
440                        toFill.fContentLength = length;
441                        toFill.fContent = fContentPool.insert(entity, length);
442                }
443                else
444                {
445                        // is this a simple entity expansion (i.e., only content) or a complex one? (i.e., content and markup)
446//                      if (XMLStringU::indexOf<chOpenAngle>(entity, length) == -1)
447//                      {
448//                              toFill.fType = XMLReference::Simple;
449//                              toFill.fContentLength = normalizeValue(entity, length, 0, scanner);
450//                              toFill.fContent = fContentPool.insert(entity, toFill.fContentLength);
451//                      }
452//                      else
453//                      {
454                                // Construct a UTF16 character set adapter to perform the markup conversion
455
456                                // TODO: check if a '<' exists in the stream and only use parabix if one does; move internal ref
457                                // handling code to a static function in this class.
458
459                                DEBUG_MESSAGE(" ************************************** PARSING CONTENT VALUE ************************************* ")
460
461                                // NOTE: it'd probably more efficient to do this with a byte-at-a-time system but for now
462                                // this ensures that the output format is consistent even if it's changed.
463
464                                // NOTE 2: I'm going with the assumption that it won't matter if two symbols that ought to
465                                // be identical (if both looked up in UTF16) can be safely stored as two seperate symbols
466                                // given that an expanded entity must itself be legal.
467
468                XMLTranscoder * const transcoder = symbolTable->getTranscoder();
469                                XMLLineColTracker refLineColTracker;
470                XMLUTF16CharacterSetAdapter refAdapter(transcoder, fMemoryManager, 0);
471                                refAdapter.init(scanner, symbolTable, refLineColTracker);
472                DEBUG_MESSAGE("transcoder=" << transcoder->getEncodingName());
473                                // swap out the symbol table transcoder with a UTF16 transcoder
474                                // symbolTable->setTranscoder(&refTranscoder);
475                                bool resumeSymbol = symbolTable->fResumeSymbol;
476                                int startPosition = symbolTable->fStartPosition;
477                                symbolTable->fResumeSymbol = 0;
478
479                                // construct the remaining data structures needed for the conversion
480                                ContentStream contentStream(length);
481                                SymbolArray symbolArray(length / 2);
482                                StringPtrArray stringEndArray(length / 2);
483
484                                // parse the reference
485                                toFill.fContentLength =
486                                        refAdapter.parseInternal
487                                        (
488                                                reinterpret_cast<const XMLByte*>(entity)                // src
489                                                , length * 2                                                                    // avail
490                                                , contentStream                                                                 // contentStream
491                                                , toFill.fMarkupCount                                                   // markupCount
492                                                , symbolArray                                                                   // symbolArray
493                                                , toFill.fSymbolCount                                                   // symbolCount
494                                                , stringEndArray                                                                // stringEndArray
495                                                , toFill.fStringEndCount                                                // stringEndCount
496                                        );
497
498                                // restore the symbol table transcoder's original transcoder
499                                // symbolTable->setTranscoder(fTranscoder);
500                                symbolTable->fResumeSymbol = resumeSymbol;
501                                symbolTable->fStartPosition = startPosition;
502
503                                toFill.fContent = fContentPool.insert(&contentStream[0], toFill.fContentLength);
504
505                                if (toFill.fMarkupCount == 0)
506                                {
507                                        toFill.fType = XMLReference::Simple;
508                                }
509                                else
510                                {
511                                        // and store the content, gids and string ends
512                                        toFill.fType = XMLReference::Complex;
513                                        toFill.fSymbols = fSymbolPool.insert(&symbolArray[0], toFill.fSymbolCount);
514                                        XMLSize_t * stringEnds = fStringEndPool.allocate(toFill.fStringEndCount);
515                                        // but convert the string end pointers into offsets
516                                        for (XMLSize_t i = 0; i < toFill.fStringEndCount; i++)
517                                        {
518                                                stringEnds[i] = (stringEndArray[i] - &contentStream[0]);
519                                        }
520                                        toFill.fStringEndArray = stringEnds;
521                                }
522                                DEBUG_MESSAGE(" ************************************** PARSED CONTENT VALUE ************************************** ")
523//                      }
524                }
525
526
527                DEBUG_MESSAGE('{' << toFill.fContent << '}')
528        }
529}
530
531IDISA_ALWAYS_INLINE
532XMLSize_t XMLReferenceTable::normalizeValue
533(
534        XMLCh *                                         entity
535        , XMLSize_t                                     length
536        , bool                                          isAttributeValue
537        , const XMLScanner * const      scanner
538)
539{
540        DEBUG_MESSAGE("XMLReferenceTable::normalizeValue(" << entity << ',' << length << ',' << isAttributeValue << ')')
541
542        if (unlikely(length == 0))
543        {
544                return 0;
545        }
546
547        XMLSize_t pos = 0;
548        XMLSize_t deletedChars = 0;
549        const XMLReader::XMLVersion version = scanner->getXMLVersion();
550        const XMLCh chSpaceOrLF = isAttributeValue ? chSpace : chLF;
551
552        // do end-of-line normalization on the input
553        if (likely(version == XMLReader::XMLV1_0))
554        {
555                do
556                {
557                        XMLCh * entityRef = &entity[pos];
558
559                        // do we have an escaped character in this entity?
560                        XMLSize_t len = XMLStringU::indexOf<0xFFFF>(entityRef, length - pos);
561
562                        if (len == -1)
563                        {
564                                // no; normalize everything in the string
565                                len = length - pos;
566                                pos = length;
567                        }
568                        else
569                        {
570                                // yes; normalize everything up to that character but not including it
571                                deletedChars++;
572                                // increment the position so that we ignore the 0xFFFF on the following loop
573                                pos += len + 2;
574                        }
575
576                        // do XML 1.0 end of line normalization
577                        XMLChIterator<chCR> crItr(entityRef, len);
578                        while (crItr.next())
579                        {
580                                size_t pos = crItr.pos();
581
582                                entityRef[pos++] = chSpaceOrLF;
583                                if (entityRef[pos] == chLF)
584                                {
585                                        // if we found a {CR,LF}, then mark the LF as an escaped character so that
586                                        // we can remove it afterwards.
587                                        entityRef[pos] = 0xFFFF;
588                                        deletedChars++;
589                                }
590                        }
591
592                        // attribute whitespace normalization
593                        if (isAttributeValue)
594                        {
595                                // do any remaining whitespace normalization on attribute values
596                                XMLChIterator2<chLF, chHTab> wsItr(entityRef, len);
597                                while (wsItr.next())
598                                {
599                                        entityRef[wsItr.pos()] = chSpace;
600                                }
601                        }
602                }
603                while (pos < length);
604        }
605        else if (version == XMLReader::XMLV1_1)
606        {
607                do
608                {
609                        XMLCh * entityRef = &entity[pos];
610
611                        // do we have an escaped character in this entity?
612                        XMLSize_t len = XMLStringU::indexOf<0xFFFF>(entityRef, length - pos);
613                        if (len == -1)
614                        {
615                                // no; normalize everything in the string
616                                len = length - pos;
617                                pos = length;
618                        }
619                        else
620                        {
621                                // yes; normalize everything up to that character but not including it
622                                deletedChars++;
623                                // increment the position so that we ignore the 0xFFFF on the following loop
624                                pos += len + 2;
625                        }
626
627                        // do XML 1.1 specific end of line normalization
628                        XMLChIterator<chCR> crItr(entityRef, len);
629                        while (crItr.next())
630                        {
631                                size_t pos = crItr.pos();
632
633                                entityRef[pos++] = chSpaceOrLF;
634                                if ((entityRef[pos] == chLF) || (entityRef[pos] == chNEL))
635                                {
636                                        // if we found a {CR,LF} or a {CR,NEL}, then mark the LF/NEL as an escaped
637                                        // character so that we can remove it afterwards.
638                                        entityRef[pos] = 0xFFFF;
639                                        deletedChars++;
640                                }
641                        }
642
643                        XMLChIterator2<chNEL, chLineSeparator> nonLfItr(entityRef, len);
644                        while (unlikely(nonLfItr.next()))
645                        {
646                                entityRef[nonLfItr.pos()] = chSpaceOrLF;
647                        }
648
649                        // attribute whitespace normalization
650                        if (isAttributeValue)
651                        {
652                                // do any remaining whitespace normalization on attribute values
653                                XMLChIterator2<chLF, chHTab> wsItr(entityRef, len);
654                                while (wsItr.next())
655                                {
656                                        entityRef[wsItr.pos()] = chSpace;
657                                }
658                        }
659                }
660                while (pos < length);
661        }
662
663        // remove all deleted characters from the final production
664        if (unlikely(deletedChars != 0))
665        {
666                // TODO: there must be a smarter way of using some bitset to mark non-0xFFFF characters and merge only
667                // the correct ones.
668                XMLChIterator<0xFFFF> itr(entity, length);
669
670                size_t pos = 0;
671                size_t start = 0;
672                itr.next();
673                size_t end = itr.pos();
674
675                for (XMLSize_t index = 0; index < deletedChars; index++)
676                {
677                        size_t len = end - start;
678                        if (len)
679                        {
680                                Array<XMLCh>::move(&entity[start], &entity[pos], len);
681                                pos += len;
682                        }
683                        start = end + 1;
684                        end = itr.pos();
685                }
686                size_t len = length - start;
687                Array<XMLCh>::move(&entity[start], &entity[pos], len);
688                length = pos + len;
689
690                #ifdef PRINT_DEBUG_MESSAGE
691                entity[length] = 0;
692                #endif
693        }
694
695        DEBUG_MESSAGE(" --> {" << entity << ',' << length << '}')
696
697        return length;
698}
699
700XERCES_CPP_NAMESPACE_END
701
702#endif
Note: See TracBrowser for help on using the repository browser.