1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.jdtaus.banking.charsets.spi;
22
23 import java.nio.ByteBuffer;
24 import java.nio.CharBuffer;
25 import java.nio.charset.Charset;
26 import java.nio.charset.CharsetDecoder;
27 import java.nio.charset.CharsetEncoder;
28 import java.nio.charset.CoderResult;
29 import java.nio.charset.CodingErrorAction;
30 import java.nio.charset.spi.CharsetProvider;
31 import java.util.Iterator;
32 import java.util.NoSuchElementException;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class DIN66003CharsetProvider extends CharsetProvider
50 {
51
52
53 static final String COMMON_NAME = "DIN_66003";
54
55
56 static final String[] ALIAS_NAMES =
57 {
58 "iso-ir-21", "de", "iso646-de", "csiso21german"
59 };
60
61
62 static final String[] SUPPORTED_NAMES =
63 {
64 COMMON_NAME.toLowerCase(), "iso-ir-21", "de", "iso646-de", "csiso21german"
65 };
66
67 static final char[] BYTE_TO_CHAR = new char[ 0xFF ];
68
69 static final byte[] CHAR_TO_BYTE = new byte[ 0xFF ];
70
71 static
72 {
73 for ( int i = 0x7F; i >= 0; i-- )
74 {
75 CHAR_TO_BYTE[i] = (byte) i;
76 BYTE_TO_CHAR[i] = (char) i;
77 }
78
79 CHAR_TO_BYTE['\u00A7'] = (byte) 0x40;
80 CHAR_TO_BYTE['\u00C4'] = (byte) 0x5B;
81 CHAR_TO_BYTE['\u00D6'] = (byte) 0x5C;
82 CHAR_TO_BYTE['\u00DC'] = (byte) 0x5D;
83 CHAR_TO_BYTE['\u00E4'] = (byte) 0x7B;
84 CHAR_TO_BYTE['\u00F6'] = (byte) 0x7C;
85 CHAR_TO_BYTE['\u00FC'] = (byte) 0x7D;
86 CHAR_TO_BYTE['\u00DF'] = (byte) 0x7E;
87
88 BYTE_TO_CHAR[0x40] = '\u00A7';
89 BYTE_TO_CHAR[0x5B] = '\u00C4';
90 BYTE_TO_CHAR[0x5C] = '\u00D6';
91 BYTE_TO_CHAR[0x5D] = '\u00DC';
92 BYTE_TO_CHAR[0x7B] = '\u00E4';
93 BYTE_TO_CHAR[0x7C] = '\u00F6';
94 BYTE_TO_CHAR[0x7D] = '\u00FC';
95 BYTE_TO_CHAR[0x7E] = '\u00DF';
96 }
97
98
99 public DIN66003CharsetProvider()
100 {
101 super();
102 }
103
104 public Charset charsetForName( final String charsetName )
105 {
106 Charset ret = null;
107
108 if ( charsetName != null )
109 {
110 final String lower = charsetName.toLowerCase();
111 for ( int i = 0; i < SUPPORTED_NAMES.length; i++ )
112 {
113 if ( SUPPORTED_NAMES[i].equals( lower ) )
114 {
115 ret = new DIN66003Charset();
116 break;
117 }
118 }
119 }
120
121 return ret;
122 }
123
124 public Iterator charsets()
125 {
126 return new Iterator()
127 {
128
129 private boolean hasNext = true;
130
131 public boolean hasNext()
132 {
133 return this.hasNext;
134 }
135
136 public Object next()
137 {
138 if ( this.hasNext )
139 {
140 this.hasNext = false;
141 return new DIN66003Charset();
142 }
143 else
144 {
145 throw new NoSuchElementException();
146 }
147 }
148
149 public void remove()
150 {
151 throw new UnsupportedOperationException();
152 }
153
154 };
155 }
156
157 }
158
159
160 class DIN66003Charset extends Charset
161 {
162
163 public DIN66003Charset()
164 {
165 super( DIN66003CharsetProvider.COMMON_NAME, DIN66003CharsetProvider.ALIAS_NAMES );
166 }
167
168 public CharsetEncoder newEncoder()
169 {
170 return new DIN66003CharsetEncoder( this );
171 }
172
173 public CharsetDecoder newDecoder()
174 {
175 return new DIN66003CharsetDecoder( this );
176 }
177
178 public boolean contains( final Charset charset )
179 {
180 return false;
181 }
182
183 static boolean isCharacterSupported( final char c )
184 {
185 return ( c >= 0x00 && c <= 0x3F ) || ( c >= 0x41 && c <= 0x5A ) || ( c >= 0x5F && c <= 0x7A ) ||
186 c == '\u00A7' || c == '\u00C4' || c == '\u00D6' || c == '\u00DC' || c == '\u00E4' || c == '\u00F6' ||
187 c == '\u00FC' || c == '\u00DF';
188
189 }
190
191 }
192
193 class DIN66003CharsetEncoder extends CharsetEncoder
194 {
195
196 private final char[] charBuf = new char[ 65536 ];
197
198 DIN66003CharsetEncoder( final Charset charset )
199 {
200 super( charset, 1f, 1f );
201 this.onUnmappableCharacter( CodingErrorAction.REPLACE );
202 }
203
204 protected CoderResult encodeLoop( final CharBuffer in, final ByteBuffer buf )
205 {
206 if ( in.hasArray() && buf.hasArray() )
207 {
208 return encodeLoopArray( in, buf );
209 }
210
211 while ( in.hasRemaining() )
212 {
213 in.mark();
214
215 final int len;
216 if ( in.remaining() < this.charBuf.length )
217 {
218 len = in.remaining();
219 in.get( this.charBuf, 0, in.remaining() );
220 }
221 else
222 {
223 in.get( this.charBuf, 0, this.charBuf.length );
224 len = this.charBuf.length;
225 }
226
227 for ( int i = 0; i < len; i++ )
228 {
229 if ( !buf.hasRemaining() )
230 {
231 in.reset();
232 in.position( in.position() + i );
233 return CoderResult.OVERFLOW;
234 }
235
236 if ( !DIN66003Charset.isCharacterSupported( this.charBuf[i] ) )
237 {
238 in.reset();
239 in.position( in.position() + i );
240 return CoderResult.unmappableForLength( 1 );
241 }
242
243 buf.put( DIN66003CharsetProvider.CHAR_TO_BYTE[this.charBuf[i]] );
244 }
245 }
246
247 return CoderResult.UNDERFLOW;
248 }
249
250 private static CoderResult encodeLoopArray( final CharBuffer in, final ByteBuffer buf )
251 {
252 final int len = in.remaining();
253 for ( int i = 0; i < len; i++, in.position( in.position() + 1 ), buf.position( buf.position() + 1 ) )
254 {
255 if ( !buf.hasRemaining() )
256 {
257 return CoderResult.OVERFLOW;
258 }
259
260 if ( !DIN66003Charset.isCharacterSupported( in.array()[in.position() + in.arrayOffset()] ) )
261 {
262 return CoderResult.unmappableForLength( 1 );
263 }
264
265 buf.array()[buf.position() + buf.arrayOffset()] =
266 DIN66003CharsetProvider.CHAR_TO_BYTE[in.array()[in.position() + in.arrayOffset()]];
267
268 }
269
270 return CoderResult.UNDERFLOW;
271 }
272
273 }
274
275 class DIN66003CharsetDecoder extends CharsetDecoder
276 {
277
278 private final byte[] byteBuf = new byte[ 65536 ];
279
280 DIN66003CharsetDecoder( final Charset charset )
281 {
282 super( charset, 1f, 1f );
283 this.onUnmappableCharacter( CodingErrorAction.REPLACE );
284 }
285
286 protected CoderResult decodeLoop( final ByteBuffer in, final CharBuffer buf )
287 {
288 if ( in.hasArray() && buf.hasArray() )
289 {
290 return decodeLoopArray( in, buf );
291 }
292
293 while ( in.hasRemaining() )
294 {
295 in.mark();
296
297 final int len;
298 if ( in.remaining() < this.byteBuf.length )
299 {
300 len = in.remaining();
301 in.get( this.byteBuf, 0, in.remaining() );
302 }
303 else
304 {
305 in.get( this.byteBuf, 0, this.byteBuf.length );
306 len = this.byteBuf.length;
307 }
308
309 for ( int i = 0; i < len; i++ )
310 {
311 if ( !buf.hasRemaining() )
312 {
313 in.reset();
314 in.position( in.position() + i );
315 return CoderResult.OVERFLOW;
316 }
317
318 if ( ( this.byteBuf[i] & 0xFF ) < 0x00 || ( this.byteBuf[i] & 0xFF ) > 0x7F )
319 {
320 in.reset();
321 in.position( in.position() + i );
322 return CoderResult.unmappableForLength( 1 );
323 }
324
325 buf.put( DIN66003CharsetProvider.BYTE_TO_CHAR[this.byteBuf[i] & 0xFF] );
326 }
327 }
328
329 return CoderResult.UNDERFLOW;
330 }
331
332 private static CoderResult decodeLoopArray( final ByteBuffer in, final CharBuffer buf )
333 {
334 final int len = in.remaining();
335 for ( int i = 0; i < len; i++, in.position( in.position() + 1 ), buf.position( buf.position() + 1 ) )
336 {
337 if ( !buf.hasRemaining() )
338 {
339 return CoderResult.OVERFLOW;
340 }
341
342 if ( ( in.array()[in.position() + in.arrayOffset()] & 0xFF ) < 0x00 ||
343 ( in.array()[in.position() + in.arrayOffset()] & 0xFF ) > 0x7F )
344 {
345 return CoderResult.unmappableForLength( 1 );
346 }
347
348 buf.array()[buf.position() + buf.arrayOffset()] =
349 DIN66003CharsetProvider.BYTE_TO_CHAR[in.array()[in.position() + in.arrayOffset()] & 0xFF];
350
351 }
352
353 return CoderResult.UNDERFLOW;
354 }
355
356 }