1 /**
2 *
3 * Copyright 2006 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19
20
21
22 package org.apache.geronimo.system.configuration;
23
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.io.OutputStreamWriter;
27 import java.io.Writer;
28
29 /**
30 * This class represents an encoding.
31 *
32 * @version $Id: SieveEncodingInfo.java 410741 2006-06-01 04:35:48Z jsisson $
33 */
34 public class SieveEncodingInfo extends EncodingInfo {
35
36 BAOutputStream checkerStream = null;
37 Writer checkerWriter = null;
38 String dangerChars = null;
39
40 /**
41 * Creates new <code>SeiveEncodingInfo</code> instance.
42 *
43 * @param dangers A sorted characters that are always printed as character references.
44 */
45 public SieveEncodingInfo(String mimeName, String javaName,
46 int lastPrintable, String dangers) {
47 super(mimeName, javaName, lastPrintable);
48 this.dangerChars = dangers;
49 }
50
51 /**
52 * Creates new <code>SeiveEncodingInfo</code> instance.
53 */
54 public SieveEncodingInfo(String mimeName, int lastPrintable) {
55 this(mimeName, mimeName, lastPrintable, null);
56 }
57
58 /**
59 * Checks whether the specified character is printable or not.
60 *
61 * @param ch a code point (0-0x10ffff)
62 */
63 public boolean isPrintable(int ch) {
64 if (this.dangerChars != null && ch <= 0xffff) {
65 /**
66 * Searches this.dangerChars for ch.
67 * TODO: Use binary search.
68 */
69 if (this.dangerChars.indexOf(ch) >= 0)
70 return false;
71 }
72
73 if (ch <= this.lastPrintable)
74 return true;
75
76 boolean printable = true;
77 synchronized (this) {
78 try {
79 if (this.checkerWriter == null) {
80 this.checkerStream = new BAOutputStream(10);
81 this.checkerWriter = new OutputStreamWriter(this.checkerStream, this.javaName);
82 }
83
84 if (ch > 0xffff) {
85 this.checkerWriter.write(((ch-0x10000)>>10)+0xd800);
86 this.checkerWriter.write(((ch-0x10000)&0x3ff)+0xdc00);
87 byte[] result = this.checkerStream.getBuffer();
88 if (this.checkerStream.size() == 2 && result[0] == '?' && result[1] == '?')
89 printable = false;
90 } else {
91 this.checkerWriter.write(ch);
92 this.checkerWriter.flush();
93 byte[] result = this.checkerStream.getBuffer();
94 if (this.checkerStream.size() == 1 && result[0] == '?')
95 printable = false;
96 }
97 this.checkerStream.reset();
98 } catch (IOException ioe) {
99 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 }