1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 *
25 * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
26 */
27
28 /*
29 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
30 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
31 *
32 * This code is free software; you can redistribute it and/or modify it
33 * under the terms of the GNU General Public License version 2 only, as
34 * published by the Free Software Foundation. Sun designates this
35 * particular file as subject to the "Classpath" exception as provided
36 * by Sun in the LICENSE file that accompanied this code.
37 *
38 * This code is distributed in the hope that it will be useful, but WITHOUT
39 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
40 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
41 * version 2 for more details (a copy is included in the LICENSE file that
42 * accompanied this code).
43 *
44 * You should have received a copy of the GNU General Public License version
45 * 2 along with this work; if not, write to the Free Software Foundation,
46 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
47 *
48 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
49 * CA 95054 USA or visit www.sun.com if you need additional information or
50 * have any questions.
51 *
52 * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
53 *
54 */
55
56 package com.sun.xml.internal.fastinfoset.sax;
57
58 import com.sun.xml.internal.fastinfoset.Encoder;
59 import com.sun.xml.internal.fastinfoset.EncodingConstants;
60 import com.sun.xml.internal.fastinfoset.QualifiedName;
61 import com.sun.xml.internal.org.jvnet.fastinfoset.sax.FastInfosetWriter;
62 import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap;
63 import java.io.IOException;
64 import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
65 import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
66 import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet;
67 import com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmAttributes;
68 import org.xml.sax.Attributes;
69 import org.xml.sax.SAXException;
70 import com.sun.xml.internal.fastinfoset.CommonResourceBundle;
71
72
73 /**
74 * The Fast Infoset SAX serializer.
75 * <p>
76 * Instantiate this serializer to serialize a fast infoset document in accordance
77 * with the SAX API.
78 * <p>
79 * This utilizes the SAX API in a reverse manner to that of parsing. It is the
80 * responsibility of the client to call the appropriate event methods on the
81 * SAX handlers, and to ensure that such a sequence of methods calls results
82 * in the production well-formed fast infoset documents. The
83 * SAXDocumentSerializer performs no well-formed checks.
84 *
85 * <p>
86 * More than one fast infoset document may be encoded to the
87 * {@link java.io.OutputStream}.
88 */
89 public class SAXDocumentSerializer extends Encoder implements FastInfosetWriter {
90 protected boolean _elementHasNamespaces = false;
91
92 protected boolean _charactersAsCDATA = false;
93
94 public SAXDocumentSerializer() {
95 }
96
97
98 public void reset() {
99 super.reset();
100
101 _elementHasNamespaces = false;
102 _charactersAsCDATA = false;
103 }
104
105 // ContentHandler
106
107 public final void startDocument() throws SAXException {
108 try {
109 reset();
110 encodeHeader(false);
111 encodeInitialVocabulary();
112 } catch (IOException e) {
113 throw new SAXException("startDocument", e);
114 }
115 }
116
117 public final void endDocument() throws SAXException {
118 try {
119 encodeDocumentTermination();
120 } catch (IOException e) {
121 throw new SAXException("endDocument", e);
122 }
123 }
124
125 public final void startPrefixMapping(String prefix, String uri) throws SAXException {
126 try {
127 if (_elementHasNamespaces == false) {
128 encodeTermination();
129
130 // Mark the current buffer position to flag attributes if necessary
131 mark();
132 _elementHasNamespaces = true;
133
134 // Write out Element byte with namespaces
135 write(EncodingConstants.ELEMENT | EncodingConstants.ELEMENT_NAMESPACES_FLAG);
136 }
137
138 encodeNamespaceAttribute(prefix, uri);
139 } catch (IOException e) {
140 throw new SAXException("startElement", e);
141 }
142 }
143
144 public final void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
145 // TODO consider using buffer for encoding of attributes, then pre-counting is not necessary
146 final int attributeCount = (atts != null && atts.getLength() > 0)
147 ? countAttributes(atts) : 0;
148 try {
149 if (_elementHasNamespaces) {
150 _elementHasNamespaces = false;
151
152 if (attributeCount > 0) {
153 // Flag the marked byte with attributes
154 _octetBuffer[_markIndex] |= EncodingConstants.ELEMENT_ATTRIBUTE_FLAG;
155 }
156 resetMark();
157
158 write(EncodingConstants.TERMINATOR);
159
160 _b = 0;
161 } else {
162 encodeTermination();
163
164 _b = EncodingConstants.ELEMENT;
165 if (attributeCount > 0) {
166 _b |= EncodingConstants.ELEMENT_ATTRIBUTE_FLAG;
167 }
168 }
169
170 encodeElement(namespaceURI, qName, localName);
171
172 if (attributeCount > 0) {
173 boolean addToTable;
174 String value;
175 if (atts instanceof EncodingAlgorithmAttributes) {
176 final EncodingAlgorithmAttributes eAtts = (EncodingAlgorithmAttributes)atts;
177 for (int i = 0; i < eAtts.getLength(); i++) {
178 if (encodeAttribute(atts.getURI(i), atts.getQName(i), atts.getLocalName(i))) {
179 final Object data = eAtts.getAlgorithmData(i);
180 // If data is null then there is no algorithm data
181 if (data == null) {
182 value = eAtts.getValue(i);
183 addToTable = (value.length() < attributeValueSizeConstraint) ? true : false;
184 encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable);
185 } else {
186 encodeNonIdentifyingStringOnFirstBit(eAtts.getAlgorithmURI(i),
187 eAtts.getAlgorithmIndex(i), data);
188 }
189 }
190 }
191 } else {
192 for (int i = 0; i < atts.getLength(); i++) {
193 if (encodeAttribute(atts.getURI(i), atts.getQName(i), atts.getLocalName(i))) {
194 value = atts.getValue(i);
195 addToTable = (value.length() < attributeValueSizeConstraint) ? true : false;
196 encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable);
197 }
198 }
199 }
200 _b = EncodingConstants.TERMINATOR;
201 _terminate = true;
202 }
203 } catch (IOException e) {
204 throw new SAXException("startElement", e);
205 } catch (FastInfosetException e) {
206 throw new SAXException("startElement", e);
207 }
208 }
209
210 public final int countAttributes(Attributes atts) {
211 // Count attributes ignoring any in the XMLNS namespace
212 // Note, such attributes may be produced when transforming from a DOM node
213 int count = 0;
214 for (int i = 0; i < atts.getLength(); i++) {
215 final String uri = atts.getURI(i);
216 if (uri == "http://www.w3.org/2000/xmlns/" || uri.equals("http://www.w3.org/2000/xmlns/")) {
217 continue;
218 }
219 count++;
220 }
221 return count;
222 }
223
224 public final void endElement(String namespaceURI, String localName, String qName) throws SAXException {
225 try {
226 encodeElementTermination();
227 } catch (IOException e) {
228 throw new SAXException("startElement", e);
229 }
230 }
231
232 public final void characters(char[] ch, int start, int length) throws SAXException {
233 if (length <= 0) {
234 return;
235 }
236
237 if (getIgnoreWhiteSpaceTextContent() &&
238 isWhiteSpace(ch, start, length)) return;
239
240 try {
241 encodeTermination();
242
243 if (!_charactersAsCDATA) {
244 encodeCharacters(ch, start, length);
245 } else {
246 encodeCIIBuiltInAlgorithmDataAsCDATA(ch, start, length);
247 }
248 } catch (IOException e) {
249 throw new SAXException(e);
250 } catch (FastInfosetException e) {
251 throw new SAXException(e);
252 }
253 }
254
255 public final void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
256 if (getIgnoreWhiteSpaceTextContent()) return;
257
258 characters(ch, start, length);
259 }
260
261 public final void processingInstruction(String target, String data) throws SAXException {
262 try {
263 if (getIgnoreProcesingInstructions()) return;
264
265 if (target == "") {
266 throw new SAXException(CommonResourceBundle.getInstance().
267 getString("message.processingInstructionTargetIsEmpty"));
268 }
269 encodeTermination();
270
271 encodeProcessingInstruction(target, data);
272 } catch (IOException e) {
273 throw new SAXException("processingInstruction", e);
274 }
275 }
276
277 public final void setDocumentLocator(org.xml.sax.Locator locator) {
278 }
279
280 public final void skippedEntity(String name) throws SAXException {
281 }
282
283
284
285 // LexicalHandler
286
287 public final void comment(char[] ch, int start, int length) throws SAXException {
288 try {
289 if (getIgnoreComments()) return;
290
291 encodeTermination();
292
293 encodeComment(ch, start, length);
294 } catch (IOException e) {
295 throw new SAXException("startElement", e);
296 }
297 }
298
299 public final void startCDATA() throws SAXException {
300 _charactersAsCDATA = true;
301 }
302
303 public final void endCDATA() throws SAXException {
304 _charactersAsCDATA = false;
305 }
306
307 public final void startDTD(String name, String publicId, String systemId) throws SAXException {
308 }
309
310 public final void endDTD() throws SAXException {
311 }
312
313 public final void startEntity(String name) throws SAXException {
314 }
315
316 public final void endEntity(String name) throws SAXException {
317 }
318
319
320 // EncodingAlgorithmContentHandler
321
322 public final void octets(String URI, int id, byte[] b, int start, int length) throws SAXException {
323 if (length <= 0) {
324 return;
325 }
326
327 try {
328 encodeTermination();
329
330 encodeNonIdentifyingStringOnThirdBit(URI, id, b, start, length);
331 } catch (IOException e) {
332 throw new SAXException(e);
333 } catch (FastInfosetException e) {
334 throw new SAXException(e);
335 }
336 }
337
338 public final void object(String URI, int id, Object data) throws SAXException {
339 try {
340 encodeTermination();
341
342 encodeNonIdentifyingStringOnThirdBit(URI, id, data);
343 } catch (IOException e) {
344 throw new SAXException(e);
345 } catch (FastInfosetException e) {
346 throw new SAXException(e);
347 }
348 }
349
350
351 // PrimitiveTypeContentHandler
352
353 public final void bytes(byte[] b, int start, int length) throws SAXException {
354 if (length <= 0) {
355 return;
356 }
357
358 try {
359 encodeTermination();
360
361 encodeCIIOctetAlgorithmData(EncodingAlgorithmIndexes.BASE64, b, start, length);
362 } catch (IOException e) {
363 throw new SAXException(e);
364 }
365 }
366
367 public final void shorts(short[] s, int start, int length) throws SAXException {
368 if (length <= 0) {
369 return;
370 }
371
372 try {
373 encodeTermination();
374
375 encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.SHORT, s, start, length);
376 } catch (IOException e) {
377 throw new SAXException(e);
378 } catch (FastInfosetException e) {
379 throw new SAXException(e);
380 }
381 }
382
383 public final void ints(int[] i, int start, int length) throws SAXException {
384 if (length <= 0) {
385 return;
386 }
387
388 try {
389 encodeTermination();
390
391 encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.INT, i, start, length);
392 } catch (IOException e) {
393 throw new SAXException(e);
394 } catch (FastInfosetException e) {
395 throw new SAXException(e);
396 }
397 }
398
399 public final void longs(long[] l, int start, int length) throws SAXException {
400 if (length <= 0) {
401 return;
402 }
403
404 try {
405 encodeTermination();
406
407 encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.LONG, l, start, length);
408 } catch (IOException e) {
409 throw new SAXException(e);
410 } catch (FastInfosetException e) {
411 throw new SAXException(e);
412 }
413 }
414
415 public final void booleans(boolean[] b, int start, int length) throws SAXException {
416 if (length <= 0) {
417 return;
418 }
419
420 try {
421 encodeTermination();
422
423 encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.BOOLEAN, b, start, length);
424 } catch (IOException e) {
425 throw new SAXException(e);
426 } catch (FastInfosetException e) {
427 throw new SAXException(e);
428 }
429 }
430
431 public final void floats(float[] f, int start, int length) throws SAXException {
432 if (length <= 0) {
433 return;
434 }
435
436 try {
437 encodeTermination();
438
439 encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.FLOAT, f, start, length);
440 } catch (IOException e) {
441 throw new SAXException(e);
442 } catch (FastInfosetException e) {
443 throw new SAXException(e);
444 }
445 }
446
447 public final void doubles(double[] d, int start, int length) throws SAXException {
448 if (length <= 0) {
449 return;
450 }
451
452 try {
453 encodeTermination();
454
455 encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.DOUBLE, d, start, length);
456 } catch (IOException e) {
457 throw new SAXException(e);
458 } catch (FastInfosetException e) {
459 throw new SAXException(e);
460 }
461 }
462
463 public void uuids(long[] msblsb, int start, int length) throws SAXException {
464 if (length <= 0) {
465 return;
466 }
467
468 try {
469 encodeTermination();
470
471 encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.UUID, msblsb, start, length);
472 } catch (IOException e) {
473 throw new SAXException(e);
474 } catch (FastInfosetException e) {
475 throw new SAXException(e);
476 }
477 }
478
479
480 // RestrictedAlphabetContentHandler
481
482 public void numericCharacters(char ch[], int start, int length) throws SAXException {
483 if (length <= 0) {
484 return;
485 }
486
487 try {
488 encodeTermination();
489
490 encodeFourBitCharacters(RestrictedAlphabet.NUMERIC_CHARACTERS_INDEX, EncodingConstants.NUMERIC_CHARACTERS_TABLE, ch, start, length);
491 } catch (IOException e) {
492 throw new SAXException(e);
493 } catch (FastInfosetException e) {
494 throw new SAXException(e);
495 }
496 }
497
498 public void dateTimeCharacters(char ch[], int start, int length) throws SAXException {
499 if (length <= 0) {
500 return;
501 }
502
503 try {
504 encodeTermination();
505
506 encodeFourBitCharacters(RestrictedAlphabet.DATE_TIME_CHARACTERS_INDEX, EncodingConstants.DATE_TIME_CHARACTERS_TABLE, ch, start, length);
507 } catch (IOException e) {
508 throw new SAXException(e);
509 } catch (FastInfosetException e) {
510 throw new SAXException(e);
511 }
512 }
513
514 public void alphabetCharacters(String alphabet, char ch[], int start, int length) throws SAXException {
515 if (length <= 0) {
516 return;
517 }
518
519 try {
520 encodeTermination();
521
522 encodeAlphabetCharacters(alphabet, ch, start, length);
523 } catch (IOException e) {
524 throw new SAXException(e);
525 } catch (FastInfosetException e) {
526 throw new SAXException(e);
527 }
528 }
529
530
531
532 protected final void encodeElement(String namespaceURI, String qName, String localName) throws IOException {
533 LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(qName);
534 if (entry._valueIndex > 0) {
535 QualifiedName[] names = entry._value;
536 for (int i = 0; i < entry._valueIndex; i++) {
537 if ((namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
538 encodeNonZeroIntegerOnThirdBit(names[i].index);
539 return;
540 }
541 }
542 }
543
544 encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, getPrefixFromQualifiedName(qName),
545 localName, entry);
546 }
547
548 protected final boolean encodeAttribute(String namespaceURI, String qName, String localName) throws IOException {
549 LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(qName);
550 if (entry._valueIndex > 0) {
551 QualifiedName[] names = entry._value;
552 for (int i = 0; i < entry._valueIndex; i++) {
553 if ((namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) {
554 encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index);
555 return true;
556 }
557 }
558 }
559
560 return encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, getPrefixFromQualifiedName(qName),
561 localName, entry);
562 }
563 }