001    package groovy.xml.streamingmarkupsupport;
002    /*
003    
004    Copyright 2004 (C) John Wilson. All Rights Reserved.
005    
006    Redistribution and use of this software and associated documentation
007    ("Software"), with or without modification, are permitted provided
008    that the following conditions are met:
009    
010    1. Redistributions of source code must retain copyright
011       statements and notices.  Redistributions must also contain a
012       copy of this document.
013    
014    2. Redistributions in binary form must reproduce the
015       above copyright notice, this list of conditions and the
016       following disclaimer in the documentation and/or other
017       materials provided with the distribution.
018    
019    3. The name "groovy" must not be used to endorse or promote
020       products derived from this Software without prior written
021       permission of The Codehaus.  For written permission,
022       please contact info@codehaus.org.
023    
024    4. Products derived from this Software may not be called "groovy"
025       nor may "groovy" appear in their names without prior written
026       permission of The Codehaus. "groovy" is a registered
027       trademark of The Codehaus.
028    
029    5. Due credit should be given to The Codehaus -
030       http://groovy.codehaus.org/
031    
032    THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033    ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034    NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
036    THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043    OF THE POSSIBILITY OF SUCH DAMAGE.
044    
045    */
046    
047    import java.io.IOException;
048    import java.io.OutputStreamWriter;
049    import java.io.Writer;
050    import java.nio.charset.Charset;
051    import java.nio.charset.CharsetEncoder;
052    
053    public class StreamingMarkupWriter extends Writer {
054            protected final Writer writer;
055        protected final String encoding;
056        protected final CharsetEncoder encoder;
057            private final Writer bodyWriter =  new Writer() {
058                                                                                            /* (non-Javadoc)
059                                                                                             * @see java.io.Writer#close()
060                                                                                             */
061                                                                                            public void close() throws IOException {
062                                                                                                    StreamingMarkupWriter.this.close();
063                                                                                            }
064                                                                                            
065                                                                                            /* (non-Javadoc)
066                                                                                             * @see java.io.Writer#flush()
067                                                                                             */
068                                                                                            public void flush() throws IOException {
069                                                                                                    StreamingMarkupWriter.this.flush();
070                                                                                            }
071                    
072                                                                                            /* (non-Javadoc)
073                                                                                             * @see java.io.Writer#write(int)
074                                                                                             */
075                                                                                            public void write(final int c) throws IOException {
076                                                                                                    if (!StreamingMarkupWriter.this.encoder.canEncode((char)c)) {
077                                                                                                            StreamingMarkupWriter.this.writer.write("&#x");
078                                                                                                            StreamingMarkupWriter.this.writer.write(Integer.toHexString(c));
079                                                                                                            StreamingMarkupWriter.this.writer.write(';');
080                                                                                                    } else if (c == '<') {
081                                                                                                            StreamingMarkupWriter.this.writer.write("&lt;");
082                                                                                                    } else if (c == '>') {
083                                                                                                            StreamingMarkupWriter.this.writer.write("&gt;");
084                                                                                                    } else if (c == '&') {
085                                                                                                            StreamingMarkupWriter.this.writer.write("&amp;");
086                                                                                                    } else {
087                                                                                                            StreamingMarkupWriter.this.writer.write(c);
088                                                                                                    }
089                                                                                            }
090                                                                                            
091                                                                                            /* (non-Javadoc)
092                                                                                             * @see java.io.Writer#write(char[], int, int)
093                                                                                             */
094                                                                                            public void write(final char[] cbuf, int off, int len) throws IOException {
095                                                                                                    while (len-- > 0){
096                                                                                                            write(cbuf[off++]);
097                                                                                                    }
098                                                                                            }
099                                                                                            
100                                                                                            public Writer attributeValue() {
101                                                                                                    return StreamingMarkupWriter.this.attributeWriter;
102                                                                                            }
103                                                                                            
104                                                                                            public Writer bodyText() {
105                                                                                                    return bodyWriter;
106                                                                                            }
107                                                                                            
108                                                                                            public Writer unescaped() {
109                                                                                                    return StreamingMarkupWriter.this;
110                                                                                            }
111                                                                                    };
112            
113            private final Writer attributeWriter =  new Writer() {
114                                                                                                    /* (non-Javadoc)
115                                                                                                     * @see java.io.Writer#close()
116                                                                                                     */
117                                                                                                    public void close() throws IOException {
118                                                                                                            StreamingMarkupWriter.this.close();
119                                                                                                    }
120                                                                                    
121                                                                                                    /* (non-Javadoc)
122                                                                                                     * @see java.io.Writer#flush()
123                                                                                                     */
124                                                                                                    public void flush() throws IOException {
125                                                                                                            StreamingMarkupWriter.this.flush();
126                                                                                                    }
127                    
128                                                                                                    /* (non-Javadoc)
129                                                                                                     * @see java.io.Writer#write(int)
130                                                                                                     */
131                                                                                                    public void write(final int c) throws IOException {
132                                                                                                            if (c == '\'') {
133                                                                                                                    StreamingMarkupWriter.this.writer.write("&apos;");
134                                                                                                            } else {
135                                                                                                                    StreamingMarkupWriter.this.bodyWriter.write(c);
136                                                                                                            }
137                                                                                                    }
138                                                                                                    
139                                                                                                    /* (non-Javadoc)
140                                                                                                     * @see java.io.Writer#write(char[], int, int)
141                                                                                                     */
142                                                                                                    public void write(final char[] cbuf, int off, int len) throws IOException {
143                                                                                                            while (len-- > 0){
144                                                                                                                    write(cbuf[off++]);
145                                                                                                            }
146                                                                                                    }
147                                                                                                    
148                                                                                                    public Writer attributeValue() {
149                                                                                                            return attributeWriter;
150                                                                                                    }
151                                                                                                    
152                                                                                                    public Writer bodyText() {
153                                                                                                            return StreamingMarkupWriter.this.bodyWriter;
154                                                                                                    }
155                                                                                                    
156                                                                                                    public Writer unescaped() {
157                                                                                                            return StreamingMarkupWriter.this;
158                                                                                                    }
159                                                                                            };
160    
161        public StreamingMarkupWriter(final Writer writer, final String encoding) {
162            this.writer = writer;
163            
164            if (encoding != null) {
165                this.encoding = encoding;
166            } else if (writer instanceof OutputStreamWriter) {
167                this.encoding = ((OutputStreamWriter)writer).getEncoding();
168            } else {
169                this.encoding = "US-ASCII";
170            }
171            
172            this.encoder = Charset.forName(this.encoding).newEncoder();
173        }
174        
175        public StreamingMarkupWriter(final Writer writer) {
176            this(writer, null);
177        }
178        
179        /* (non-Javadoc)
180         * @see java.io.Writer#close()
181         */
182        public void close() throws IOException {
183            this.writer.close();
184        }
185        
186        /* (non-Javadoc)
187         * @see java.io.Writer#flush()
188         */
189        public void flush() throws IOException {
190            this.writer.flush();
191        }
192        
193        /* (non-Javadoc)
194         * @see java.io.Writer#write(int)
195         */
196        public void write(final int c) throws IOException {
197            if (!this.encoder.canEncode((char)c)) {
198                this.writer.write("&#x");
199                this.writer.write(Integer.toHexString(c));
200                this.writer.write(';');
201            } else {
202                this.writer.write(c);
203            }
204        }
205        
206        /* (non-Javadoc)
207         * @see java.io.Writer#write(char[], int, int)
208         */
209        public void write(final char[] cbuf, int off, int len) throws IOException {
210            while (len-- > 0){
211                write(cbuf[off++]);
212            }
213        }
214        
215        public Writer attributeValue() {
216            return this.attributeWriter;
217        }
218        
219        public Writer bodyText() {
220            return this.bodyWriter;
221        }
222        
223        public Writer unescaped() {
224            return this;
225        }
226        
227        public String getEncoding() {
228            return this.encoding;
229        }
230    }