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 }