001 /**
002 *
003 * Copyright 2006 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 /*
019 * This code has been borrowed from the Apache Xerces project. We're copying the code to
020 * keep from adding a dependency on Xerces in the Geronimo kernel.
021 */
022 package org.apache.geronimo.system.configuration;
023
024 import java.io.ByteArrayOutputStream;
025 import java.io.IOException;
026 import java.io.OutputStreamWriter;
027 import java.io.Writer;
028
029 /**
030 * This class represents an encoding.
031 *
032 * @version $Id: SieveEncodingInfo.java 410741 2006-06-01 04:35:48Z jsisson $
033 */
034 public class SieveEncodingInfo extends EncodingInfo {
035
036 BAOutputStream checkerStream = null;
037 Writer checkerWriter = null;
038 String dangerChars = null;
039
040 /**
041 * Creates new <code>SeiveEncodingInfo</code> instance.
042 *
043 * @param dangers A sorted characters that are always printed as character references.
044 */
045 public SieveEncodingInfo(String mimeName, String javaName,
046 int lastPrintable, String dangers) {
047 super(mimeName, javaName, lastPrintable);
048 this.dangerChars = dangers;
049 }
050
051 /**
052 * Creates new <code>SeiveEncodingInfo</code> instance.
053 */
054 public SieveEncodingInfo(String mimeName, int lastPrintable) {
055 this(mimeName, mimeName, lastPrintable, null);
056 }
057
058 /**
059 * Checks whether the specified character is printable or not.
060 *
061 * @param ch a code point (0-0x10ffff)
062 */
063 public boolean isPrintable(int ch) {
064 if (this.dangerChars != null && ch <= 0xffff) {
065 /**
066 * Searches this.dangerChars for ch.
067 * TODO: Use binary search.
068 */
069 if (this.dangerChars.indexOf(ch) >= 0)
070 return false;
071 }
072
073 if (ch <= this.lastPrintable)
074 return true;
075
076 boolean printable = true;
077 synchronized (this) {
078 try {
079 if (this.checkerWriter == null) {
080 this.checkerStream = new BAOutputStream(10);
081 this.checkerWriter = new OutputStreamWriter(this.checkerStream, this.javaName);
082 }
083
084 if (ch > 0xffff) {
085 this.checkerWriter.write(((ch-0x10000)>>10)+0xd800);
086 this.checkerWriter.write(((ch-0x10000)&0x3ff)+0xdc00);
087 byte[] result = this.checkerStream.getBuffer();
088 if (this.checkerStream.size() == 2 && result[0] == '?' && result[1] == '?')
089 printable = false;
090 } else {
091 this.checkerWriter.write(ch);
092 this.checkerWriter.flush();
093 byte[] result = this.checkerStream.getBuffer();
094 if (this.checkerStream.size() == 1 && result[0] == '?')
095 printable = false;
096 }
097 this.checkerStream.reset();
098 } catch (IOException ioe) {
099 printable = false;
100 }
101 }
102
103 return printable;
104 }
105
106 /**
107 * Why don't we use the original ByteArrayOutputStream?
108 * - Because the toByteArray() method of the ByteArrayOutputStream
109 * creates new byte[] instances for each call.
110 */
111 static class BAOutputStream extends ByteArrayOutputStream {
112 BAOutputStream() {
113 super();
114 }
115
116 BAOutputStream(int size) {
117 super(size);
118 }
119
120 byte[] getBuffer() {
121 return this.buf;
122 }
123 }
124
125 }