Initial revision
[TestXSLT.git] / libsablot / src / engine / parser.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s): Tim Crook <tcrook@accelio.com>
19  *                 Christian Lefebvre <christian.lefebvre@atosorigin.com>
20  * 
21  * Alternatively, the contents of this file may be used under the
22  * terms of the GNU General Public License Version 2 or later (the
23  * "GPL"), in which case the provisions of the GPL are applicable 
24  * instead of those above.  If you wish to allow use of your 
25  * version of this file only under the terms of the GPL and not to
26  * allow others to use your version of this file under the MPL,
27  * indicate your decision by deleting the provisions above and
28  * replace them with the notice and other provisions required by
29  * the GPL.  If you do not delete the provisions above, a recipient
30  * may use your version of this file under either the MPL or the
31  * GPL.
32  */
33
34 //  parser.cpp
35
36 #include "base.h"
37 #include "parser.h"
38 #include "situa.h"
39 #include "tree.h"
40 #include "error.h"
41 #include "proc.h"
42 #include "encoding.h"
43 #include "guard.h"
44
45 // GP: clean
46
47 // 
48 //
49 //      TreeConstructer
50 //
51 //
52
53 SAXHandlerInternal TreeConstructer::myHandlerRecord =
54 {
55     saxStartDocument,
56     saxStartElement,
57     saxEndElement,
58     saxStartNamespace,
59     saxEndNamespace,
60     saxComment,
61     saxPI,
62     saxCharacters,
63     saxEndDocument,
64     saxStartNamespace2
65 };
66
67 TreeConstructer::TreeConstructer(Sit S_)
68 : S(S_)
69 {
70     theParser = NULL;
71     theTree = NULL;
72     theDataLine = NULL;
73     theLineNumber = 0;
74     inSAXForAWhile = FALSE;
75     nsCount.append(0);
76 }
77
78 TreeConstructer::~TreeConstructer()
79 {
80 }
81
82
83 eFlag TreeConstructer::parseDataLineUsingGivenExpat(Sit S, 
84     Tree *t, DataLine *d, XML_Parser theParser_)
85 {
86     theTree = t;
87     theDataLine = d;
88     theParser = theParser_;
89
90     S.setCurrFile(d -> fullUri);
91     E( feedDocumentToParser(S, this) );
92     E( t -> parseFinished(S) );
93     if (t -> XSLTree)
94     {
95         t -> stripped += t -> getRoot().strip();
96         E( t -> aliases().checkRedefinitions(S, *t) );
97         E( t -> attSets().checkRedefinitions(S) );
98     }
99     return OK;
100 };
101
102
103 eFlag TreeConstructer::parseDataLineUsingExpat(Sit S, 
104                                                Tree *t, DataLine *d, 
105                                                char *base_ /*=NULL*/)
106 {
107     theParser = XML_ParserCreateNS(NULL, THE_NAMESPACE_SEPARATOR);
108
109     M( S, theParser );
110     // XML_UseParserAsHandlerArg(parser);
111     XML_SetElementHandler(theParser, 
112         tcStartElement,
113         tcEndElement);
114     XML_SetCharacterDataHandler(theParser, 
115         tcCharacters);
116     XML_SetNamespaceDeclHandler(theParser, 
117         tcStartNamespace, 
118         tcEndNamespace);
119     XML_SetCommentHandler(theParser,
120         tcComment);
121     XML_SetProcessingInstructionHandler(theParser,
122         tcPI);
123     
124     // the unknown encoding handler is no more used:
125     // XML_SetUnknownEncodingHandler(theParser, 
126     //     tcUnknownEncoding, 
127     //     NULL);
128
129     XML_SetExternalEntityRefHandler(theParser,
130                                     tcExternalEntityRef);
131     XML_SetEntityDeclHandler(theParser, tcEntityDecl);
132
133
134     XML_SetUserData(theParser, this);
135     if (S.getProcessor())
136       XML_SetBase(theParser, S.getProcessor() -> findBaseURI(S, t ->getURI()));
137     else if (base_)
138       XML_SetBase(theParser, base_);
139     
140     // wasn't this done before?
141     XML_SetParamEntityParsing(theParser, XML_PARAM_ENTITY_PARSING_ALWAYS);
142
143     //we want to get all info (including prefixes)
144 #ifdef EXPAT_SUPPORTS_TRIPLETS
145     XML_SetReturnNSTriplet(theParser, 1);
146 #endif
147
148     eFlag eCode = parseDataLineUsingGivenExpat(S, t, d, theParser);
149
150     XML_ParserFree(theParser);
151     if( eCode )
152         return S.getError();
153     return OK;
154 };
155
156 eFlag TreeConstructer::parseUsingSAX(Sit S, Tree *t, OutputterObj& source,
157                                      SAXOutputType ot)
158 {
159     theTree = t;
160     theDataLine = NULL;
161     // register the handler with the outputter
162     E( source.setOptionsSAX(S, (SAXHandler*)&myHandlerRecord, this, ot) );
163     E( source.eventBeginOutput(S) );
164     return OK;
165 }
166
167 eFlag TreeConstructer::parseUsingSAXForAWhile(Sit S, OutputterObj& source,
168                                               Str &saxUri, 
169                                               Bool resetNamespaces,
170                                               Tree* srcTree,
171                                               NSList &swallowNS)
172 // it's assumed that this is a tree constructer over a dataline
173 // (not a SAX one)
174 {
175     assert(theTree && theDataLine);
176     inSAXForAWhile = TRUE;
177     theSAXUri = saxUri;
178
179     if (resetNamespaces) 
180       E( theTree -> pushPendingNS(S, srcTree, swallowNS) );
181
182     // register the handler with the outputter
183     E( source.setOptionsSAX(S, (SAXHandler*)&myHandlerRecord, this, SAXOUTPUT_COPY_TREE) );
184     E( source.eventBeginOutput(S) );
185     return OK;
186 }
187
188 eFlag TreeConstructer::parseUsingSAXForAWhileDone(Sit S, OutputterObj& source,
189                                                   Bool resetNamespaces)
190 {
191     E( source.eventEndOutput(S) );
192     inSAXForAWhile = FALSE;
193
194     if (resetNamespaces) 
195       E( theTree -> popPendingNS(S) );
196
197     return OK;
198 }
199
200 int TreeConstructer::getCurrentLineNumber() const
201 {
202   if (this -> inSAXForAWhile)
203     {
204       return this -> S.getCurrSAXLine();
205     }
206   else if (theParser)
207     {
208       return XML_GetCurrentLineNumber(theParser);
209     }
210   else
211     return theLineNumber;
212 }
213   
214 /* static */
215 eFlag TreeConstructer::getDocEncoding(Sit S, const char *buf, Str& theEncoding, TreeConstructer *this_)
216   // assumes the parse buffer null-terminated
217 {
218   // copy the unsigned shorts out of the string to avoid misalignment
219     unsigned short bom_part1, bom_part2;
220     memcpy (&bom_part1, buf, sizeof(unsigned short));
221     switch (bom_part1)
222     {
223     case 0xfeff:
224     case 0xfffe:
225         theEncoding = "UTF-16";
226         break;
227     case 0x003c:
228     case 0x3c00:
229         // no byte order mark!
230         memcpy (&bom_part2, buf+1, sizeof(unsigned short));
231         if ((bom_part2 == 0x003f) ||
232             (bom_part2 == 0x3f00))
233             theEncoding = "UTF-16";
234         else
235             this_ -> Warn(S, W_BAD_START);
236         break;
237     case 0x0000:
238         memcpy (&bom_part2, buf+1, sizeof(unsigned short));
239         if ((bom_part2 == 0x003c) ||
240             (bom_part2 == 0x3c00))
241             theEncoding = "ISO-10646-UCS-4";
242         else
243             this_ -> Warn(S, W_BAD_START);
244         break;
245     default:
246         {
247         // look for "<?xml " to distinguish from "<?xml-stylesheet"
248         // or any other similar processing instructions
249           Bool found = FALSE;
250           if (buf[0] == '<' && buf[1] == '?' && buf[2] == 'x' 
251               && buf[3] == 'm' && buf[4] == 'l' && buf[5] == ' ')
252             {
253               const char *p = buf;
254               p = strpbrk(p + 2,"=?");
255               while (! found && p && *p == '=')
256                 {
257                   //now find the pseudo-attribute name
258                   const char *beg = p - 1;
259                   while ( isWhite(*beg) ) beg--;
260                   while ( (!isWhite(*beg)) && *beg != '?') beg--;
261                   if ( strncmp(beg + 1, "encoding", 8) )
262                     p = strpbrk(p + 1, "=?");
263                   else
264                     {
265                       p++;
266                       skipWhite(p);
267                   
268                       const char *q = strpbrk(p + 1, "?\'\"");
269                       if (q && *q != '?' && *q == *p)
270                         {
271                           theEncoding.nset(p + 1, q - p - 1);
272                           found = TRUE;
273                         }
274                     }
275                 }
276             }
277           if (! found) theEncoding = "UTF-8";
278         };
279     }  
280     return OK;
281 }
282
283
284 /* static */
285 eFlag TreeConstructer::feedDocumentToParser(Sit S, void* constructer)
286 {
287     TreeConstructer *this_ =
288         (TreeConstructer*) constructer;
289     //char convBuffer[PARSE_CONV_BUFSIZE];
290     //char rawBuffer[PARSE_BUFSIZE + 1];
291
292     char *convBuffer, *rawBuffer;
293     GPA( GChar ) convAux = convBuffer = new char[PARSE_CONV_BUFSIZE];
294     GPA( GChar ) rawAux = rawBuffer = new char[PARSE_BUFSIZE + 1];
295
296     char *outbuf = (char *) convBuffer;
297     const char *inbuf = (char *) rawBuffer;
298
299     Bool quit = FALSE, firstTime = TRUE;
300     Bool mustConvert = FALSE, haveReadAll = FALSE;
301     int res = 0, bytes = 0;
302     size_t inleft = 0, outleft = 0;
303     EncResult convResult = ENC_OK;
304     CDesc cd = (CDesc) -1;
305     // seems to be useless here
306     // void *recoderUD;
307     // EncHandler *recoder = NZ(S.getProcessor()) -> getEncHandler(&recoderUD);
308     Str theEncoding;
309     
310     if (S.isError())
311         return NOT_OK;
312     XML_Parser parser = NZ( this_ -> theParser );
313
314     // GP: tree constructer does get killed on error
315     // callers are Processor::parse (stack variable) and ext ent handler (disposes)
316
317     // this is to add the 'xml' namespace declarations
318     //
319     tcStartNamespace(constructer, "xml", theXMLNamespace);
320
321     while (!quit)
322     {
323 //        char *buf = (char*) XML_GetBuffer(parser, PARSE_BUFSIZE + 1);
324         switch (convResult)
325         {
326         case ENC_OK:
327             {
328                 // just get the next block of data
329                 bytes = this_ -> theDataLine -> get(S, rawBuffer, PARSE_BUFSIZE); 
330                 haveReadAll = (bytes < PARSE_BUFSIZE);
331                 inbuf = rawBuffer;
332                 inleft = bytes;
333             }; break;
334         case ENC_EINVAL:
335             {
336                 // buffer ended with an incomplete sequence
337                 // copy the sequence
338                 memmove(rawBuffer, inbuf, inleft);
339                 // get the rest from dataline
340                 bytes = this_ -> theDataLine -> get(S, rawBuffer + inleft, PARSE_BUFSIZE - inleft); 
341                 haveReadAll = (bytes < PARSE_BUFSIZE - (int) inleft);
342                 inbuf = rawBuffer;
343                 inleft += bytes;
344             }; break;
345         case ENC_E2BIG:
346             {
347                 // the converted text was too big to fit in convBuffer
348                 // don't get more, just convert from input buffer
349                 // not changing haveReadAll, inbuf or inleft
350             }; break;
351         default:
352             assert(!"feedDocumentToParser");
353         }
354
355         // the test for bytes==-1 is superfluous but just in case
356         if (bytes == -1 || S.isError())
357         {
358             // read error, bailing out
359           //XML_ParserFree(parser);
360           //the parser is freed at another place too
361             return NOT_OK;
362         };
363
364         if (firstTime)
365         {
366             // find the document's encoding
367             E( getDocEncoding(S, rawBuffer, theEncoding, this_) );
368             // decide whether to recode or not
369             if (S.recoder().handledByExpat(theEncoding))
370                 mustConvert = FALSE;
371             else
372             {
373                 mustConvert = TRUE;
374                 XML_SetEncoding(parser, "UTF-8");
375                 E( S.recoder().openToUTF8(S, theEncoding, cd) );
376             }
377         }
378         
379         if (mustConvert)
380         {
381             outleft = PARSE_CONV_BUFSIZE;
382             outbuf = (char *) convBuffer;
383             E( S.recoder().conv(S, cd,
384                 inbuf, inleft, outbuf, outleft, 
385                 convResult) );
386             switch(convResult)
387             {
388             case ENC_OK:
389                 quit = haveReadAll;
390                 break;
391             case ENC_EINVAL:
392             case ENC_E2BIG:
393                 quit = FALSE;
394                 break;
395             case ENC_EILSEQ:
396                         Err1T(this_, S, E1_BAD_CHAR, theEncoding);
397                 break;
398             default:
399                 assert(!"bad convResult");
400             };
401             bytes = PARSE_CONV_BUFSIZE - outleft;
402             res = XML_Parse(parser,convBuffer,bytes,FALSE);
403         }
404         else
405         {
406             quit = haveReadAll;
407             res = XML_Parse(parser,rawBuffer,bytes,FALSE);
408         }
409         if (S.isError())
410             return NOT_OK;
411         if (!res)
412           break;
413         firstTime = FALSE;
414     }
415
416     if (res) 
417         {
418         //finish with parser
419         res = XML_Parse(parser, NULL, 0, TRUE);
420         if (S.isError())
421             return NOT_OK;
422         }
423     if (!res) 
424     {
425         // parsing error to be reported
426         // situation_.setCurrFile(t -> name);   is unnecessary as already set
427
428         // hack to avoid an apparent bug in expat causing crashes when an UTF-8 text
429         // happens to start with a byte order mark by mistake
430         if (!(firstTime && rawBuffer[0] == (char) 0xEF && 
431             rawBuffer[1] == (char) 0xBB && rawBuffer[2] == (char) 0xBF))
432             S.setCurrLine(XML_GetCurrentLineNumber(parser));
433         XML_Error code = XML_GetErrorCode(parser); 
434         Str eCodeStr, eNameStr;
435         eCodeStr = (int)code;
436         eNameStr = (char*) XML_ErrorString(code);
437         // XML_ParserFree(parser); -- done later
438         Err2T(this_, S, E_XML, eCodeStr, eNameStr);
439     }
440     
441     // remove the 'xml' namespace declarations
442     //
443     tcEndNamespace(constructer, "xml");
444     return OK;
445 }
446
447 //
448 //  tcStartDocument
449 //  callback for the document start event
450 //
451
452 /* static */
453 void TreeConstructer::tcStartDocument(
454     void* constructer)
455 {
456     TreeConstructer *this_ =
457         (TreeConstructer*) constructer;
458     if (this_ -> S.isError())
459         return;
460     // new slot for count of pending namespaces
461     this_ -> nsCount.append(0);
462 };
463
464
465
466 //
467 //  tcStartElement
468 //  callback for the element start event
469 //
470
471 void _dump(Tree *tree, QName &name)
472 {
473   Str uri = tree -> expand(name.getUri());
474   Str loc = tree -> expand(name.getLocal());
475   Str pre = tree -> expand(name.getPrefix());
476
477   printf("%s, %s, %s\n", (char*)uri, (char*)pre, (char*)loc);
478 }
479
480 /* static */
481 void TreeConstructer::tcStartElement(
482     void *constructer,const char *elName,const char **atts)
483 {
484     TreeConstructer *this_ =
485         (TreeConstructer*) constructer;
486
487     Tree *t = this_ -> theTree;
488     char **p = (char**) atts;
489     XSL_OP opCode;
490     XSL_ATT attCode;
491     BOOL itsXSL = FALSE;
492     BOOL itsExtension = FALSE;
493     Vertex *v;  // GP: OK (goes to tree)
494     Attribute *a;   // GP: OK (goes to tree)
495     QName el;
496     int elemLine;
497     int xmlSpace = -1;
498     AttsCache auxAtts;
499
500     if (this_ -> S.isError())
501         return;
502
503     this_ -> S.setCurrLine(elemLine = this_ -> getCurrentLineNumber());
504
505     //get elName to QName q - DO NOT CHANGE LATER!!
506     if (setQNameFromExpat(this_ -> S, this_, el, elName))
507         return;
508
509     itsXSL = (t -> XSLTree) && (t -> expand(el.getUri()) == theXSLTNamespace);
510
511     //first we have to create all attributes, we need them for extension
512     //and excluded namespace definitions
513     t -> markNamespacePrefixes(this_ -> S); //IMPORTANT
514
515     while(*p)
516     {
517       QName q;
518       if (setQNameFromExpat(this_ -> S, this_, q, (char *)p[0]))
519         return;
520       
521       //check xml attributes (currently xml:space)
522       if (q.getUri() == t -> stdPhrase(PHRASE_XML_NAMESPACE) && 
523           t -> expand(q.getLocal()) == (const char*)"space")
524         {
525           if (!strcmp(p[1], "preserve"))
526             xmlSpace = 1;
527           else
528             xmlSpace = 0;
529         }
530       
531       //xsl attributes may occure in literal ements!!
532       //attCode = (itsXSL ? 
533       attCode = (itsXSL || (t -> expand(q.getUri()) == theXSLTNamespace) ?
534                  (XSL_ATT) lookup(t -> expand(q.getLocal()),xslAttNames) : 
535                  XSLA_NONE);
536       //check duplicities
537       if (auxAtts.find(q))
538         {
539           Str name;
540           t -> expandQStr(q, name);
541           this_ -> S.message(MT_ERROR, E_DUPLICIT_ATTRIBUTE, 
542                              (char*)name, (char*)NULL);
543         }
544       a = new(&(t -> getArena())) Attribute(*t, q, p[1],attCode);
545       a -> lineno = this_ -> getCurrentLineNumber();
546       auxAtts.append(a);
547
548       //process extension and excluded prefixes
549       if (attCode == XSLA_EXT_ELEM_PREFIXES || 
550           attCode == XSLA_EXCL_RES_PREFIXES)
551         {
552           t -> pushNamespacePrefixes(this_ -> S, a -> cont, attCode);
553         }
554       //move on
555       p += 2;
556     };
557
558     // DETACH: optimize this comparison ###
559     if (itsXSL) 
560       //t -> stdPhrase(PHRASE_XSL_NAMESPACE)))
561       {
562         opCode = (XSL_OP) lookup((char*)(t->expand(el.getLocal())),xslOpNames);
563         if (opCode == XSL_NONE)
564           {
565             if (this_ -> theDataLine) {
566               if (this_ -> inSAXForAWhile)
567                 this_ -> S.setCurrFile(this_ -> theSAXUri);
568               else
569                 this_ -> S.setCurrFile(this_ -> theDataLine -> fullUri);
570             }
571             this_ -> S.message(MT_ERROR, ET_BAD_XSL, (char*)NULL, (char*)NULL);
572             return;
573           };
574         v = new(&(t -> getArena())) XSLElement(*t, el, opCode);
575       }
576     else if ((t->XSLTree) && t -> isExtensionUri(el.getUri())) 
577       { 
578         //extension element
579         v = new(&(t -> getArena())) ExtensionElement(*t, el);
580         itsExtension = TRUE;
581       }
582     else
583       {
584         v = new(&(t -> getArena())) Element(*t, el);
585         Processor *proc = this_->S.getProcessor();
586         if ( proc && proc->outputter() ) 
587           {
588             OutputDocument *doc = proc->outputter()->getDocumentForLevel(TRUE);
589             toE(v)->setOutputDocument(doc);
590           }
591       }
592     
593     //check whether it is top level foreign
594     if (t -> XSLTree) 
595       {
596         if ( (t -> stackTop -> vt & VT_TOP_FOREIGN) ||
597              (!isXSL(v) &&
598               isXSL(t -> stackTop) && 
599               ((toX(t -> stackTop) -> op == XSL_STYLESHEET) || 
600                (toX(t -> stackTop) -> op == XSL_TRANSFORM))) )
601           {
602             v -> vt = (VTYPE)(v -> vt | VT_TOP_FOREIGN);
603           }
604       }
605
606     v -> lineno = elemLine;
607     t -> appendVertex(this_ -> S, v);
608
609     //if we are looking at the document element we need to check,
610     // whether the default namespace was declared
611     if (isRoot(v -> parent) && t -> pendingNS().findNdx(UNDEF_PHRASE) == -1)
612       tcStartNamespace(constructer, NULL, ""); //empty default namespace
613
614     t -> pendingNS().giveCurrent(this_ -> S, toE(v) -> namespaces, t,
615                                  this_ -> nsCount.last());
616 #ifndef EXPAT_SUPPORTS_TRIPLETS
617     toE(v) -> namespaces.findPrefix(toE(v) -> name);
618 #endif
619       //_dump(t, toE(v) -> name);
620
621     toE(v) -> namespaces.incPrefixUsage(toE(v) -> name.prefix);
622
623     //add attributes to the element
624     for (int n = 0; n < auxAtts.number(); n++)
625       {
626         const QName *auxName = &(auxAtts[n] -> getName());
627 #ifndef EXPAT_SUPPORTS_TRIPLETS
628         //force the prefix!!
629         toE(v) -> namespaces.findPrefix(*(const_cast<QName*>(auxName)));
630 #endif
631         t -> appendVertex(this_ -> S, auxAtts[n]);
632         if (auxName -> getPrefix() != UNDEF_PHRASE)
633           toE(v) -> namespaces.incPrefixUsage(auxName -> getPrefix());
634       }
635     auxAtts.keepThem();
636
637      //process xml space
638     if (xmlSpace == -1)
639       {
640         Bool val = this_ -> preserveSpace.number() ? 
641           this_ -> preserveSpace.last() : FALSE;
642         this_ -> preserveSpace.append(val);
643       }
644     else
645       this_ -> preserveSpace.append(xmlSpace);
646     toE(v) -> preserveSpace = this_ -> preserveSpace.last();
647     //xml-space end
648
649     if (itsXSL)
650       {
651         //t -> extensionNamespaces(this_ -> S, toE(v));
652         if (toX(v) -> checkAtts(this_ -> S)) return; 
653         // also check if a toplevel element does not 
654         //have a non-stylesheet parent
655         if (toX(v) -> checkToplevel(this_ -> S)) return; 
656       }
657     else if (itsExtension)
658       {
659         if (toExtension(v) -> checkAtts(this_ -> S)) return; 
660       }
661     else
662       {
663         if (t -> XSLTree)
664           {
665             int k;
666             int kLimit = toE(v) -> atts.number();
667             for (k = 0; k < kLimit; k++)
668               if (toA(toE(v) -> atts[k]) -> buildExpr(this_ -> S,
669                                                       TRUE, EX_NONE)) return;
670             // this calls situation.error() on error
671         }
672       }
673     this_ -> nsCount.append(0);
674 }
675
676 //
677 //  tcEndElement
678 //  callback for the element end event
679 //
680
681 /* static */
682 void TreeConstructer::tcEndElement(
683     void* constructer, const char* name)
684 {
685     TreeConstructer *this_ =
686         (TreeConstructer*) constructer;
687     if (this_ -> S.isError())
688         return;
689     Tree *t = this_ -> theTree;
690     // destroyed slot for count of pending namespaces
691     this_ -> nsCount.deppend();
692
693     Vertex *v = NZ( t -> stackTop );
694     t -> flushPendingText();
695     
696     if (t -> XSLTree)
697         t -> stripped += 
698         (isXSLElement(v)? toX(v) : cast(Daddy*, v))
699             -> strip();
700
701     if (isXSLElement(v))
702     {
703         // situation.error() is called in the following
704         if (toX(v) -> checkChildren(this_ -> S))
705             return;
706     } 
707     else if ( isExtension(v) ) 
708       {
709         if (toExtension(v) -> checkChildren(this_ -> S))
710             return;
711       }
712
713     //IMPORTANT STUFF
714     t -> processVertexAfterParse(this_ -> S, v, this_);
715
716     //cleanup
717     t -> popNamespacePrefixes(this_ -> S);
718     
719     //pop preserver space
720     this_ -> preserveSpace.deppend();
721 }
722
723
724 //
725 //  tcStartNamespace
726 //  callback for the namespace scope start event
727 //
728
729 /* static */
730 void TreeConstructer::tcStartNamespace(
731     void* constructer, const char* prefix, const char* uri)
732 {
733   tcStartNamespace2(constructer, prefix, uri, false);
734 }
735
736 void TreeConstructer::tcStartNamespace2(
737     void* constructer, const char* prefix, const char* uri, Bool hidden)
738 {
739     TreeConstructer *this_ =
740         (TreeConstructer*) constructer;
741     if (this_ -> S.isError())
742         return;
743     Tree *t = this_ -> theTree;
744
745     Vertex *newv;   // GP: OK (goes to tree)
746
747     //XML_Parser parser = this_ -> theParser;
748
749     Phrase prefixPh, uriPh;
750     if (prefix)
751       {
752         t -> dict().insert(prefix, prefixPh);
753       }
754     else
755       {
756         prefixPh = UNDEF_PHRASE;
757       }
758     t -> dict().insert(uri, uriPh);
759
760     // t -> pendingNS().appendAndSetOrdinal(
761     t -> pendingNS().append(
762         newv = new(&(t -> getArena())) 
763             NmSpace(*t, prefixPh, uriPh, hidden));
764     
765     newv -> lineno = this_ -> getCurrentLineNumber();
766     // count of pending namespaces increased
767     this_ -> nsCount[this_ -> nsCount.number()-1]++;
768
769     // warn on obsolete namespace
770     if (uri && !strcmp(oldXSLTNamespace, uri)) /* _PH_ */
771         this_ -> Warn1(this_ -> S, W1_OLD_NS_USED, (char*)uri)
772     else
773       {
774         if (prefix && !strcmp(prefix, "xsl") && 
775               uri && strcmp(theXSLTNamespace, uri)) /* _PH_ */
776           this_ -> Warn1(this_ -> S, W1_XSL_NOT_XSL, (char*) uri);
777       }
778 };
779
780 //
781 //  tcEndNamespace
782 //  callback for the namespace scope end event
783 //
784
785 /* static */
786 void TreeConstructer::tcEndNamespace(
787     void* constructer, const char* prefix)
788 {
789     TreeConstructer *this_ =
790         (TreeConstructer*) constructer;
791     if (this_ -> S.isError())
792         return;
793     Tree *t = this_ -> theTree;
794
795 #ifdef _DEBUG
796     // hope this works
797     Phrase prefixPh;
798     if (prefix)
799         prefixPh = t -> dict().lookup(prefix);
800     else
801         prefixPh = UNDEF_PHRASE;
802     assert(toNS(t -> pendingNS().last()) -> prefix == prefixPh);
803 #endif
804     t -> pendingNS().freelast(FALSE);
805     // count of pending namespaces decreased
806     this_ -> nsCount[this_ -> nsCount.number()-1]--;
807 };
808
809
810 //
811 //  tcComment
812 //  callback for the comment event
813 //
814
815 /* static */
816 void TreeConstructer::tcComment(
817     void* constructer, const char* contents)
818 {
819     TreeConstructer *this_ =
820         (TreeConstructer*) constructer;
821     if (this_ -> S.isError())
822         return;
823     Tree *t = this_ -> theTree;
824
825     if (t -> XSLTree)
826         return;
827
828     Comment *newNode;   // GP: OK
829     newNode = new(&(t -> getArena())) Comment(*t, contents);
830     newNode -> lineno = this_ -> getCurrentLineNumber();
831
832     Processor *proc = this_ -> S.getProcessor();
833     if ( proc && proc->outputter() ) 
834       {
835         OutputDocument *doc = proc->outputter()->getDocumentForLevel(FALSE);
836         newNode -> setOutputDocument(doc);
837       }
838
839     t -> appendVertex(this_ -> S, newNode);
840 };
841
842
843 //
844 //  tcPI
845 //  callback for the processing instruction event
846 //
847
848 /* static */
849 void TreeConstructer::tcPI(
850     void* constructer, const char* target, const char* contents)
851 {
852     TreeConstructer *this_ =
853         (TreeConstructer*) constructer;
854     if (this_ -> S.isError())
855         return;
856     Tree *t = this_ -> theTree;
857
858     if (t -> XSLTree)
859         return;
860
861     ProcInstr *newNode; // GP: OK
862     Phrase targetPh;
863     t -> dict().insert(target, targetPh);
864
865     newNode = new(&(t -> getArena()))
866         ProcInstr(*t, targetPh, contents);
867     newNode -> lineno = this_ -> getCurrentLineNumber();
868
869     Processor *proc = this_ -> S.getProcessor();
870     if ( proc && proc->outputter() ) 
871       {
872         OutputDocument *doc = proc->outputter()->getDocumentForLevel(FALSE);
873         newNode -> setOutputDocument(doc);
874       }
875     
876     t -> appendVertex(this_ -> S, newNode);
877 };
878
879
880 //
881 //  tcCharacters
882 //  callback for the character data ("text") event
883 //
884
885 /* static */
886 void TreeConstructer::tcCharacters(
887     void* constructer, const char* contents, int length)
888 {
889     TreeConstructer *this_ =
890         (TreeConstructer*) constructer;
891     if (this_ -> S.isError())
892         return;
893     Tree *t = this_ -> theTree;
894
895     Vertex *newVertex;  // GP: OK
896     if (!!(newVertex = t -> appendText(this_ -> S, (char *) contents, length)))
897         newVertex -> lineno = this_ -> getCurrentLineNumber();
898 };
899
900
901
902 //
903 //  tcEndDocument
904 //  callback for the document end event
905 //
906
907 /* static */
908 void TreeConstructer::tcEndDocument(
909     void* constructer)
910 {
911     TreeConstructer *this_ =
912         (TreeConstructer*) constructer;
913     if (this_ -> S.isError())
914         return;
915     // slot for namespaces counted for childs of this element destroyed 
916     this_ -> nsCount.deppend();
917 };
918
919
920 //
921 //  tcUnknownEncoding
922 //  callback for the unknown encoding event (expat)
923 //  needs to have "enc1250.h" included
924 //
925
926
927 // the unknown encoding handler is no more used:
928 /* static */
929 /*
930 int TreeConstructer::tcUnknownEncoding(
931     void *encodingHandlerData, const char *name, XML_Encoding *info)
932 {
933     int *theTable;
934     if (strEqNoCase((char*) name,"windows-1250"))
935         theTable = Enc1250;
936     else if (strEqNoCase((char*) name,"iso-8859-2"))
937         theTable = EncLatin2;
938     else
939         return 0;
940     int i;
941     for (i = 0; i < 0x80; i++)
942     {
943         info -> map[i] = i;
944         info -> map[i + 0x80] = theTable[i];
945     }
946     info -> map[0x7f] = -1;
947     info -> data = NULL;
948     info -> convert = NULL;
949     info -> release = NULL;
950     return 1;
951 };
952 */
953
954 //
955 //  tcExternalEntity
956 //  callback for the external entity reference event (expat)
957 //
958
959 /* static */
960 int TreeConstructer::tcExternalEntityRef(
961     XML_Parser parser, const char* context, const char* base,
962     const char* systemId, const char* publicId)
963 {
964     TreeConstructer *this_ =
965         (TreeConstructer*) XML_GetUserData(parser);
966
967     //PH
968     if ( publicId && ! this_ -> S.hasFlag(SAB_PARSE_PUBLIC_ENTITIES)) 
969       return 1;
970     
971     if (this_ -> S.isError())
972         return 0;
973     Tree *t = this_ -> theTree;
974
975     this_ -> Log1(this_ -> S, L1_READING_EXT_ENTITY, systemId);    
976     XML_Parser newParser =
977         XML_ExternalEntityParserCreate(parser, context, /* encoding= */ NULL);
978
979     if (!newParser)
980         return 0;
981
982     Str absolute;
983     makeAbsoluteURI(this_ -> S,systemId, base, absolute);
984     XML_SetBase(newParser, absolute); //Christian + PH
985
986     GP(DataLine) newDL = new DataLine;
987     if ( (*newDL).open(this_ -> S, absolute, DLMODE_READ, NULL) )
988       {
989         XML_ParserFree(newParser);
990         return 0;
991       }
992
993     /*
994     if (NZ(this_->S.getProcessor())->addLineNoTree(this_ -> S, newDL, absolute, 
995                                                    t -> XSLTree) || !newDL)
996       {
997         XML_ParserFree(newParser);
998         return 0;
999       }
1000     */
1001
1002     TreeConstructer *newTC;
1003     MT( this_, this_ -> S, newTC = new TreeConstructer(this_ -> S));
1004
1005     // record subtree information for the external entity
1006     // XSL_NONE stands for 'external entity'
1007     eFlag code = t -> startSubtree(this_ -> S, absolute, XSL_NONE, TRUE);
1008     if (!code)
1009     {
1010         code = newTC -> parseDataLineUsingGivenExpat(this_ -> S, t, newDL, newParser);
1011         t -> endSubtree(this_ -> S, XSL_NONE); 
1012     }
1013     (*newDL).close(this_ -> S);
1014     XML_ParserFree(newParser);
1015     delete newTC;
1016     return code ? 0 : 1;
1017 }
1018
1019 void TreeConstructer::tcEntityDecl(void *userData, const char *entityName,
1020                                    int is_parameter_entity, const char *value,
1021                                    int value_length, const char *base,
1022                                    const char *systemId, const char *publicId,
1023                                    const char *notationName)
1024 {
1025   TreeConstructer *this_ = (TreeConstructer*) userData;
1026   if (notationName)
1027     {
1028       Str name = entityName;
1029       Str absolute;
1030       makeAbsoluteURI(this_ -> S, systemId, base, absolute);
1031       this_ -> theTree -> setUnparsedEntityUri( name, absolute );
1032     }
1033 }
1034
1035 /* methods for internal sax handler */
1036 void TreeConstructer::saxStartDocument(void* userData, 
1037                                        SablotHandle processor_)
1038 {
1039   tcStartDocument(userData);
1040 }
1041
1042 void TreeConstructer::saxStartElement(void *constructer,
1043                                       SablotHandle processor_,
1044                                       const char *elName, const char **atts)
1045 {
1046   tcStartElement(constructer, elName, atts);
1047 }
1048  
1049 void TreeConstructer::saxEndElement(void* constructer, 
1050                                     SablotHandle processor_, 
1051                                     const char* name)
1052 {
1053   tcEndElement(constructer, name);
1054 }
1055
1056 void TreeConstructer::saxStartNamespace(void* userData, 
1057                                         SablotHandle processor_,
1058                                         const char* prefix, const char* uri)
1059 {
1060   tcStartNamespace(userData, prefix, uri);
1061 }
1062
1063 void TreeConstructer::saxStartNamespace2(void* userData, 
1064                                          SablotHandle processor_,
1065                                          const char* prefix, const char* uri,
1066                                          Bool hidden)
1067 {
1068   tcStartNamespace2(userData, prefix, uri, hidden);
1069 }
1070
1071 void TreeConstructer::saxEndNamespace(void* constructer, 
1072                                       SablotHandle processor_, 
1073                                       const char* prefix)
1074 {
1075   tcEndNamespace(constructer, prefix);
1076 }
1077
1078 void TreeConstructer::saxComment(void* constructer, 
1079                                  SablotHandle processor_, 
1080                                  const char* contents)
1081 {
1082   tcComment(constructer, contents);
1083 }
1084
1085 void TreeConstructer::saxPI(void* constructer, 
1086                             SablotHandle processor_,
1087                             const char* target, const char* contents)
1088 {
1089   tcPI(constructer, target, contents);
1090 }
1091
1092 void TreeConstructer::saxCharacters(void* constructer, 
1093                                     SablotHandle processor_,
1094                                     const char* contents, int length)
1095 {
1096   tcCharacters(constructer, contents, length);
1097 }
1098
1099 void TreeConstructer::saxEndDocument(void* constructer, 
1100                                      SablotHandle processor_)
1101 {
1102   tcEndDocument(constructer);
1103 }
1104
1105 /* static MUST NOT RELY ON EXPAT_SUPPORTS_TRIPLETS*/
1106 eFlag TreeConstructer::setQNameFromExpat(Sit S, TreeConstructer* this_, QName& qname_, const char* text)
1107 {
1108     Tree *t = this_ -> theTree;
1109     char *p = (char*) text,
1110         *q = strchr(p, THE_NAMESPACE_SEPARATOR);
1111     if (q)
1112     {
1113         *q = 0;
1114
1115         qname_.setUri(t -> unexpand(p));
1116         *q = NS_SEP;
1117         
1118         p = q + 1;
1119         q = strchr(p, THE_NAMESPACE_SEPARATOR);
1120         if (q) *q = 0;
1121
1122         qname_.setLocal(t -> unexpand(p));
1123         if (strchr(p,':'))
1124         {
1125             DStr msg = "{";
1126             msg += t -> expand(qname_.getUri());
1127             msg += "}:";
1128             msg += t -> expand(qname_.getLocal());
1129             Err1T(this_, S, E1_EXTRA_COLON, (char *)msg);
1130         }
1131         //read the prefix - should append only if XML_SetReturnNSTriplet
1132         //works
1133         if (q)
1134           {
1135             *q = NS_SEP;
1136             qname_.setPrefix(t -> unexpand(q + 1));
1137           }
1138     }
1139     else
1140     {
1141         qname_.uri = UNDEF_PHRASE;
1142         qname_.setLocal(t -> unexpand(p));
1143         char *isColon;
1144         qname_.prefix = UNDEF_PHRASE;
1145         if (!!(isColon = strchr(p,':')))
1146         {
1147             *isColon = 0;
1148
1149             // fixing what appears a bug in expat 
1150             //- sometimes the xml:lang attr arrives unexpanded
1151             // apparently only in XSL and when it's not at the top level
1152             if (!strEqNoCase(p,"xml"))
1153                 Err1T(this_, S, ET_BAD_PREFIX,p)
1154             else
1155             {
1156                 qname_.setLocal(t -> unexpand(isColon + 1));
1157                 qname_.setUri(t -> stdPhrase(PHRASE_XML_NAMESPACE));
1158                         qname_.setPrefix(t -> unexpand((char*)"xml"));
1159                 // E( t -> dict().insert(S, "xml",qname_.getPrefix) );                
1160             }
1161         }
1162     };
1163     return OK;
1164 }
1165
1166 void TreeConstructer::report(Sit S, MsgType type, MsgCode code, 
1167     const Str& arg1, const Str& arg2) const 
1168 {
1169     if (theDataLine)
1170         S.setCurrFile(theDataLine -> fullUri);
1171         S.setCurrLine(getCurrentLineNumber());
1172     S.message(type, code, arg1, arg2);
1173 };
1174
1175