View Javadoc

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   * This code has been borrowed from the Apache Xerces project. We're copying the code to
20   * keep from adding a dependency on Xerces in the Geronimo kernel.
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 }