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 < 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, "<") );
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 > always to prevent bad
878 //escaping in cdata sections.
879 E( sendLit(S, ">") );
880 served = TRUE;
881 }; break;
882 }
883 }; break;
884 case '&':
885 {
886 switch(escapeMode)
887 {
888 /* will escape & in URIs as & 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, "&") );
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, """) );
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