001: /*
002: Copyright (c) 2004, Dennis M. Sosnoski.
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.runtime.impl;
030:
031: import java.io.IOException;
032: import java.io.Writer;
033:
034: import org.jibx.runtime.ICharacterEscaper;
035:
036: /**
037: * Handler for writing ASCII output stream. This code is specifically for XML
038: * 1.0 and would require changes for XML 1.1 (to handle the added legal
039: * characters, rather than throwing an exception).
040: *
041: * @author Dennis M. Sosnoski
042: * @version 1.0
043: */
044:
045: public class USASCIIEscaper implements ICharacterEscaper {
046: /** Singleton instance of class. */
047: private static final USASCIIEscaper s_instance = new USASCIIEscaper();
048:
049: /**
050: * Private constructor to prevent external creation.
051: */
052:
053: private USASCIIEscaper() {
054: }
055:
056: /**
057: * Write attribute value with character entity substitutions. This assumes
058: * that attributes use the regular quote ('"') delimitor.
059: *
060: * @param text attribute value text
061: * @param writer sink for output text
062: * @throws IOException on error writing to document
063: */
064:
065: public void writeAttribute(String text, Writer writer)
066: throws IOException {
067: int mark = 0;
068: for (int i = 0; i < text.length(); i++) {
069: char chr = text.charAt(i);
070: if (chr == '"') {
071: writer.write(text, mark, i - mark);
072: mark = i + 1;
073: writer.write(""");
074: } else if (chr == '&') {
075: writer.write(text, mark, i - mark);
076: mark = i + 1;
077: writer.write("&");
078: } else if (chr == '<') {
079: writer.write(text, mark, i - mark);
080: mark = i + 1;
081: writer.write("<");
082: } else if (chr == '>' && i > 2 && text.charAt(i - 1) == ']'
083: && text.charAt(i - 2) == ']') {
084: writer.write(text, mark, i - mark - 2);
085: mark = i + 1;
086: writer.write("]]>");
087: } else if (chr < 0x20) {
088: if (chr != 0x9 && chr != 0xA && chr != 0xD) {
089: throw new IOException("Illegal character code 0x"
090: + Integer.toHexString(chr)
091: + " in attribute value text");
092: }
093: } else if (chr > 0x7F) {
094: writer.write(text, mark, i - mark);
095: mark = i + 1;
096: if (chr > 0xD7FF
097: && (chr < 0xE000 || chr == 0xFFFE
098: || chr == 0xFFFF || chr > 0x10FFFF)) {
099: throw new IOException("Illegal character code 0x"
100: + Integer.toHexString(chr)
101: + " in attribute value text");
102: }
103: writer.write("&#x");
104: writer.write(Integer.toHexString(chr));
105: writer.write(';');
106: }
107: }
108: writer.write(text, mark, text.length() - mark);
109: }
110:
111: /**
112: * Write content value with character entity substitutions.
113: *
114: * @param text content value text
115: * @param writer sink for output text
116: * @throws IOException on error writing to document
117: */
118:
119: public void writeContent(String text, Writer writer)
120: throws IOException {
121: int mark = 0;
122: for (int i = 0; i < text.length(); i++) {
123: char chr = text.charAt(i);
124: if (chr == '&') {
125: writer.write(text, mark, i - mark);
126: mark = i + 1;
127: writer.write("&");
128: } else if (chr == '<') {
129: writer.write(text, mark, i - mark);
130: mark = i + 1;
131: writer.write("<");
132: } else if (chr == '>' && i > 2 && text.charAt(i - 1) == ']'
133: && text.charAt(i - 2) == ']') {
134: writer.write(text, mark, i - mark - 2);
135: mark = i + 1;
136: writer.write("]]>");
137: } else if (chr < 0x20) {
138: if (chr != 0x9 && chr != 0xA && chr != 0xD) {
139: throw new IOException("Illegal character code 0x"
140: + Integer.toHexString(chr)
141: + " in content text");
142: }
143: } else if (chr > 0x7F) {
144: writer.write(text, mark, i - mark);
145: mark = i + 1;
146: if (chr > 0xD7FF
147: && (chr < 0xE000 || chr == 0xFFFE
148: || chr == 0xFFFF || chr > 0x10FFFF)) {
149: throw new IOException("Illegal character code 0x"
150: + Integer.toHexString(chr)
151: + " in content text");
152: }
153: writer.write("&#x");
154: writer.write(Integer.toHexString(chr));
155: writer.write(';');
156: }
157: }
158: writer.write(text, mark, text.length() - mark);
159: }
160:
161: /**
162: * Write CDATA to document. This writes the beginning and ending sequences
163: * for a CDATA section as well as the actual text, verifying that only
164: * characters allowed by the encoding are included in the text.
165: *
166: * @param text content value text
167: * @param writer sink for output text
168: * @throws IOException on error writing to document
169: */
170:
171: public void writeCData(String text, Writer writer)
172: throws IOException {
173: writer.write("<![CDATA[");
174: for (int i = 0; i < text.length(); i++) {
175: char chr = text.charAt(i);
176: if (chr == '>' && i > 2 && text.charAt(i - 1) == ']'
177: && text.charAt(i - 2) == ']') {
178: throw new IOException(
179: "Sequence \"]]>\" is not allowed "
180: + "within CDATA section text");
181: } else if (chr < 0x20) {
182: if (chr != 0x9 && chr != 0xA && chr != 0xD) {
183: throw new IOException("Illegal character code 0x"
184: + Integer.toHexString(chr)
185: + " in CDATA section");
186: }
187: } else if (chr >= 0x80) {
188: throw new IOException("Character code 0x"
189: + Integer.toHexString(chr)
190: + " not supported by encoding in CDATA section");
191: }
192: }
193: writer.write(text);
194: writer.write("]]>");
195: }
196:
197: /**
198: * Get instance of escaper.
199: *
200: * @return escaper instance
201: */
202:
203: public static ICharacterEscaper getInstance() {
204: return s_instance;
205: }
206: }
|