Initial revision
[TestXSLT.git] / libsablot / src / engine / output.h
1 /* -*- mode: c++ -*-
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):
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 #if !defined(OutputHIncl)
34 #define OutputHIncl
35
36 // GP: clean
37
38 #include "datastr.h"
39 #include "utf8.h"
40 #include "encoding.h"
41
42 class DataLine;     // see uri.h
43
44 enum OutputMethod
45 {
46     OUTPUT_XML,
47     OUTPUT_HTML,
48     OUTPUT_TEXT,
49     OUTPUT_XHTML,
50     OUTPUT_UNKNOWN
51 };
52
53 enum EscMode
54 {
55     ESCAPING_NONE,
56     ESCAPING_URI,
57     ESCAPING_ATTR,
58 //    ESCAPING_CDATA, - use ESCAPING_NONE
59     ESCAPING_LT_AMP,
60     ESCAPING_HTML_URI,
61     ESCAPING_HTML_ATTR
62 };
63
64 enum SAXOutputType
65 {
66   SAXOUTPUT_NONE,
67   //hard copy, no translations, no hidden ns....
68   SAXOUTPUT_COPY_TREE,
69   //for physical output, hidden ns, aliasing
70   SAXOUTPUT_AS_PHYSICAL,
71   //as physical, but use expat like names
72   SAXOUTPUT_INT_PHYSICAL
73 };
74
75 #define THE_NAMESPACE_SEPARATOR '`'
76
77 // the following must match the size of outputStringAtts[] - 1
78 // as defined in output.cpp
79 #define STRING_ITEMS_COUNT 8
80
81 // constants for special values of precedence for xsl:output attributes
82 // use for OutputDefinition::setItemStr and setItemEQName
83
84 // specify only if not yet specified, otherwise no error
85 #define OUTPUT_PRECEDENCE_WEAKEST -1
86 // override, no error
87 #define OUTPUT_PRECEDENCE_STRONGEST -2
88 // for internal use only
89 #define OUTPUT_PRECEDENCE_UNSPECIFIED -3
90
91 //
92 //  StrPrec
93 //  string with (import) precedence
94 //  unspecified: precedence = -1
95 //  to set, new precedence must be less than existing (unless existing == -1)
96 //  special values of new precedence: override without checking (-1), set only if unspecified (-2)
97 //
98
99 class StrPrec
100 {
101
102 public:
103     StrPrec()
104         {
105             precedence = OUTPUT_PRECEDENCE_UNSPECIFIED;
106         };
107     // sets the string if new precedence is stronger
108     // returns TRUE if new pref is non-negative and equal to old (does not set in this case)
109     Bool set(const Str& newString, int newPrecedence);
110     const Str& get() const 
111         {
112             return string;
113         }
114 private:
115     Str string;
116     int precedence;
117 };
118
119 //
120 //  EQNamePrec
121 //  same as StrPrec but holding EQName
122 //
123
124 class EQNamePrec
125 {
126
127 public:
128     EQNamePrec()
129         {
130             precedence = OUTPUT_PRECEDENCE_UNSPECIFIED;
131         };
132   // sets the string if new precedence is stronger
133   // returns TRUE if new pref is non-negative and equal to old (does not set in this case)
134     Bool set(const EQName& newName, int newPrecedence);
135     const EQName& get() const 
136         {
137             return name;
138         }
139 private:
140     EQName name;
141     int precedence;
142 };
143
144 //
145 //  OutputDef
146 //  stores the output-controlling information for an XSLT tree
147 //
148
149 #define OUTPUT_BUFFER_LIMIT     1024
150 #define OUTPUT_BUFFER_SIZE      OUTPUT_BUFFER_LIMIT + 64
151
152
153 #define HTML_SPECIAL            TRUE
154 #define NOT_HTML_SPECIAL        FALSE
155
156 class OutputDefinition
157 {
158 public:
159     OutputDefinition();
160     ~OutputDefinition();
161     // sets a string item
162     // itemId identifies the attribute code, 'value' is the new value
163     // 'caller' is the xsl:output element
164     // precedence is the current import precedence 
165     // (may be OUTPUT_PRECEDENCE_STRONGEST to override, ..._WEAKEST to only set if unset) if !caller
166     eFlag setItemStr(
167         Sit S, XSL_ATT itemId, const Str& value, Vertex *caller, int precedence);
168     // sets an EQName item (@method or @cdata-sect-elems)
169     eFlag setItemEQName(
170         Sit S, XSL_ATT itemId, const EQName& value, Vertex *caller, int precedence);
171     eFlag setDefaults(Sit S);
172     const Str& getValueStr(XSL_ATT itemId) const;
173     const EQName& getValueEQName(XSL_ATT itemId) const;
174     Bool askEQNameList(XSL_ATT itemId, const EQName &what) const;
175     int getStatus(XSL_ATT itemId) const;
176     OutputMethod getMethod() const;
177     Bool getIndent() const;
178     const Str& getEncoding() const;
179 private:
180     StrPrec stringItems[STRING_ITEMS_COUNT];
181     EQNamePrec
182         method;
183     EQNameList
184         cdataElems;
185     DataLine *targetDataLine;
186     void report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2);
187 };
188
189 //
190 //
191 //  PhysicalOutputterObj
192 //
193 //
194
195 class PhysicalOutputLayerObj
196 {
197 public:
198     PhysicalOutputLayerObj(CDesc encodingCD_);
199     ~PhysicalOutputLayerObj();
200     eFlag setOptions(Sit S, DataLine *targetDataLine_, OutputDefinition *outDef_);
201     eFlag outputElementStart(Sit S, const Str& name, 
202         const NamespaceStack& namespaces, const int namespace_index,
203         const StrStrList& atts, Bool isEmpty);
204     eFlag outputElementEnd(Sit S, const Str& name, Bool isEmpty);
205     eFlag outputText(Sit S, const Str& contents, Bool outputEscaping, Bool inHTMLSpecial);
206     eFlag outputComment(Sit S, const Str& contents);
207     eFlag outputCDataSection(Sit S, const Str& contents);
208     eFlag outputPI(Sit S, const Str& target, const Str& data);
209     eFlag outputDTD(Sit S, const Str& name, const Str& publicId, const Str& systemId);
210     eFlag outputTrailingNewline(Sit S);
211     eFlag outputDone(Sit S);
212     eFlag setMethodByDefault(Sit S, OutputMethod method_);
213     DataLine* getDataLine() { return targetDataLine; };
214 private:
215     DataLine *targetDataLine;
216     OutputDefinition *outDef;
217     OutputMethod method;
218     Bool indent;
219     Bool after_markup;  //pc
220     int level;  //pc
221     char buffer[OUTPUT_BUFFER_SIZE],
222         smallBuf[SMALL_BUFFER_SIZE];
223     int curr;
224     Str encoding;
225     CDesc encodingCD;
226     Bool defaultNSWas;
227     eFlag sendOut(Sit S, const char* data, int length, EscMode escapeMode);
228     eFlag sendOutUntil(Sit S, const char* & data, int length,
229         EscMode escapeMode, const char* stoppingText);
230     int writeCharacterRef(char* dest, const char *src, EscMode escapeMode);
231     eFlag flushBuffer(Sit S);
232     void report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2);
233 };
234
235 //
236 //
237 //  OutputterObj
238 //
239 //
240
241 //output document (for multiple document output)
242 enum OutdocState {
243   OUTDOC_NEW,
244   OUTDOC_ACTIVE,
245   OUTDOC_FINISHED
246 };
247
248 class OutputterObj;
249 class OutputDocument
250 {
251 public:
252   OutputDocument(Str h, OutputDefinition *d) : 
253     href (h), outputter(NULL), state(OUTDOC_NEW), def(d) {};
254   ~OutputDocument();
255   Str &getURI() { return uri; };
256   OutputterObj* setOutputter(OutputterObj* new_);
257   OutputterObj* getOutputter() { return outputter; };
258   OutputDefinition* getDefinition() { return def; };
259   OutdocState getState() { return state; };
260   void setState(OutdocState s) { state = s; };
261   eFlag finish(Sit S);
262   Str &getHref() { return href; };
263 private:
264   Str href;
265   OutputterObj *outputter;
266   OutdocState state;
267   OutputDefinition *def;
268   Str uri;
269 };
270
271 //following structures are used for correct namespace exclusions
272 class SubtreeInfo;
273
274 enum OutputterState
275 {
276     STATE_OUTSIDE = 0,
277     STATE_IN_MARKUP,
278     STATE_IN_ELEMENT,
279     STATE_IN_ATTRIBUTE,
280     STATE_IN_COMMENT,
281     STATE_IN_PI,
282     STATE_DONE,
283     STATE_UNDEFINED
284 };
285
286 struct OutputHistoryItem
287 {
288   int flags;
289   int firstOwnNS;
290   OutputDocument *document;
291   OutputDocument *useDocument;
292 };
293
294 typedef PList<OutputHistoryItem*> OutputHistory;
295
296 //
297 //  FrontMatter
298 //
299
300 enum FrontMatterKind
301 {
302     FM_TEXT,
303     FM_COMMENT,
304     FM_PI
305 };
306
307 struct FrontMatterItem
308 {
309     FrontMatterKind kind;
310     Str string1, string2;
311     Bool disableEsc;
312 };
313
314 class FrontMatter : public PList<FrontMatterItem*>
315 {
316 public:
317     eFlag appendConstruct(Sit S, FrontMatterKind kind, const Str& string1,
318         const Str& string2, Bool disableEsc);
319     void report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2);
320 };
321
322
323 class OutputterObj
324 {
325 public:
326     OutputterObj();
327     ~OutputterObj();
328     eFlag setOptions(Sit S, DataLine *targetDataLine_, OutputDefinition *outDef_);
329     eFlag setOptionsSAX(Sit S, SAXHandler *streaming_, void *userData, SAXOutputType saxout_);
330     eFlag eventBeginOutput(Sit S);
331     //_PH_ used for subtree serialization, ends with eventEndOutput
332     eFlag eventBeginSubtree(Sit S); 
333     eFlag eventElementStart(Sit S, const EQName& name);
334     eFlag eventElementEnd(Sit S, const EQName& name);
335     eFlag eventAttributeStart(Sit S, const EQName& name);
336     eFlag eventAttributeEnd(Sit S);
337     eFlag eventCommentStart(Sit S);
338     eFlag eventCommentEnd(Sit S);
339   //eFlag eventExcludeNS(Sit S, UriList &exNS);
340     eFlag eventNamespace(Sit S, const Str& prefix, const Str& uri, 
341                          Bool hidden = FALSE);
342     eFlag eventPIStart(Sit S, const Str& name);
343     eFlag eventPIEnd(Sit S);
344     eFlag eventData(Sit S, const Str& data, Bool hardCData = FALSE);
345     eFlag eventCDataSection(Sit S, const Str& data);
346     eFlag eventDisableEscapingForNext(Sit S);
347     eFlag eventEndOutput(Sit S);
348     eFlag eventTrailingNewline(Sit S);
349     eFlag setDocumentForLevel(Sit S, OutputDocument *doc);
350     OutputDocument* getDocumentForLevel(Bool forElement);
351     SAXOutputType getSAXOutputType() { return mySAXOutputType; };
352     PhysicalOutputLayerObj* getPhysical() { return physical; };
353 private:
354     eFlag reportCurrData(Sit S, Bool hardCData = FALSE);
355     eFlag reportStartTag(Sit S, Bool isEmpty);
356     eFlag throwInMeta(Sit S);
357     Str* nameForSAX(Sit S, const EQName& q);
358     void pushLevel(const EQName& name);
359 //    void popLevel();
360     int getLevel() 
361     {
362       return history.number() - 1; //ignore the '/' frame
363     };
364     int getFlags()
365     {
366         return (history.number()? history.last() -> flags : 0);
367     }
368     int getFirstOwnNS()
369     {
370         return (history.number()? history.last() -> firstOwnNS : 0);
371     }
372     Bool nsExcluded(Sit S, Str & uri);
373     eFlag reportXMLDeclIfMust(Sit S);
374     eFlag reportDTDIfMust(Sit S, const EQName& docElementName);
375     eFlag reportFront(Sit S);
376     void report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2);    
377     //
378     PhysicalOutputLayerObj *physical;
379     SAXHandler *mySAXHandler;
380     void *mySAXUserData;
381     SAXOutputType mySAXOutputType;
382     OutputDefinition *outDef;
383     OutputMethod method;
384     CDesc encodingCD;
385     OutputterState state;
386     Bool outputEscaping;
387     DStr currData;
388     Str
389         currPIName;
390     EQName
391         currElement, 
392         currAttName;
393     NamespaceStack
394         currNamespaces;
395     EQNameStrList
396         currAtts;
397     OutputHistory history;
398     Bool noElementYet,
399       noHeadYet,
400       delayedDTD;
401     FrontMatter front;
402 };
403
404
405 #endif  // OutputHIncl