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): Marc Lehmann <pcg@goof.com>
19  *
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable
23  * instead of those above.  If you wish to allow use of your
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32 
33 //
34 //  output.cpp
35 //
36 
37 #include "output.h"
38 #include "uri.h"
39 #include "proc.h"
40 
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44 
45 #ifdef SABLOT_DEBUGGER
46 #include "debugger.h"
47 #endif
48 
49 #include "guard.h"
50 
51 // GP: clean
52 
53 #define NONEMPTY_ELEMENT FALSE
54 #define EMPTY_ELEMENT TRUE
55 
56 
57 enum OutputterFlags
58 {
59     HTML_ELEMENT = 1,
60     HTML_SCRIPT_OR_STYLE = 2,
61     CDATA_SECTION = 4
62 };
63 
64 #define IF_SAX1( FUNC )\
65     { if (mySAXHandler)\
66         { mySAXHandler -> FUNC(mySAXUserData, S.getProcessor()); }}
67 #define IF_SAX2( FUNC, ARG1 )\
68     { if (mySAXHandler)\
69         { mySAXHandler -> FUNC(mySAXUserData, S.getProcessor(), (ARG1)); }}
70 #define IF_SAX3( FUNC, ARG1, ARG2 )\
71     { if (mySAXHandler)\
72         { mySAXHandler -> FUNC(mySAXUserData, S.getProcessor(), (ARG1), (ARG2)); }}
73 
74 //macros on internal handler
75 #define IF_INT_SAX4( FUNC, ARG1, ARG2, ARG3 )\
76     { if (mySAXHandler)\
77         { ((SAXHandlerInternal*)mySAXHandler) -> FUNC(mySAXUserData, S.getProcessor(), (ARG1), (ARG2), (ARG3)); }}
78 
79 #define IF_PH1( FUNC )\
80     { if (physical)\
81         { physical -> FUNC(S); }}
82 #define IF_PH2( FUNC, ARG1)\
83     { if (physical)\
84         { physical -> FUNC(S, ARG1); }}
85 #define IF_PH3( FUNC, ARG1, ARG2 )\
86     { if (physical)\
87         { physical -> FUNC(S, (ARG1), (ARG2)); }}
88 
89 // STRING_ITEMS_COUNT (output.h) must be in sync with the size
90 // of the following table:
91 
92 XSL_ATT outputStringAtts[STRING_ITEMS_COUNT + 1] = {
93     XSLA_VERSION, XSLA_ENCODING, XSLA_OMIT_XML_DECL, XSLA_STANDALONE,
94     XSLA_DOCTYPE_PUBLIC, XSLA_DOCTYPE_SYSTEM, XSLA_INDENT, XSLA_MEDIA_TYPE,
95     XSLA_NONE
96 };
97 
98 const char* theEmptyHTML40Tags[] =
99 {
100     "area", "base", "basefont", "br", "col", "frame", "hr", "img",
101     "input", "isindex", "link", "meta", "param", NULL
102 };
103 
104 const char* theURI_HTMLAtts[] =
105 {
106     "action",       // FORM
107     "archive",      // OBJECT
108     "background",   // BODY
109     "cite",         // BLOCKQUOTE, Q, DEL, INS
110     "classid",      // OBJECT
111     "codebase",     // OBJECT, APPLET
112     "data",         // OBJECT
113     "href",         // A, AREA, LINK, BASE
114     "longdesc",     // IMG, FRAME, IFRAME
115     "profile",      // HEAD
116     "src",          // SCRIPT, INPUT, FRAME, IFRAME, IMG
117     "usemap",       // IMG, INPUT, OBJECT
118     NULL
119 };
120 
121 const char* theHTMLBooleanAtts[] =
122 {
123   "checked",
124   "compact",
125   "declare",
126   "defer",
127   "disabled",
128   "ismap",
129   "multiple",
130   "nohref",
131   "noresize",
132   "noshade",
133   "nowrap",
134   "readonly",
135   "selected",
136   NULL
137 };
138 
139 const char* theHTMLNoEscapeTags[] =
140 {
141   "script",
142   "style",
143   NULL
144 };
145 
146 // tags new lines should not be inserted after by indent
147 const char* theNoEolHTMLTags[] =
148 {
149     "img", "span", NULL
150 };
151 
isEmptyHTMLTag(const Str & name)152 Bool isEmptyHTMLTag(const Str& name)
153 {
154     int ndx = lookupNoCase(name, theEmptyHTML40Tags);
155     // return TRUE iff found
156     return !!theEmptyHTML40Tags[ndx];
157 }
158 
isHTMLNoEscapeTag(const Str & name)159 Bool isHTMLNoEscapeTag(const Str& name)
160 {
161     int ndx = lookupNoCase(name, theHTMLNoEscapeTags);
162     return !!theHTMLNoEscapeTags[ndx];
163 }
164 
isBooleanHTMLAtt(const Str & name)165 Bool isBooleanHTMLAtt(const Str& name)
166 {
167   int ndx = lookupNoCase(name, theHTMLBooleanAtts);
168  return !!theHTMLBooleanAtts[ndx];
169 }
170 
171 //  this should be improved by checking the name of the parent element
172 //  see the element names in theURI_HTMLAtts
isURI_HTMLAtt(const Str & name)173 Bool isURI_HTMLAtt(const Str& name)
174 {
175     int ndx = lookupNoCase(name, theURI_HTMLAtts);
176     // return TRUE iff found
177     return !!theURI_HTMLAtts[ndx];
178 }
179 
isNoEolHTMLTag(const Str & name)180 Bool isNoEolHTMLTag(const Str& name)
181 {
182     int ndx = lookupNoCase(name, theNoEolHTMLTags);
183     // return TRUE iff found
184     return !!theNoEolHTMLTags[ndx];
185 }
186 
187 //
188 //  StrPrec and EQNamePrec implementation
189 //
190 
191 
192 // returns -1 if oldPrec wins, +1 if newPrec wins, 0 if equal (usually error)
cmpPrecedences(int oldPrec,int newPrec)193 int cmpPrecedences(int oldPrec, int newPrec)
194 {
195     if (oldPrec == OUTPUT_PRECEDENCE_UNSPECIFIED ||
196 	newPrec == OUTPUT_PRECEDENCE_STRONGEST ||
197 	newPrec >= 0 && newPrec < oldPrec)
198 	return 1;
199     if (newPrec >= 0 && oldPrec == newPrec)
200 	return 0;
201     return -1;
202 }
203 
set(const Str & newString,int newPrecedence)204 Bool StrPrec::set(const Str& newString, int newPrecedence)
205 {
206     int cmp = cmpPrecedences(precedence, newPrecedence);
207     // if new wins or there's a draw, set the value
208     if (cmp >= 0)
209     {
210 	string = newString;
211 	precedence = newPrecedence;
212     };
213     // if cmp == 0, return TRUE
214     return cmp ? FALSE : TRUE;
215 }
216 
set(const EQName & newName,int newPrecedence)217 Bool EQNamePrec::set(const EQName& newName, int newPrecedence)
218 {
219     int cmp = cmpPrecedences(precedence, newPrecedence);
220     // if new wins or there's a draw, set the value
221     if (cmp >= 0)
222     {
223 	name = newName;
224 	precedence = newPrecedence;
225     };
226     // if cmp == 0, return TRUE
227     return cmp ? FALSE : TRUE;
228 }
229 
230 //
231 //  OutputDefinition
232 //
233 
checkYesNo(const Str & what)234 Bool checkYesNo(const Str& what)
235 {
236     return(what == (const char*) "yes" || what == (const char*) "no");
237 }
238 
OutputDefinition()239 OutputDefinition::OutputDefinition()
240 : method()
241 {
242 }
243 
~OutputDefinition()244 OutputDefinition::~OutputDefinition()
245 {
246     cdataElems.freeall(FALSE);
247 }
248 
lookupAttCode(XSL_ATT * table,XSL_ATT what)249 int lookupAttCode(XSL_ATT* table, XSL_ATT what)
250 {
251     int i;
252     for (i = 0; table[i] != XSLA_NONE && table[i] != what; i++) {};
253     return (table[i] == XSLA_NONE ? -1 : i);
254 }
255 
setItemStr(Sit S,XSL_ATT itemId,const Str & value,Vertex * caller,int precedence)256 eFlag OutputDefinition::setItemStr(Sit S, XSL_ATT itemId, const Str& value, Vertex *caller, int precedence)
257 {
258     if (caller)
259 	precedence = caller -> getImportPrecedence();
260     switch(itemId)
261     {
262     case XSLA_OMIT_XML_DECL:
263     case XSLA_STANDALONE:
264     case XSLA_INDENT:
265     {
266 	if (!checkYesNo(value))
267 	{
268 	    S.setCurrVDoc(caller);
269 	    Err1(S, E1_ATTR_YES_NO, xslAttNames[itemId]);
270 	}
271     }; break;
272     };
273     int index = lookupAttCode(outputStringAtts, itemId);
274     sabassert(index >= 0);
275     if (stringItems[index].set(value, precedence))
276     {
277 	S.setCurrVDoc(caller);
278 	Warn1(S, W1_OUTPUT_ATTR, xslAttNames[itemId]);
279     }
280     return OK;
281 }
282 
setItemEQName(Sit S,XSL_ATT itemId,const EQName & value,Vertex * caller,int precedence)283 eFlag OutputDefinition::setItemEQName(Sit S, XSL_ATT itemId, const EQName& value, Vertex *caller, int precedence)
284 {
285     if (caller)
286 	precedence = caller -> getImportPrecedence();
287     switch(itemId)
288     {
289     case XSLA_CDATA_SECT_ELEMS:
290         cdataElems.append(new EQName(value)); break;
291     default:
292     {
293         sabassert(itemId == XSLA_METHOD);
294 	if (method.set(value, precedence))
295 	{
296 	    S.setCurrVDoc(caller);
297 	    Warn1(S, W1_OUTPUT_ATTR, xslAttNames[itemId]);
298 	}
299     }
300     }
301     return OK;
302 }
303 
getValueStr(XSL_ATT itemId) const304 const Str& OutputDefinition::getValueStr(XSL_ATT itemId) const
305 {
306     int index = lookupAttCode(outputStringAtts, itemId);
307     sabassert(index >= 0);
308     return stringItems[index].get();
309 }
310 
getValueEQName(XSL_ATT itemId) const311 const EQName& OutputDefinition::getValueEQName(XSL_ATT itemId) const
312 {
313     sabassert(itemId == XSLA_METHOD);
314     return method.get();
315 };
316 
askEQNameList(XSL_ATT itemId,const EQName & what) const317 Bool OutputDefinition::askEQNameList(XSL_ATT itemId, const EQName &what) const
318 {
319     sabassert(itemId == XSLA_CDATA_SECT_ELEMS);
320     return (cdataElems.find(what) != NULL);
321 }
322 
getMethod() const323 OutputMethod OutputDefinition::getMethod() const
324 {
325     const Str& method_ = getValueEQName(XSLA_METHOD).getLocal();
326     if (method_ == (const char*) "html")
327         return OUTPUT_HTML;
328     else if (method_ == (const char*) "text")
329         return OUTPUT_TEXT;
330     else if (method_ == (const char*) "xml")
331         return OUTPUT_XML;
332     else if (method_ == (const char*) "xhtml")
333         return OUTPUT_XHTML;
334     else return OUTPUT_UNKNOWN;
335 }
336 
getEncoding() const337 const Str& OutputDefinition::getEncoding() const
338 {
339     return getValueStr(XSLA_ENCODING);
340 }
341 
getIndent() const342 Bool OutputDefinition::getIndent() const
343 {
344     const Str& indent_ = getValueStr(XSLA_INDENT);
345     return (indent_ == (char*)"yes");
346 }
347 
setDefaults(Sit S)348 eFlag OutputDefinition::setDefaults(Sit S)
349 {
350     OutputMethod meth = getMethod();
351     sabassert( meth != OUTPUT_UNKNOWN );
352     char strYes[] = "yes", strNo[] = "no";
353     E( setItemStr(S, XSLA_ENCODING, "UTF-8", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
354     switch(meth)
355     {
356     case OUTPUT_XML:
357         {
358             E( setItemStr(S, XSLA_VERSION, "1.0", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
359             E( setItemStr(S, XSLA_INDENT, strNo, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
360             E( setItemStr(S, XSLA_MEDIA_TYPE, "text/xml", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
361             E( setItemStr(S, XSLA_OMIT_XML_DECL, strNo, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
362         }; break;
363     case OUTPUT_HTML:
364         {
365             E( setItemStr(S, XSLA_VERSION, "4.0", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
366             E( setItemStr(S, XSLA_INDENT, strYes, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
367             E( setItemStr(S, XSLA_MEDIA_TYPE, "text/html", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
368             E( setItemStr(S, XSLA_OMIT_XML_DECL, strYes, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
369         }; break;
370     case OUTPUT_TEXT:
371         {
372             E( setItemStr(S, XSLA_INDENT, strNo, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
373             E( setItemStr(S, XSLA_MEDIA_TYPE, "text/plain", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
374             E( setItemStr(S, XSLA_OMIT_XML_DECL, strYes, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
375         }; break;
376     case OUTPUT_XHTML:
377         {
378             E( setItemStr(S, XSLA_VERSION, "1.0", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
379             E( setItemStr(S, XSLA_INDENT, strYes, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
380             E( setItemStr(S, XSLA_MEDIA_TYPE, "text/html", NULL, OUTPUT_PRECEDENCE_WEAKEST) );
381             E( setItemStr(S, XSLA_OMIT_XML_DECL, strYes, NULL, OUTPUT_PRECEDENCE_WEAKEST) );
382         }; break;
383     }
384     return OK;
385 }
386 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)387 void OutputDefinition::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
388 {
389     S.message(type, code, arg1, arg2);
390 }
391 
392 
393 
394 //
395 //
396 //  PhysicalOutputLayerObj
397 //
398 //
399 
400 #define sendStrEsc(SIT, STRING,ESCAPING) sendOut(SIT, (STRING), (STRING.length()), (ESCAPING))
401 #define sendStr(SIT, STRING)     sendStrEsc(SIT, (STRING), ESCAPING_NONE)
402 #define sendLit(SIT, LITERAL)    sendOut(SIT, (LITERAL), sizeof(LITERAL) - 1, ESCAPING_NONE)
403 // S is the situation (existing in each context indentEOL is called in)
404 #define indentEOL() {sendLit(S, "\n");}
405 #define indentSpace() {for (int i__ = 0; i__ < level; i__++) sendLit(S, "  ");}
406 #define indentFull() {if (indent && after_markup) {indentEOL(); indentSpace();}}
407 #define ignoreTextMethod() {if (method == OUTPUT_TEXT) return OK; }
408 
PhysicalOutputLayerObj(CDesc encodingCD_)409 PhysicalOutputLayerObj::PhysicalOutputLayerObj(CDesc encodingCD_)
410 {
411     curr = 0;
412     encodingCD = encodingCD_;
413     indent = FALSE;
414     after_markup = FALSE;  //pc
415     level = 0;  //pc
416     defaultNSWas = false;
417 }
418 
~PhysicalOutputLayerObj()419 PhysicalOutputLayerObj::~PhysicalOutputLayerObj()
420 {
421 }
422 
setOptions(Sit S,DataLine * targetDataLine_,OutputDefinition * outDef_)423 eFlag PhysicalOutputLayerObj::setOptions(Sit S,
424     DataLine *targetDataLine_, OutputDefinition *outDef_)
425 {
426     targetDataLine = targetDataLine_;
427     outDef = outDef_;
428     method = outDef -> getMethod();
429     indent = outDef -> getIndent();
430     //enc = outDef -> getEncoding();
431     encoding = outDef -> getEncoding();
432     return OK;
433 }
434 
outputTrailingNewline(Sit S)435 eFlag PhysicalOutputLayerObj::outputTrailingNewline (Sit S)
436 {
437   switch (method) {
438   case OUTPUT_HTML:
439   case OUTPUT_XML:
440   case OUTPUT_XHTML:
441     indentEOL();
442     break;
443   }
444   return OK;
445 }
446 
outputDone(Sit S)447 eFlag PhysicalOutputLayerObj::outputDone(Sit S)
448 {
449   E( flushBuffer(S) );
450   return OK;
451 }
452 
_localName(Str fullname)453 Str _localName(Str fullname)
454 {
455   char *full = (char*)fullname;
456   char *colon = strchr(fullname, ':');
457   if (colon)
458     return colon + 1;
459   else
460     return full;
461 }
462 
outputElementStart(Sit S,const Str & name,const NamespaceStack & namespaces,const int namespace_index,const StrStrList & atts,Bool isEmpty)463 eFlag PhysicalOutputLayerObj::outputElementStart(Sit S,
464     const Str& name,
465     const NamespaceStack& namespaces, const int namespace_index,
466     const StrStrList& atts,
467     Bool isEmpty)
468 {
469   //exit for text output method!!!
470   ignoreTextMethod();
471 
472     // begin output of start tag: output element name
473     if (!isNoEolHTMLTag(name) || (method != OUTPUT_HTML && method != OUTPUT_XHTML))
474       indentFull();
475 
476     sendLit(S, "<");
477     E( sendStr(S, name) );
478 
479     // output namespace declarations
480 
481     int i;
482     const Str* prefix;
483     for (i = namespace_index; i < namespaces.number(); i++)
484     {
485       NamespaceStackObj * nm = namespaces[i];
486       prefix = &(nm -> prefix);
487       //prefix = &(namespaces[i] -> prefix);
488       //if (!namespaces.isHidden(*prefix))
489 
490       //swallow hidden namespaces as well as the empty default
491       //namespace, if no default namespace was output recently
492       if (! nm -> hidden &&
493 	  (!(prefix -> isEmpty()) || !(nm -> uri.isEmpty()) || defaultNSWas))
494 	{
495 	  defaultNSWas = defaultNSWas || prefix -> isEmpty();
496 
497           sendLit(S, " xmlns");
498           if (!prefix -> isEmpty())
499           {
500              sendLit(S, ":");
501              E( sendStr(S, *prefix) );
502           }
503           sendLit(S, "=\"");
504           E( sendStrEsc(S, nm -> uri,
505                         method == OUTPUT_HTML || method == OUTPUT_XHTML ?
506                         ESCAPING_HTML_URI : ESCAPING_URI) );
507           sendLit(S, "\"");
508        };
509     };
510 
511     // output attributes
512 
513     for (i = 0; i < atts.number(); i++)
514     {
515         sendLit(S, " ");
516 	/*
517         const EQName& attQName = atts[i] -> key;
518         if (attQName.hasPrefix())
519         {
520             E( sendStr(S, attQName.getPrefix()) );
521             sendLit(S, ":");
522         };
523         const Str& localAttName = atts[i] -> key.getLocal();
524         E( sendStr(S, localAttName) );
525 	*/
526 	sendOut(S, (char*)atts[i] -> key, atts[i] -> key.length(),
527 		ESCAPING_NONE);
528 
529 	//boolean atts for html
530 	if (method == OUTPUT_HTML && isBooleanHTMLAtt(atts[i]->key))
531 	    continue;
532 
533         sendLit(S, "=\"");
534 
535 	/*
536         EscMode escapingMode =
537             ((method == OUTPUT_HTML || method == OUTPUT_XHTML) ?
538 	     ESCAPING_HTML_ATTR : ESCAPING_ATTR);
539         if ((method == OUTPUT_HTML || method == OUTPUT_XHTML) &&
540 	    isURI_HTMLAtt(_localName(atts[i]->key)))
541 	  {
542 	    escapingMode = ESCAPING_HTML_URI;
543 	  }
544 	*/
545 	EscMode escapingMode = ESCAPING_ATTR;
546 	if (method == OUTPUT_HTML || method == OUTPUT_XHTML)
547 	  {
548 	    if ( strchr(name, ':') )
549 	      {
550 		escapingMode = ESCAPING_ATTR;
551 	      }
552 	    else if ( isURI_HTMLAtt(_localName(atts[i]->key)) )
553 	      {
554 		escapingMode = ESCAPING_HTML_URI;
555 	      }
556 	    else
557 	      {
558 		if (method == OUTPUT_HTML)
559 		  escapingMode = ESCAPING_HTML_ATTR;
560 	      }
561 	  }
562 
563         E( sendStrEsc(S, atts[i] -> value, escapingMode));
564         sendLit(S, "\"");
565     };
566 
567     // close the tag
568 
569     after_markup = TRUE;  //pc
570 
571     if (!isEmpty)
572     {
573       sendLit(S, ">");
574       level++;  //pc
575     }
576     else
577     {
578         if (method == OUTPUT_HTML || method == OUTPUT_XHTML)
579 	{
580             if (!isEmptyHTMLTag(name))
581             {
582                 sendLit(S, "></");
583                 sendStr(S, name);
584                 sendLit(S, ">");
585             }
586             else if (method == OUTPUT_HTML)
587                 sendLit(S, ">");
588             else
589                 sendLit(S, " />");
590 
591 	    if (isNoEolHTMLTag(name))
592 	        after_markup = FALSE;
593         }
594         else
595 	    sendLit(S, "/>");
596     };
597     return OK;
598 }
599 
600 
601 
outputElementEnd(Sit S,const Str & name,Bool isEmpty)602 eFlag PhysicalOutputLayerObj::outputElementEnd(Sit S,
603     const Str& name, Bool isEmpty)
604 {
605   //exit for text output method!!!
606   ignoreTextMethod();
607 
608     if (!isEmpty)
609     {
610 	level--;  //pc
611         indentFull();
612         sendLit(S, "</");
613         E( sendStr(S, name) );
614         sendLit(S, ">");
615 	if (!isNoEolHTMLTag(name)) after_markup = TRUE;  //pc
616     };
617     return OK;
618 }
619 
620 
outputComment(Sit S,const Str & contents)621 eFlag PhysicalOutputLayerObj::outputComment(Sit S, const Str& contents)
622 {
623   //exit for text output method!!!
624   ignoreTextMethod();
625 
626     indentFull();
627     sendLit(S, "<!--");
628     const char *p = contents, *p_was = p;
629     int len = contents.length();
630     Bool trailingHyphen = len ? (contents[len - 1] == '-') : FALSE;
631     while (*p)
632     {
633         E( sendOutUntil(S, p, len - (p - p_was), ESCAPING_NONE, "--") );
634         if (*p)
635         {
636             sendLit(S, "- ");
637             p++;
638         }
639     };
640     if (trailingHyphen)
641         sendLit(S, " ");
642     sendLit(S, "-->");
643     after_markup = TRUE;  //pc
644     return OK;
645 }
646 
647 
outputCDataSection(Sit S,const Str & contents)648 eFlag PhysicalOutputLayerObj::outputCDataSection(Sit S, const Str& contents)
649 {
650   switch (method) {
651   case OUTPUT_TEXT:
652     {
653       sendLit(S, contents);
654     }; break;
655   default:
656     {
657       const char *p = contents, *p_was = p;
658       if (!*p)
659         return OK;
660       indentFull();
661       sendLit(S, "<![CDATA[");
662       while (*p)
663 	{
664 	  E( sendOutUntil(S, p,
665 			  contents.length() -(int)(p - p_was),
666 			  ESCAPING_NONE, "]]>") );
667 	  if (*p)
668 	    {
669 	      sendLit(S, "]]]]><![CDATA[>");
670 	      p += 3;
671 	    }
672 	};
673       sendLit(S, "]]>");
674       after_markup = TRUE;  //pc
675     }
676   }
677   return OK;
678 }
679 
outputPI(Sit S,const Str & target,const Str & data)680 eFlag PhysicalOutputLayerObj::outputPI(Sit S, const Str& target, const Str& data)
681 {
682   //exit for text output method!!!
683   ignoreTextMethod();
684 
685     indentFull();
686     sendLit(S, "<?");
687     E( sendStr(S, target) );
688     sendLit(S, " ");
689     E( sendStr(S, data) );
690     if (method == OUTPUT_HTML && !(target == (const char*)"xml"))
691         sendLit(S, ">");
692     else
693         sendLit(S, "?>");
694     after_markup = TRUE;  //pc
695     return OK;
696 }
697 
outputDTD(Sit S,const Str & name,const Str & publicId,const Str & systemId)698 eFlag PhysicalOutputLayerObj::outputDTD(Sit S,
699     const Str& name, const Str& publicId, const Str& systemId)
700 {
701   //exit for text output method!!!
702   ignoreTextMethod();
703 
704     indentFull();
705     sendLit(S, "<!DOCTYPE ");
706     switch(method)
707     {
708     case OUTPUT_XML:
709     case OUTPUT_XHTML:
710         {
711             E( sendStr(S, name) );
712             if (!systemId.isEmpty())
713             {
714                 if (!publicId.isEmpty())
715                 {
716                     sendLit(S, " PUBLIC \"");
717                     E( sendStrEsc(S, publicId, ESCAPING_NONE) );
718                     sendLit(S, "\"");
719                 }
720                 else
721                     sendLit(S, " SYSTEM");
722                 sendLit(S, " \"");
723                 E( sendStrEsc(S, systemId, ESCAPING_URI) );
724                 sendLit(S, "\"");
725             }
726         }; break;
727     case OUTPUT_HTML:
728         {
729             sendLit(S, "html");
730             if (!publicId.isEmpty())
731             {
732                 sendLit(S, " PUBLIC \"");
733                 E( sendStrEsc(S, publicId, ESCAPING_NONE) );
734                 sendLit(S, "\"");
735             }
736             if (!systemId.isEmpty())
737             {
738                 if (publicId.isEmpty())
739                     sendLit(S, " SYSTEM");
740                 sendLit(S, " \"");
741                 E( sendStrEsc(S, systemId, ESCAPING_URI) );
742                 sendLit(S, "\"");
743             };
744         }; break;
745     };
746     if (indent)
747         sendLit(S, ">");
748 	else
749         sendLit(S, ">\xa");
750     after_markup = TRUE;  //pc
751     return OK;
752 }
753 
outputText(Sit S,const Str & contents,Bool disableEsc,Bool inHTMLSpecial)754 eFlag PhysicalOutputLayerObj::outputText(Sit S,
755     const Str& contents, Bool disableEsc,
756     Bool inHTMLSpecial)
757 {
758     switch(method)
759     {
760     case OUTPUT_XML:
761     case OUTPUT_XHTML:
762         {
763             E( sendStrEsc(S, contents, (disableEsc || inHTMLSpecial) ? ESCAPING_NONE : ESCAPING_LT_AMP) );
764         }; break;
765     case OUTPUT_HTML:
766         {
767             E( sendStrEsc(S, contents, (disableEsc || inHTMLSpecial) ? ESCAPING_NONE : ESCAPING_LT_AMP) );
768         }; break;
769     case OUTPUT_TEXT:
770         {
771             E( sendStrEsc(S, contents, ESCAPING_NONE) );
772         }; break;
773     };
774     after_markup = FALSE;  //pc
775     return OK;
776 }
777 
778 
flushBuffer(Sit S)779 eFlag PhysicalOutputLayerObj::flushBuffer(Sit S)
780 {
781     E( targetDataLine -> save(S, buffer, curr) );
782     curr = 0;
783     return OK;
784 }
785 
writeCharacterRef(char * dest,const char * src,EscMode escapeMode)786 int PhysicalOutputLayerObj::writeCharacterRef(char* dest, const char *src, EscMode escapeMode)
787 {
788     char *dest_was = dest;
789     if (escapeMode == ESCAPING_URI || escapeMode == ESCAPING_HTML_URI)
790     {
791         int i, iLimit = utf8SingleCharLength(src);
792         for (i = 0; i < iLimit; i++)
793 	  {
794             dest += sprintf(dest, "%%%02hhx", (unsigned char)src[i]);
795 	  }
796         return (int)(dest - dest_was);
797     }
798     else
799         return sprintf(dest, "&#%lu;", utf8CharCode(src));
800 }
801 
802 // data is assumed null-terminated in the following
803 
sendOutUntil(Sit S,const char * & data,int length,EscMode escapeMode,const char * stoppingText)804 eFlag PhysicalOutputLayerObj::sendOutUntil(Sit S,
805     const char *& data, int length,
806     EscMode escapeMode, const char* stoppingText)
807 {
808     const char *p = strstr(data, stoppingText);
809     int sending = (p ? p - data : length);
810     E( sendOut(S, data, sending, escapeMode) );
811     data += sending;
812     return OK;
813 }
814 
815 
816 
817 #define minimum(a,b) (((a) < (b)) ? (a) : (b))
818 
819 //
820 // sendOut
821 //
822 // This is the place where *all* actual character output and conversion work takes place. The
823 // individual characters are recoded and written into a buffer. When the buffer is full, it is
824 // sent to the appropriate dataline.
825 //
826 
sendOut(Sit S,const char * data,int length,EscMode escapeMode)827 eFlag PhysicalOutputLayerObj::sendOut(Sit S,
828     const char* data, int length,
829     EscMode escapeMode)
830 {
831     int count = 0;
832     size_t srcCharLen, destCharLen;
833     Bool served;
834     char *outbuf;
835     size_t outleft, inleft;
836     EncResult result;
837 
838     while (count < length)
839     {
840         srcCharLen = 1;
841         served = FALSE;
842         switch(*data)
843         {
844         case '<':
845             {
846                 switch(escapeMode)
847                 {
848 /*  will escape < in URIs as &lt; not the %xx way
849                 case ESCAPING_URI:
850                 case ESCAPING_HTML_URI:
851                     {
852                         E( sendOut(smallBuf,
853                             writeCharacterRef(smallBuf, data, escapeMode),
854                             ESCAPING_NONE) );
855                         served = TRUE;
856                     }; break;
857 */
858                 case ESCAPING_URI:
859                 case ESCAPING_HTML_URI:
860                 case ESCAPING_ATTR:
861                 case ESCAPING_LT_AMP:
862                     {
863                         E( sendLit(S, "&lt;") );
864                         served = TRUE;
865                     }; break;
866                 }
867             }; break;
868         case '>':
869             {
870                 switch(escapeMode)
871                 {
872                 case ESCAPING_URI:
873                 case ESCAPING_HTML_URI:
874                 case ESCAPING_ATTR:
875                 case ESCAPING_LT_AMP:
876                     {
877 		      //now we escape &gt; always to prevent bad
878 		      //escaping in cdata sections.
879 		      E( sendLit(S, "&gt;") );
880 		      served = TRUE;
881                     }; break;
882                 }
883             }; break;
884         case '&':
885             {
886                 switch(escapeMode)
887                 {
888 /*  will escape & in URIs as &amp; not the %xx way
889                 case ESCAPING_URI:
890                 case ESCAPING_HTML_URI:
891                     {
892                         E( sendOut(smallBuf,
893                             writeCharacterRef(smallBuf, data, escapeMode),
894                             ESCAPING_NONE) );
895                         served = TRUE;
896                     }; break;
897 */
898                 case ESCAPING_HTML_ATTR:
899                     {
900                         if (data[1] == '{')
901                             break;
902                     }; // no break
903                 case ESCAPING_URI:
904                 case ESCAPING_HTML_URI:
905                 case ESCAPING_ATTR:
906                 case ESCAPING_LT_AMP:
907                     {
908                         E( sendLit(S, "&amp;") );
909                         served = TRUE;
910                     }; break;
911                 }
912             }; break;
913         case '\"':
914             {
915                 switch(escapeMode)
916                 {
917                 case ESCAPING_URI:
918                 case ESCAPING_HTML_URI:
919                     {
920                         E( sendOut(S, smallBuf,
921                             writeCharacterRef(smallBuf, data, escapeMode),
922                             ESCAPING_NONE) );
923                         served = TRUE;
924                     }; break;
925                 case ESCAPING_HTML_ATTR:
926                 case ESCAPING_ATTR:
927                     {
928                         E( sendLit(S, "&quot;") );
929                         served = TRUE;
930                     }; break;
931                 };
932             }; break;
933         case 9:
934         case 10:
935         case 13:
936             {
937                 switch(escapeMode)
938                 {
939                 case ESCAPING_URI:
940                 case ESCAPING_HTML_URI:
941                 case ESCAPING_ATTR:
942                 case ESCAPING_HTML_ATTR:
943                     {
944                         E( sendOut(S, smallBuf,
945                             writeCharacterRef(smallBuf, data, escapeMode),
946                             ESCAPING_NONE) );
947                         served = TRUE;
948                     }; break;
949                 }
950             }; break;
951         case ' ':
952             {
953                 switch(escapeMode)
954                 {
955                 case ESCAPING_URI:
956                 case ESCAPING_HTML_URI:
957                     {
958                         E( sendOut(S, smallBuf,
959                             writeCharacterRef(smallBuf, data, escapeMode),
960                             ESCAPING_NONE) );
961                         served = TRUE;
962                     }; break;
963                 }
964             }; break;
965 	    default:
966 	        {
967 		  // escape non-ASCII values in URIs
968 		  if (*data & 0x80)
969 		    {
970 		      switch(escapeMode)
971 			{
972 			case ESCAPING_URI:
973 			case ESCAPING_HTML_URI:
974 			  {
975                             E( sendOut(S, smallBuf,
976 				       writeCharacterRef(smallBuf, data,
977 							 escapeMode),
978 				       ESCAPING_NONE) );
979                             served = TRUE;
980 			  }; break;
981 			}
982 		    }
983 		}
984         };
985 
986 
987         if (!served)
988         {
989             srcCharLen = utf8SingleCharLength(data);
990             sabassert(srcCharLen > 0);
991             // if encoding differs from utf-8 then recode
992 
993 #ifdef SABLOT_DEBUGGER
994 	    if ( debugger )
995 	      {
996 		debugger -> printOutput(data, srcCharLen);
997 	      }
998 #endif
999 
1000             if (encodingCD == (void*)-1)
1001             {
1002                 memcpy(buffer + curr, data, srcCharLen);
1003                 data += srcCharLen;
1004                 curr += srcCharLen;
1005             }
1006             else
1007             {
1008                 // convert
1009                 outbuf = buffer + curr;
1010                 outleft = OUTPUT_BUFFER_SIZE - curr;
1011                 inleft = srcCharLen;
1012 		        // getProcessor must be non-null here since encodingCD is
1013                 S.recoder().conv(S, encodingCD, data, inleft, outbuf, outleft, result);
1014                 // data is shifted automatically, set curr
1015                 curr = outbuf - buffer;
1016                 // check result, write a character code if
1017 		//couldn't convert (unless ESCAPING_NONE)
1018                 sabassert(result != ENC_EINVAL && result != ENC_E2BIG);
1019                 // FIXME: in NT, must check differently
1020                 if (result == ENC_EILSEQ)
1021                 {
1022                     // unable to convert
1023                     destCharLen = writeCharacterRef(smallBuf, data, escapeMode);
1024                     //if (escapeMode == ESCAPING_NONE)
1025 		    if (method == OUTPUT_TEXT)
1026                         Err1(S, E1_BAD_CHAR_IN_ENC, smallBuf)
1027                     else
1028 		      {
1029                         E( sendOut(S, smallBuf, destCharLen, ESCAPING_NONE) );
1030                         data += srcCharLen;
1031                         served = TRUE;
1032 		      }
1033                 }
1034             }
1035         }   // if (!served)
1036         else
1037         {
1038             data += srcCharLen;
1039         }
1040 
1041         // send the buffer if over a threshold
1042         if (curr > OUTPUT_BUFFER_LIMIT)
1043             flushBuffer(S);
1044 
1045         count += srcCharLen;
1046         // curr already got shifted in all cases
1047 
1048     }       // while
1049     return OK;
1050 }
1051 
1052 
setMethodByDefault(Sit S,OutputMethod method_)1053 eFlag PhysicalOutputLayerObj::setMethodByDefault(Sit S, OutputMethod method_)
1054 {
1055     EQName q;
1056     sabassert(method == OUTPUT_UNKNOWN);
1057     switch( method = method_ )
1058     {
1059     case OUTPUT_XML:
1060         q.setLocal("xml"); break;
1061     case OUTPUT_HTML:
1062         q.setLocal("html"); break;
1063     default:
1064         sabassert(!"PhysicalOutputLayerObj::setMethod()");
1065     }
1066     E( NZ(outDef) -> setItemEQName(S, XSLA_METHOD, q, NULL, OUTPUT_PRECEDENCE_STRONGEST) );
1067     E( outDef -> setDefaults(S) );
1068     return OK;
1069 }
1070 
close(Sit S)1071 eFlag PhysicalOutputLayerObj::close(Sit S)
1072 {
1073   DataLine * dl;
1074   if (dl = getDataLine())
1075     {
1076       E( dl -> close(S) );
1077     }
1078   return OK;
1079 }
1080 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)1081 void PhysicalOutputLayerObj::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
1082 {
1083     S.message(type, code, arg1, arg2);
1084 }
1085 
1086 
1087 
1088 //
1089 //
1090 //      FrontMatter
1091 //
1092 //
1093 
appendConstruct(Sit S,FrontMatterKind kind,const Str & string1,const Str & string2,Bool disableEsc)1094 eFlag FrontMatter::appendConstruct(Sit S,
1095     FrontMatterKind kind, const Str& string1,
1096     const Str& string2, Bool disableEsc)
1097 {
1098     FrontMatterItem* item;
1099 
1100     M( S, item = new FrontMatterItem ); // GP: OK
1101     item -> kind = kind;
1102     item -> string1 = string1;
1103     item -> string2 = string2;
1104     item -> disableEsc = disableEsc;
1105     append(item);
1106     return OK;
1107 };
1108 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)1109 void FrontMatter::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
1110 {
1111     S.message(type, code, arg1, arg2);
1112 }
1113 
1114 //
1115 //
1116 //  OutputDocument
1117 //
1118 //
1119 
~OutputDocument()1120 OutputDocument::~OutputDocument()
1121 {
1122   //we do not delete outputter objects as they are stored with
1123   //Processor
1124   // if (outputter) delete outputter;
1125   if (def) delete def;
1126 }
1127 
finish(Sit S)1128 eFlag OutputDocument::finish(Sit S)
1129 {
1130   if (state == OUTDOC_ACTIVE)
1131     {
1132       E( NZ(outputter) -> eventTrailingNewline(S) );
1133       E( NZ(outputter) -> eventEndOutput(S, true) );
1134       setState(OUTDOC_FINISHED);
1135     }
1136   return OK;
1137 }
1138 
setOutputter(OutputterObj * new_)1139 OutputterObj* OutputDocument::setOutputter(OutputterObj* new_)
1140 {
1141   if (outputter) delete outputter;
1142   return outputter = new_;
1143 }
1144 
1145 //
1146 //
1147 //  OutputterObj
1148 //
1149 //
1150 
1151 
nameForSAX(Sit S,const EQName & q)1152 Str* OutputterObj::nameForSAX(Sit S, const EQName& q)
1153 {
1154   DStr temp;
1155   if (mySAXOutputType == SAXOUTPUT_COPY_TREE ||
1156       mySAXOutputType == SAXOUTPUT_INT_PHYSICAL)
1157     {
1158       if (q.getUri().isEmpty())
1159 	return new Str(q.getLocal());
1160       temp = q.getUri();
1161       temp += THE_NAMESPACE_SEPARATOR;
1162       temp += q.getLocal();
1163       temp += THE_NAMESPACE_SEPARATOR;
1164       temp += q.getPrefix();
1165       return new Str(temp);
1166     }
1167   else
1168     {
1169       Str s;
1170       q.getname(s);
1171       return new Str(s);
1172     }
1173 };
1174 
OutputterObj()1175 OutputterObj::OutputterObj()
1176 {
1177     encodingCD = (CDesc) -1;
1178     outputEscaping = TRUE;
1179     physical = NULL;
1180     outDef = NULL;
1181     mySAXHandler = NULL;
1182     mySAXOutputType = SAXOUTPUT_NONE;
1183     method = OUTPUT_UNKNOWN;
1184     noElementYet = TRUE;
1185     noHeadYet = TRUE;
1186     delayedDTD = FALSE;
1187     // to recognize the first HEAD element
1188 }
1189 
~OutputterObj()1190 OutputterObj::~OutputterObj()
1191 {
1192     history.freeall(FALSE);
1193     front.freeall(FALSE);
1194     currNamespaces.freeall(FALSE);
1195     cdelete(physical);
1196 }
1197 
setOptions(Sit S,DataLine * targetDataLine_,OutputDefinition * outDef_)1198 eFlag OutputterObj::setOptions(Sit S,
1199     DataLine *targetDataLine_, OutputDefinition *outDef_)
1200 {
1201     Str encoding;
1202     outDef = NZ(outDef_);
1203     method = outDef -> getMethod(); //_PH_
1204     if (method != OUTPUT_UNKNOWN)
1205         E( outDef -> setDefaults(S) );
1206 
1207     if (S.getProcessor())
1208       {
1209         encoding = S.getProcessor() -> getHardEncoding();
1210 	if ( !encoding.isEmpty() )
1211 	  outDef -> setItemStr(S, XSLA_ENCODING, encoding, NULL,
1212 			       OUTPUT_PRECEDENCE_STRONGEST);
1213       }
1214     else
1215 	encoding.empty();
1216     if (encoding.isEmpty())
1217         encoding = outDef -> getValueStr(XSLA_ENCODING);
1218     if (!encoding.isEmpty() && !encoding.eqNoCase("utf-8"))
1219     {
1220         // set the conversion descriptor
1221 	if (S.getProcessor())
1222 	{
1223             E( S.recoder().openFromUTF8(S,
1224 					encoding, encodingCD) );
1225 	}
1226 	else
1227 	    encodingCD = (ConvInfo*)-1;
1228         if (encodingCD == (void*)-1)
1229         {
1230             Warn1(S, W1_UNSUPP_OUT_ENCODING, encoding);
1231             encoding = "UTF-8";
1232             E( outDef -> setItemStr(S, XSLA_ENCODING, encoding,
1233 				    NULL, OUTPUT_PRECEDENCE_STRONGEST) );
1234         }
1235     }
1236     else
1237 	if (!encoding.isEmpty())
1238 	    E( outDef -> setItemStr(S, XSLA_ENCODING, encoding,
1239 				    NULL, OUTPUT_PRECEDENCE_WEAKEST) );
1240 
1241     if (targetDataLine_)
1242     {
1243         M( S, physical = new PhysicalOutputLayerObj(encodingCD) );
1244         // GP: OK, OutputterObj gets disposed of in cleanupAfterRun
1245         E( physical -> setOptions(S, targetDataLine_, outDef_) );
1246     };
1247 
1248     return OK;
1249 }
1250 
setOptionsSAX(Sit S,SAXHandler * streaming_,void * userData_,SAXOutputType saxout_)1251 eFlag OutputterObj::setOptionsSAX(Sit S,
1252     SAXHandler *streaming_, void* userData_, SAXOutputType saxout_)
1253 {
1254     mySAXHandler = streaming_;
1255     mySAXUserData = userData_;
1256     mySAXOutputType = saxout_;
1257     return OK;
1258 }
1259 
reportXMLDeclIfMust(Sit S)1260 eFlag OutputterObj::reportXMLDeclIfMust(Sit S)
1261 {
1262     if (!physical || method == OUTPUT_UNKNOWN ||
1263         outDef -> getValueStr(XSLA_OMIT_XML_DECL) == (const char*)"yes")
1264         return OK;
1265     DStr declText = "version=\"";
1266     declText += outDef -> getValueStr(XSLA_VERSION);
1267     declText += "\" encoding=\"";
1268     declText += outDef -> getValueStr(XSLA_ENCODING);
1269     declText += '\"';
1270     const Str &standaloneText = outDef -> getValueStr(XSLA_STANDALONE);
1271     if (!standaloneText.isEmpty())
1272     {
1273         declText += " standalone=\"";
1274         declText += standaloneText;
1275         declText += '\"';
1276     };
1277     E( physical -> outputPI(S, Str("xml"), declText) );
1278     return OK;
1279 }
1280 
reportDTDIfMust(Sit S,const EQName & docElementName)1281 eFlag OutputterObj::reportDTDIfMust(Sit S, const EQName& docElementName)
1282 // to be called only after the output method is determined
1283 {
1284     sabassert(method != OUTPUT_TEXT);
1285     if (!physical)
1286         return OK;
1287     const Str&
1288         DTSystem = outDef -> getValueStr(XSLA_DOCTYPE_SYSTEM),
1289         DTPublic = outDef -> getValueStr(XSLA_DOCTYPE_PUBLIC);
1290     Bool writeDTD;
1291     switch(method)
1292     {
1293     case OUTPUT_XML:
1294     case OUTPUT_XHTML:
1295         writeDTD = !DTSystem.isEmpty();
1296         break;
1297     case OUTPUT_HTML:
1298         writeDTD = !DTSystem.isEmpty() || !DTPublic.isEmpty();
1299         break;
1300     default:
1301         writeDTD = FALSE;
1302     }
1303 
1304     delayedDTD = writeDTD;
1305 
1306     /*
1307     if (writeDTD)
1308     {
1309       Str fullName;
1310           docElementName.getname(fullName);
1311 
1312     };
1313     */
1314     return OK;
1315 }
1316 
1317 
reportFront(Sit S)1318 eFlag OutputterObj::reportFront(Sit S)
1319 {
1320     sabassert(method != OUTPUT_UNKNOWN);
1321     int i, frontCount = front.number();
1322     FrontMatterItem *item;
1323     for(i = 0; i < frontCount; i++)
1324     {
1325         item = front[i];
1326         switch(item -> kind)
1327         {
1328         case FM_TEXT:
1329             {
1330                 if (item -> disableEsc)
1331                     E( eventDisableEscapingForNext(S) );
1332                 E( eventData(S, item -> string1) );
1333             }; break;
1334         case FM_PI:
1335             {
1336                 E( eventPIStart(S, item -> string1) );
1337                 E( eventData(S, item -> string2) );
1338                 E( eventPIEnd(S) );
1339             }; break;
1340         case FM_COMMENT:
1341             {
1342                 E( eventCommentStart(S) );
1343                 E( eventData(S, item -> string1) );
1344                 E( eventCommentEnd(S) );
1345             };
1346         }
1347     }
1348     return OK;
1349 }
1350 
1351 
eventBeginOutput(Sit S)1352 eFlag OutputterObj::eventBeginOutput(Sit S)
1353 {
1354   const EQName dummy;
1355   pushLevel(dummy); //experimental
1356   method = outDef ? outDef -> getMethod() : OUTPUT_UNKNOWN;
1357   if (physical)
1358     {
1359       //??JP??both physical & method !=...
1360       //duplicit with the same in reportXMLDeclIfMust
1361       if (method != OUTPUT_UNKNOWN)
1362 	E( reportXMLDeclIfMust(S) );
1363     }
1364   // initialize the SAX interface
1365   IF_SAX1( startDocument );
1366   state = STATE_OUTSIDE;
1367   return OK;
1368 }
1369 
eventBeginSubtree(Sit S)1370 eFlag OutputterObj::eventBeginSubtree(Sit S)
1371 {
1372   const EQName dummy;
1373   pushLevel(dummy); //experimntal
1374     method = outDef -> getMethod();
1375     if (physical)
1376     {
1377       //      method = outDef -> getMethod();
1378     }
1379     // initialize the SAX interface
1380     IF_SAX1( startDocument );
1381     state = STATE_OUTSIDE;
1382     return OK;
1383 }
1384 
1385 
eventElementStart(Sit S,const EQName & name)1386 eFlag OutputterObj::eventElementStart(Sit S, const EQName& name)
1387 {
1388   if (noElementYet)
1389     {
1390       noElementYet = FALSE;
1391       if (physical)
1392         {
1393 	  if (method == OUTPUT_UNKNOWN)
1394             {
1395 	      if (name.getUri().isEmpty() && name.getLocal().eqNoCase("html"))
1396 		method = OUTPUT_HTML;
1397 	      else
1398 		method = OUTPUT_XML;
1399 	      E( physical -> setMethodByDefault(S, method) );
1400 	      E( reportXMLDeclIfMust(S) );
1401 	      E( reportFront(S) );//??JP??sax
1402             };
1403 	  // If this is an included stylesheet, output method cd be TEXT here
1404 	  if (method != OUTPUT_TEXT) {
1405 	    E( reportDTDIfMust( S, name ) );//??JP??sax
1406 	  }
1407         };
1408     }
1409   switch(state)
1410     {
1411     case STATE_OUTSIDE:
1412     case STATE_IN_MARKUP:
1413     case STATE_IN_ELEMENT:
1414       {
1415 	// reportStartTag also sends the event to SAX
1416 	E( reportStartTag(S, NONEMPTY_ELEMENT) );
1417 	E( reportCurrData(S) );
1418 	pushLevel(name);
1419 	// this sets state to STATE_IN_MARKUP
1420       };
1421       break;
1422     case STATE_IN_COMMENT:
1423     case STATE_IN_PI:
1424     case STATE_IN_ATTRIBUTE:
1425       Err( S, E_ELEM_IN_COMMENT_PI );
1426     default:
1427       sabassert(!"eventElementStart");
1428     };
1429 
1430   // determine whether we're in a HEAD html element so a META tag
1431   // needs to be added
1432 
1433   return OK;
1434 }
1435 
throwInMeta(Sit S)1436 eFlag OutputterObj::throwInMeta(Sit S)
1437 {
1438     noHeadYet = FALSE;
1439 
1440     if ( S.hasFlag(SAB_DISABLE_ADDING_META) ) return OK;
1441 
1442     if (physical || mySAXHandler)
1443     {
1444         Str metaName("meta");
1445 	Str httpEquiv("http-equiv");
1446 	Str contentType("Content-Type");
1447 	Str content("content");
1448         DStr contentValue =
1449 	  NZ(outDef) -> getValueStr(XSLA_MEDIA_TYPE) + "; charset=" +
1450 	  outDef -> getValueStr(XSLA_ENCODING);
1451 
1452 	if (physical) {
1453 	  StrStrList metaAtts;
1454 	  //EQName
1455 	  //   httpEquivName,
1456 	  //   contentName;
1457 	  //httpEquivName.setLocal("http-equiv");
1458 	  //contentName.setLocal("content");
1459 	  metaAtts.appendConstruct(httpEquiv, contentType);
1460 	  metaAtts.appendConstruct(content, contentValue);
1461 	  E( physical -> outputElementStart(S, metaName, currNamespaces,
1462 					    getFirstOwnNS(), metaAtts, TRUE) );
1463 	  E( physical -> outputElementEnd(S, metaName, TRUE) );
1464 	  metaAtts.freeall(FALSE);
1465 	};
1466 
1467 	if (mySAXHandler) {
1468 	  char *saxAtts[5];
1469 	  saxAtts[0] = httpEquiv;
1470 	  saxAtts[1] = contentType;
1471 	  saxAtts[2] = content;
1472 	  saxAtts[3] = (char *) contentValue;
1473 	  saxAtts[4] = NULL;
1474 	  mySAXHandler->startElement(mySAXUserData, S.getProcessor(),
1475 				     metaName,
1476 				     (const char**) saxAtts);
1477 	  mySAXHandler->endElement(mySAXUserData, S.getProcessor(),
1478 				   metaName);
1479 	};
1480 
1481         state = STATE_IN_ELEMENT;//??JP?? why to change state ?
1482 
1483     };
1484     return OK;
1485 }
1486 
1487 
1488 
eventElementEnd(Sit S,const EQName & name)1489 eFlag OutputterObj::eventElementEnd(Sit S, const EQName& name)
1490 {
1491   sabassert(!(physical && mySAXOutputType == SAXOUTPUT_INT_PHYSICAL));
1492   Str physName;
1493   //  if (S.getProcessor())
1494   //  temp = S.getProcessor() -> getAliasedName(name,
1495   //					      currNamespaces,
1496   //					      mySAXOutputType == SAXOUTPUT_INT_PHYSICAL);
1497   //else name.getname(temp);
1498 
1499   switch(state)
1500     {
1501     case STATE_IN_MARKUP:
1502       E( reportStartTag(S, EMPTY_ELEMENT) );
1503       break;
1504     case STATE_IN_ELEMENT:
1505       {
1506 	E( reportCurrData(S) );
1507 	if (physical)
1508 	  {
1509 	    Str physName;
1510 	    name.getname(physName);
1511 	    physical -> outputElementEnd(S, physName, NONEMPTY_ELEMENT );
1512 	  };
1513       }; break;
1514     default:
1515       sabassert(!"eventElementEnd");
1516     };
1517 
1518   // send the event to SAX
1519   switch(mySAXOutputType)
1520     {
1521     case SAXOUTPUT_COPY_TREE:
1522     case SAXOUTPUT_INT_PHYSICAL:
1523       {
1524         GP( Str ) theSAXname = nameForSAX(S, name);
1525 	IF_SAX2( endElement, (const char*) *theSAXname );
1526 	theSAXname.del();
1527 	// report namespace scope ends
1528 	//while (currNamespaces.number() > getFirstOwnNS())
1529 	for (int ii = currNamespaces.number() - 1; ii >= getFirstOwnNS(); ii--)
1530 	  {
1531 	    IF_SAX2( endNamespace, currNamespaces[ii] -> prefix );
1532 	    //debug
1533 	  }
1534       };
1535       break;
1536     case SAXOUTPUT_AS_PHYSICAL:
1537       {
1538 	Str physName;
1539 	name.getname(physName);
1540         IF_SAX2( endElement, (const char*) physName );
1541 	// report namespace scope ends
1542 	Str* prefix;
1543 	//while (currNamespaces.number() > getFirstOwnNS())
1544 	for (int ii = currNamespaces.number() - 1; ii >= getFirstOwnNS(); ii--)
1545 	  {
1546 	    prefix = &(currNamespaces[ii] -> prefix);
1547 	    if (! currNamespaces.isHidden(*prefix))
1548 	      IF_SAX2( endNamespace, currNamespaces[ii] -> prefix );
1549 	  }
1550       };
1551       break;
1552     case SAXOUTPUT_NONE: break;
1553     default:
1554       sabassert(!"eventElementEnd");
1555     };
1556 
1557   //remove our namespaces
1558   while (currNamespaces.number() > getFirstOwnNS())
1559     currNamespaces.freelast(FALSE);
1560 
1561   // pop one history level
1562   history.freelast(FALSE);
1563   if (getLevel()) //experimental
1564     state = STATE_IN_ELEMENT;
1565   else
1566     state = STATE_OUTSIDE;
1567 
1568   return OK;
1569 }
1570 
1571 
eventAttributeStart(Sit S,const EQName & name)1572 eFlag OutputterObj::eventAttributeStart(Sit S, const EQName& name)
1573 {
1574     Str fullName;
1575     name.getname(fullName);
1576     switch(state)
1577     {
1578     case STATE_IN_MARKUP:
1579         {
1580             state = STATE_IN_ATTRIBUTE;
1581             currAttName = name;
1582         }; break;
1583     case STATE_IN_ELEMENT:
1584         {
1585             Err1(S, E1_ATTRIBUTE_TOO_LATE, fullName);
1586 	    };
1587         break;
1588     case STATE_OUTSIDE:
1589         {
1590             Err1(S, E1_ATTRIBUTE_OUTSIDE, fullName);
1591 	    };
1592         break;
1593     default:
1594       Err1(S, E1_ATTRIBUTE_MISPLACED, fullName);
1595       //sabassert(!"eventAttributeStart");
1596     };
1597     return OK;
1598 }
1599 
1600 
eventAttributeEnd(Sit S)1601 eFlag OutputterObj::eventAttributeEnd(Sit S)
1602 {
1603     sabassert(state == STATE_IN_ATTRIBUTE);
1604 
1605     int currAttNameNdx = currAtts.findNdx(currAttName);
1606     if (currAttNameNdx != -1)
1607         currAtts[currAttNameNdx] -> value = currData;
1608     else
1609         currAtts.appendConstruct(currAttName, currData);
1610     currData.empty();
1611     state = STATE_IN_MARKUP;
1612     return OK;
1613 }
1614 
1615 
eventCommentStart(Sit S)1616 eFlag OutputterObj::eventCommentStart(Sit S)
1617 {
1618     switch(state)
1619     {
1620     case STATE_IN_MARKUP:
1621         E( reportStartTag(S, NONEMPTY_ELEMENT) );
1622         // no break
1623     case STATE_OUTSIDE:
1624     case STATE_IN_ELEMENT:
1625         {
1626             E( reportCurrData(S) );
1627             state = STATE_IN_COMMENT;
1628         }; break;
1629     default:
1630         sabassert(!"eventCommentStart");
1631     };
1632     return OK;
1633 }
1634 
eventCommentEnd(Sit S)1635 eFlag OutputterObj::eventCommentEnd(Sit S)
1636 {
1637     sabassert(state == STATE_IN_COMMENT);
1638     if (physical && method == OUTPUT_UNKNOWN)
1639         E( front.appendConstruct(S, FM_COMMENT, currData,
1640                                  ""/**theEmptyString*/, FALSE) )
1641     else
1642     {
1643         IF_PH2( outputComment, currData );
1644         IF_SAX2( comment, currData );
1645     }
1646     currData.empty();
1647     state = (getLevel() ? STATE_IN_ELEMENT : STATE_OUTSIDE); //experimental
1648     return OK;
1649 }
1650 
eventPIStart(Sit S,const Str & name)1651 eFlag OutputterObj::eventPIStart(Sit S, const Str& name)
1652 {
1653     switch(state)
1654     {
1655     case STATE_IN_MARKUP:
1656         E( reportStartTag(S, NONEMPTY_ELEMENT) );
1657         // no break
1658     case STATE_IN_ELEMENT:
1659     case STATE_OUTSIDE:
1660         {
1661             E( reportCurrData(S) );
1662             state = STATE_IN_PI;
1663             currPIName = name;
1664         }; break;
1665     default:
1666         sabassert(!"eventPIStart");
1667     };
1668     return OK;
1669 }
1670 
eventPIEnd(Sit S)1671 eFlag OutputterObj::eventPIEnd(Sit S)
1672 {
1673     sabassert(state == STATE_IN_PI);
1674 
1675     //check te PI data
1676     if ( strstr((char*)currData, "?>") )
1677       Err(S, E_INVALID_DATA_IN_PI);
1678 
1679     if (physical && method == OUTPUT_UNKNOWN)
1680         E( front.appendConstruct(S, FM_PI, currPIName, currData, FALSE) )
1681     else
1682     {
1683         IF_PH3( outputPI, currPIName, currData );
1684         IF_SAX3( processingInstruction, currPIName, currData );
1685     }
1686     currData.empty();
1687     currPIName.empty();
1688     state = (getLevel() ? STATE_IN_ELEMENT : STATE_OUTSIDE);
1689     return OK;
1690 }
1691 
eventNamespace(Sit S,const Str & prefix,const Str & uri,Bool hidden)1692 eFlag OutputterObj::eventNamespace(Sit S, const Str& prefix, const Str& uri,
1693 				   Bool hidden)
1694 {
1695     sabassert(state == STATE_IN_MARKUP);
1696     // GP: OK, not allocated
1697     Str search = uri;
1698     int existing_ndx = currNamespaces.findNum(prefix);
1699     const Str *existing_namespace = (
1700        existing_ndx == -1 ? NULL : &(currNamespaces[existing_ndx] -> uri));
1701     //explanation: if we found previously inserted namespace, we have
1702     //to add new definition to override it with one exception. Two
1703     //namespaces with the same prefix may be added (e.g. for
1704     //xsl:element insrtuction) in this case (existing_ndx >=
1705     //getFirstOwnNS()) we need override former definition in place.
1706 
1707     /*
1708     if (uri == theXSLTNamespace)
1709       {
1710 	//we need to reveal the xslt namespace if it is aliased
1711 	Processor *proc = S.getProcessor();
1712 	if (proc)
1713 	  {
1714 	    Bool aliased;
1715 	    E( proc -> prefixIsAliasTarget(S, prefix, aliased) );
1716 	    hidden = hidden && ! aliased;
1717 	  }
1718       }
1719     */
1720 
1721     if (!existing_namespace)
1722       {
1723 	//if the namespace doesn't exist yet, we add it
1724 	currNamespaces.appendConstruct(prefix, uri, hidden);
1725       }
1726     else
1727       {
1728 	Bool exIsHidden = currNamespaces[existing_ndx]->hidden;
1729 	if (!(*existing_namespace == uri))
1730 	  {
1731 	    if (existing_ndx >= getFirstOwnNS())
1732 	      {
1733 		currNamespaces[existing_ndx] -> uri = uri;
1734 		currNamespaces[existing_ndx] -> hidden = hidden;
1735 	      }
1736 	    else
1737 	      {
1738 		currNamespaces.appendConstruct(prefix, uri, hidden);
1739 	      }
1740 	  }
1741 	//may be we found excluded one, but in current subtree
1742 	//it sould be kept
1743 	else if (exIsHidden && !hidden)
1744 	  {
1745 	    currNamespaces.appendConstruct(prefix, uri, hidden);
1746 	  }
1747       }
1748     return OK;
1749 }
1750 
eventDisableEscapingForNext(Sit S)1751 eFlag OutputterObj::eventDisableEscapingForNext(Sit S)
1752 {
1753     if (method != OUTPUT_TEXT)
1754     {
1755         switch(state)
1756         {
1757         case STATE_IN_ATTRIBUTE:
1758         case STATE_IN_PI:
1759         case STATE_IN_COMMENT:
1760 	  Warn(S, W_DISABLE_OUTPUT_ESC); break;
1761         default:
1762 	  outputEscaping = FALSE;
1763         };
1764     }
1765     return OK;
1766 }
1767 
eventData(Sit S,const Str & data,Bool hardCData)1768 eFlag OutputterObj::eventData(Sit S, const Str& data, Bool hardCData /* = FALSE */)
1769 {
1770     if (physical && method == OUTPUT_UNKNOWN && state == STATE_OUTSIDE)
1771     {
1772         E( front.appendConstruct(S, FM_TEXT, data,
1773                                  "" /**theEmptyString*/, !outputEscaping) );
1774         if (!isAllWhite((const char*) data))
1775         {
1776             E( physical -> setMethodByDefault(S, method = OUTPUT_XML) );
1777             E( reportXMLDeclIfMust(S) );
1778             E( reportFront(S) );
1779         }
1780         return OK;
1781     }
1782 
1783     switch(state)
1784     {
1785     case STATE_IN_MARKUP:
1786         E( reportStartTag(S, NONEMPTY_ELEMENT) );
1787         // no break
1788     case STATE_IN_ELEMENT:
1789     case STATE_OUTSIDE:
1790         {   // this is a text node
1791             if (!(getFlags() & CDATA_SECTION) && !hardCData)
1792             {
1793                 int htmlScriptOrStyle = ( getFlags() & HTML_SCRIPT_OR_STYLE );
1794                 if (physical)
1795                     E( physical -> outputText(S, data, !outputEscaping,
1796 					      htmlScriptOrStyle) );
1797             }
1798             // reset outputEscaping to default after use
1799             // even if we just save a part of cdata section
1800             outputEscaping = TRUE;
1801             state = getLevel() ? STATE_IN_ELEMENT : STATE_OUTSIDE;
1802         }   // no break
1803     case STATE_IN_COMMENT:
1804     case STATE_IN_PI:
1805     case STATE_IN_ATTRIBUTE:
1806         {
1807             currData += data;
1808         }; break;
1809     default:
1810         sabassert(!"eventData()");
1811     }
1812     return OK;
1813 }
1814 
eventCDataSection(Sit S,const Str & data)1815 eFlag OutputterObj::eventCDataSection(Sit S, const Str& data)
1816 {
1817     switch(state)
1818     {
1819         case STATE_IN_MARKUP:
1820 	        E( reportStartTag(S, NONEMPTY_ELEMENT) );
1821 		// no break
1822 		case STATE_OUTSIDE:
1823 		case STATE_IN_ELEMENT:
1824 		{
1825 		    E( reportCurrData(S) );
1826 		    E( eventData(S, data, /* hardCData = */ TRUE) );
1827 		    E( reportCurrData(S, /* hardCData = */ TRUE) );
1828 		}; break;
1829 		default:
1830 		    sabassert(!"eventCDataSection()");
1831     };
1832     return OK;
1833 }
1834 
eventEndOutput(Sit S,Bool closePhysical)1835 eFlag OutputterObj::eventEndOutput(Sit S, Bool closePhysical /* = false */)
1836 {
1837     sabassert(state == STATE_OUTSIDE);
1838     E( reportCurrData(S) );
1839     if (physical && method == OUTPUT_UNKNOWN)
1840     {
1841         E( physical -> setMethodByDefault(S, method = OUTPUT_XML) );
1842         E( reportXMLDeclIfMust(S) );
1843         E( reportFront(S) );
1844     }
1845     IF_PH1( outputDone );
1846     IF_SAX1( endDocument );
1847     state = STATE_DONE;
1848 
1849     //pop fake history item
1850     history.freelast(FALSE);
1851 
1852     //close physical (used for multiple doc output)
1853     if (physical && closePhysical)
1854       {
1855 	E( physical -> close(S) );
1856       }
1857 
1858     return OK;
1859 }
1860 
eventTrailingNewline(Sit S)1861 eFlag OutputterObj::eventTrailingNewline(Sit S)
1862 {
1863   sabassert(state == STATE_OUTSIDE);
1864   if (physical)
1865     {
1866       E(physical -> outputTrailingNewline(S))
1867     }
1868   return OK;
1869 }
1870 
reportCurrData(Sit S,Bool hardCData)1871 eFlag OutputterObj::reportCurrData(Sit S, Bool hardCData /* = FALSE */)
1872 {
1873     if (currData.isEmpty())
1874         return OK;
1875     switch(state)
1876     {
1877     case STATE_OUTSIDE:
1878     case STATE_IN_MARKUP:
1879     case STATE_IN_ELEMENT:
1880         {
1881             if (getFlags() & CDATA_SECTION || hardCData)
1882             {
1883                 // we might now call the SAX startCData handler (if there was one)
1884                 IF_SAX3( characters, currData, currData.length() );
1885                 IF_PH2( outputCDataSection, currData );
1886                 // we might call the SAX endCData handler
1887             }
1888             else
1889             {
1890                 // the text had been output to physical in parts
1891                 IF_SAX3( characters, currData, currData.length());
1892             }
1893         }; break;
1894     default:
1895         sabassert(!"reportCurrData()");
1896     }
1897     currData.empty();
1898     return OK;
1899 }
1900 
1901 
1902 /*
1903     GP: if this function is modified, care must be taken about the guarded
1904     pointers
1905 */
1906 
reportStartTag(Sit S,Bool isEmpty)1907 eFlag OutputterObj::reportStartTag(Sit S, Bool isEmpty)
1908 {
1909   sabassert(!(physical && mySAXOutputType == SAXOUTPUT_INT_PHYSICAL));
1910   // FIXME: couldn't improve reportStartTag from GP point of view?
1911   if (state == STATE_OUTSIDE || currElement.isEmpty())
1912     return OK;
1913 
1914   int doThrowMeta = method == OUTPUT_HTML && noHeadYet &&
1915     currElement.getUri().isEmpty() && currElement.getLocal().eqNoCase("head");
1916   int i;
1917   //get attr aliased names
1918   StrStrList attAliased;
1919   // the temporary string is a workaround for VisualAge on AIX
1920   //Str temp;
1921 
1922 
1923   Str physName;
1924   Bool intPhys = mySAXOutputType == SAXOUTPUT_INT_PHYSICAL;
1925 
1926   if (physical || (mySAXHandler && (mySAXOutputType == SAXOUTPUT_AS_PHYSICAL)))
1927     {
1928       //if (S.getProcessor())
1929       //temp = S.getProcessor() -> getAliasedName(currElement,
1930       //					  currNamespaces, intPhys);
1931       //else
1932       //currElement.getname(temp);
1933       currElement.getname(physName);
1934 
1935       for (i = 0; i < currAtts.number(); i++)
1936 	{
1937 	  Str aliname;
1938 	  //if (S.getProcessor())
1939 	  //  aliname = S.getProcessor() -> getAliasedName(currAtts[i] -> key,
1940 	  //					 currNamespaces,
1941 	  //					 intPhys);
1942 	  //else
1943 	  //  currAtts[i] -> key.getname(aliname);
1944 	  currAtts[i] -> key.getname(aliname);
1945 	  attAliased.appendConstruct(aliname, currAtts[i] -> value);
1946 	}
1947 
1948       if (physical) {
1949 	if ( delayedDTD )
1950 	  {
1951 	    const Str&
1952 	      DTSystem = outDef -> getValueStr(XSLA_DOCTYPE_SYSTEM),
1953 	      DTPublic = outDef -> getValueStr(XSLA_DOCTYPE_PUBLIC);
1954 	    E( physical -> outputDTD( S, physName, DTPublic, DTSystem) );
1955 	    delayedDTD = FALSE;
1956 	  }
1957 
1958 	E( physical -> outputElementStart(S, physName, currNamespaces,
1959 					  getFirstOwnNS(), attAliased,
1960 					  isEmpty && !doThrowMeta) );
1961       }
1962     }
1963 
1964   if (mySAXHandler)
1965     {
1966       const char** attsTable;
1967       GPA( ConstCharP ) attsArr = attsTable = new const char*[(currAtts.number() * 2) + 1];
1968       // GP: the allocations are OK: no exit routes
1969 
1970       PList<Str*> stringsForDeletion;
1971       attsTable[currAtts.number() * 2] = NULL;
1972 
1973       switch(mySAXOutputType)
1974 	{
1975 	case SAXOUTPUT_COPY_TREE:
1976 	case SAXOUTPUT_INT_PHYSICAL:
1977 	  {
1978 	    // report only the new namespaces
1979 	    Str* prefix;
1980 	    for (i = getFirstOwnNS(); i < currNamespaces.number(); i++)
1981 	      {
1982 		prefix = &(currNamespaces[i] -> prefix);
1983 		if (intPhys)
1984 		  {
1985 		    IF_INT_SAX4( startNamespace2, currNamespaces[i] -> prefix,
1986 				 currNamespaces[i] -> uri,
1987 				 currNamespaces.isHidden(*prefix) );
1988 		  }
1989 		else
1990 		  IF_SAX3( startNamespace, currNamespaces[i] -> prefix,
1991 			   currNamespaces[i] -> uri );
1992 	      }
1993 	    // create the attribute table
1994 	    for (i = 0; i < currAtts.number(); i++)
1995 	      {
1996 		Str *expatName = nameForSAX(S, currAtts[i] -> key);
1997 		stringsForDeletion.append(expatName);
1998 		attsTable[i * 2] = *expatName;
1999 		attsTable[(i * 2) + 1] = currAtts[i] -> value;
2000 	      };
2001 	    Str* theSAXname = nameForSAX(S, currElement);
2002 	    stringsForDeletion.append(theSAXname);
2003 	    IF_SAX3(startElement, *theSAXname, attsTable);
2004 	    stringsForDeletion.freeall(FALSE);
2005 	  };
2006 	  break;
2007 	case SAXOUTPUT_AS_PHYSICAL:
2008 	  // report only the new not hidden namespaces
2009 	  Str* prefix;
2010 	  for (i = getFirstOwnNS(); i < currNamespaces.number(); i++)
2011 	    {
2012 	      prefix = &(currNamespaces[i] -> prefix);
2013 	      if (! currNamespaces.isHidden(*prefix))
2014 		IF_SAX3( startNamespace, currNamespaces[i] -> prefix,
2015 			 currNamespaces[i] -> uri );
2016 	    }
2017 	  // create the attribute table
2018 	  for (i = 0; i < currAtts.number(); i++)
2019 	    {
2020 	      attsTable[i * 2] = (char *)attAliased[i] -> key;
2021 	      attsTable[(i * 2) + 1] = (char *)attAliased[i] -> value;
2022 	    };
2023 
2024 	  IF_SAX3(startElement, physName, attsTable);
2025 	  break;
2026 	case SAXOUTPUT_NONE:
2027 	  sabassert(!"saxoutput == NONE");
2028 	default:
2029 	  sabassert(!"eventElementEnd");
2030 	};
2031       //attsTable.delArray();
2032     }
2033 
2034   if (physical || (mySAXHandler && mySAXOutputType == SAXOUTPUT_AS_PHYSICAL))
2035     {
2036       attAliased.freeall(FALSE);
2037     }
2038 
2039   eFlag result = OK;
2040   if (doThrowMeta) {
2041     result = throwInMeta(S);
2042     //__PH__ close head if needed
2043     if (isEmpty) {
2044       if (physical) {
2045 	E( physical ->outputElementEnd(S, physName, FALSE) );
2046       };
2047     };
2048   }
2049 
2050   currElement.empty();
2051   currAtts.freeall(FALSE);
2052   currData.empty();
2053   return result;
2054 }
2055 
pushLevel(const EQName & name)2056 void OutputterObj::pushLevel(const EQName& name)
2057 {
2058     currElement = name;
2059     GP( OutputHistoryItem ) newItem = new OutputHistoryItem;
2060     if (history.number())
2061       {
2062         *newItem = *(history.last());
2063 	//next line is speed optimalization (very few)
2064 	(*newItem).useDocument = (*(history.last())).document;
2065       }
2066     else
2067       {
2068         (*newItem).flags = 0;
2069 	(*newItem).useDocument = NULL;
2070       }
2071     //definition is used for multiple document output
2072     (*newItem).document = NULL; //in any case
2073     if (physical)
2074     {
2075         if (outDef -> askEQNameList(XSLA_CDATA_SECT_ELEMS, name))
2076             (*newItem).flags |= CDATA_SECTION;
2077         else
2078             (*newItem).flags &= ~CDATA_SECTION;
2079 
2080 	//style and script for html
2081 	if ( (method == OUTPUT_HTML && name.getUri() == "") &&
2082 	     isHTMLNoEscapeTag(name.getLocal()) )
2083 	  {
2084 	    (*newItem).flags |= HTML_SCRIPT_OR_STYLE;
2085 	  }
2086 	else
2087 	  {
2088 	    (*newItem).flags &= ~HTML_SCRIPT_OR_STYLE;
2089 	  }
2090     };
2091     (*newItem).firstOwnNS = currNamespaces.number();
2092     history.append(newItem.keep());
2093     state = STATE_IN_MARKUP;
2094 }
2095 
report(Sit S,MsgType type,MsgCode code,const Str & arg1,const Str & arg2)2096 void OutputterObj::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
2097 {
2098     S.message(type, code, arg1, arg2);
2099 }
2100 
setDocumentForLevel(Sit S,OutputDocument * doc)2101 eFlag OutputterObj::setDocumentForLevel(Sit S, OutputDocument *doc)
2102 {
2103   if (history.number())
2104     (*(history.last())).document = doc;
2105   return OK;
2106 }
2107 
getDocumentForLevel(Bool forElement)2108 OutputDocument* OutputterObj::getDocumentForLevel(Bool forElement)
2109 {
2110   if (history.number())
2111     return forElement ? (*(history.last())).useDocument :
2112     (*(history.last())).document;
2113   else
2114     return NULL;
2115 }
2116