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 ISO88591Escaper implements ICharacterEscaper {
046: /** Singleton instance of class. */
047: private static final ISO88591Escaper s_instance = new ISO88591Escaper();
048:
049: /**
050: * Private constructor to prevent external creation.
051: */
052:
053: private ISO88591Escaper() {
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 >= 0x80) {
094: if (chr < 0xA0 || chr > 0xFF) {
095: writer.write(text, mark, i - mark);
096: mark = i + 1;
097: if (chr > 0xD7FF
098: && (chr < 0xE000 || chr == 0xFFFE
099: || chr == 0xFFF || chr > 0x10FFFF)) {
100: throw new IOException(
101: "Illegal character code 0x"
102: + Integer.toHexString(chr)
103: + " in attribute value text");
104: }
105: writer.write("&#x");
106: writer.write(Integer.toHexString(chr));
107: writer.write(';');
108: }
109: }
110: }
111: writer.write(text, mark, text.length() - mark);
112: }
113:
114: /**
115: * Write content value with character entity substitutions.
116: *
117: * @param text content value text
118: * @param writer sink for output text
119: * @throws IOException on error writing to document
120: */
121:
122: public void writeContent(String text, Writer writer)
123: throws IOException {
124: int mark = 0;
125: for (int i = 0; i < text.length(); i++) {
126: char chr = text.charAt(i);
127: if (chr == '&') {
128: writer.write(text, mark, i - mark);
129: mark = i + 1;
130: writer.write("&");
131: } else if (chr == '<') {
132: writer.write(text, mark, i - mark);
133: mark = i + 1;
134: writer.write("<");
135: } else if (chr == '>' && i > 2 && text.charAt(i - 1) == ']'
136: && text.charAt(i - 2) == ']') {
137: writer.write(text, mark, i - mark - 2);
138: mark = i + 1;
139: writer.write("]]>");
140: } else if (chr < 0x20) {
141: if (chr != 0x9 && chr != 0xA && chr != 0xD) {
142: throw new IOException("Illegal character code 0x"
143: + Integer.toHexString(chr)
144: + " in content text");
145: }
146: } else if (chr >= 0x80) {
147: if (chr < 0xA0 || chr > 0xFF) {
148: writer.write(text, mark, i - mark);
149: mark = i + 1;
150: if (chr > 0xD7FF
151: && (chr < 0xE000 || chr == 0xFFFE
152: || chr == 0xFFF || chr > 0x10FFFF)) {
153: throw new IOException(
154: "Illegal character code 0x"
155: + Integer.toHexString(chr)
156: + " in content text");
157: }
158: writer.write("&#x");
159: writer.write(Integer.toHexString(chr));
160: writer.write(';');
161: }
162: }
163: }
164: writer.write(text, mark, text.length() - mark);
165: }
166:
167: /**
168: * Write CDATA to document. This writes the beginning and ending sequences
169: * for a CDATA section as well as the actual text, verifying that only
170: * characters allowed by the encoding are included in the text.
171: *
172: * @param text content value text
173: * @param writer sink for output text
174: * @throws IOException on error writing to document
175: */
176:
177: public void writeCData(String text, Writer writer)
178: throws IOException {
179: writer.write("<![CDATA[");
180: for (int i = 0; i < text.length(); i++) {
181: char chr = text.charAt(i);
182: if (chr == '>' && i > 2 && text.charAt(i - 1) == ']'
183: && text.charAt(i - 2) == ']') {
184: throw new IOException(
185: "Sequence \"]]>\" is not allowed "
186: + "within CDATA section text");
187: } else if (chr < 0x20) {
188: if (chr != 0x9 && chr != 0xA && chr != 0xD) {
189: throw new IOException("Illegal character code 0x"
190: + Integer.toHexString(chr)
191: + " in CDATA section");
192: }
193: } else if (chr >= 0x80 && (chr < 0xA0 || chr > 0xFF)) {
194: throw new IOException("Character code 0x"
195: + Integer.toHexString(chr)
196: + " not supported by encoding in CDATA section");
197: }
198: }
199: writer.write(text);
200: writer.write("]]>");
201: }
202:
203: /**
204: * Get instance of escaper.
205: *
206: * @return escaper instance
207: */
208:
209: public static ICharacterEscaper getInstance() {
210: return s_instance;
211: }
212: }
|