]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/classes/charset/src/com/ibm/icu/charset/CharsetUTF7.java
Clean up imports.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / charset / src / com / ibm / icu / charset / CharsetUTF7.java
1 /*
2  *******************************************************************************
3  * Copyright (C) 2007-2011, International Business Machines Corporation and         *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package com.ibm.icu.charset;
8
9 import java.nio.ByteBuffer;
10 import java.nio.CharBuffer;
11 import java.nio.IntBuffer;
12 import java.nio.charset.CharsetDecoder;
13 import java.nio.charset.CharsetEncoder;
14 import java.nio.charset.CoderResult;
15
16 import com.ibm.icu.text.UnicodeSet;
17
18 /**
19  * @author Michael Ow
20  *
21  */
22 class CharsetUTF7 extends CharsetICU {
23     private final static String IMAP_NAME="IMAP-mailbox-name";
24     private boolean useIMAP;
25     protected byte[] fromUSubstitution=new byte[]{0x3F};
26    
27     public CharsetUTF7(String icuCanonicalName, String javaCanonicalName, String[] aliases) {
28         super(icuCanonicalName, javaCanonicalName, aliases);
29         maxBytesPerChar=4; /* max 3 bytes per code unit from UTF-7 (base64) */
30         minBytesPerChar=1;
31         maxCharsPerByte=1;
32         
33         useIMAP=false;
34         
35         if (icuCanonicalName.equals(IMAP_NAME)) {
36             useIMAP=true;
37         }
38     }
39     
40     //private static boolean inSetD(char c) {
41     //    return (
42     //            (char)(c - 97) < 26 || (char)(c - 65) < 26 || /* letters */
43     //            (char)(c - 48) < 10 ||                        /* digits */
44     //            (char)(c - 39) < 3 ||                          /* ' () */
45     //            (char)(c - 44) < 4 ||                          /* ,-./ */
46     //            (c==58) || (c==63)            /* :? */
47     //            );
48     //}
49     
50     //private static boolean inSetO(char c) {
51     //    return (
52     //            (char)(c - 33) < 6 ||                           /* !"#$%& */
53     //            (char)(c - 59) < 4 ||                           /* ;<=> */
54     //            (char)(c - 93) < 4 ||                           /* ]^_` */
55     //            (char)(c - 123) < 3 ||                         /* {|} */
56     //            (c==58) || (c==63)             /* *@[ */
57     //            );
58     //}
59     
60     private static boolean isCRLFTAB(char c) {
61         return (
62                 (c==13) || (c==10) || (c==9)
63                 );
64     }
65     
66     //private static boolean isCRLFSPTAB(char c) {
67     //   return (
68     //            (c==32) || (c==13) || (c==10) || (c==9)
69     //            );
70     //}
71     
72     private static final byte PLUS=43;
73     private static final byte MINUS=45;
74     private static final byte BACKSLASH=92;
75     //private static final byte TILDE=126;
76     private static final byte AMPERSAND=0x26;
77     private static final byte COMMA=0x2c;
78     private static final byte SLASH=0x2f;
79     
80     // legal byte values: all US-ASCII graphic characters 0x20..0x7e
81     private static boolean isLegal(char c, boolean useIMAP) {
82         if (useIMAP) {
83             return (
84                     (0x20 <= c) && (c <= 0x7e)
85                     );
86         } else {
87             return (
88                     ((char)(c - 32) < 94 && (c != BACKSLASH)) || isCRLFTAB(c)
89                     );
90         }
91     }
92     
93     // directly encode all of printable ASCII 0x20..0x7e except '&' 0x26
94     private static boolean inSetDIMAP(char c) {
95         return (
96                 (isLegal(c, true) && c != AMPERSAND)
97                 );
98     }
99     
100     private static byte TO_BASE64_IMAP(int n) {
101         return (n < 63 ? TO_BASE_64[n] : COMMA);
102     }
103     
104     private static byte FROM_BASE64_IMAP(char c) {
105         return (c==COMMA ? 63 : c==SLASH ? -1 : FROM_BASE_64[c]);
106     }
107     
108     /* encode directly sets D and O and CR LF SP TAB */
109     private static final byte ENCODE_DIRECTLY_MAXIMUM[] =
110     {
111      /*0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f*/
112         0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
113         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114         
115         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
116         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
117         
118         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
119         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
120         
121         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
122         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0
123     };
124     
125     /* encode directly set D and CR LF SP TAB but not set O */
126     private static final byte ENCODE_DIRECTLY_RESTRICTED[] =
127     {
128      /*0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f*/
129         0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
130         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131         
132         1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1,
133         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
134         
135         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
136         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 
137         
138         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
139         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
140     };
141     
142     private static final byte TO_BASE_64[] =
143     {
144        /* A-Z */
145        65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
146        78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
147        /* a-z */
148        97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
149        110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
150        /* 0-9 */
151        48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
152        /* +/ */
153        43, 47
154     };
155     
156     private static final byte FROM_BASE_64[] =
157     {
158        /* C0 controls, -1 for legal ones (CR LF TAB), -3 for illegal ones */
159        -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3,
160        -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
161        /* general punctuation with + and / and a special value (-2) for - */
162        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -2, -1, 63,
163        /* digits */
164        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
165        /* A-Z */
166        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
167        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -3, -1, -1, -1,       
168        /* a-z*/
169        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
170        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -3, -3
171     };
172     
173     class CharsetDecoderUTF7 extends CharsetDecoderICU {
174         public CharsetDecoderUTF7(CharsetICU cs) {
175             super(cs);
176             implReset();
177         }
178     
179         protected void implReset() {
180             super.implReset();
181             toUnicodeStatus=(toUnicodeStatus & 0xf0000000) | 0x1000000;
182         }
183         
184         protected CoderResult decodeLoop(ByteBuffer source, CharBuffer target, IntBuffer offsets, boolean flush) { 
185             CoderResult cr=CoderResult.UNDERFLOW;
186             byte base64Value;
187             byte base64Counter;
188             byte inDirectMode;
189             char bits;
190             int byteIndex;
191             int sourceIndex, nextSourceIndex;
192             
193             int length;
194             
195             char b;
196             char c;
197             
198             int sourceArrayIndex=source.position();
199             
200             //get the state of the machine state
201             {
202             int status=toUnicodeStatus;
203             inDirectMode=(byte)((status >> 24) & 1);
204             base64Counter=(byte)(status >> 16);
205             bits=(char)status;
206             }
207             byteIndex=toULength;
208             /* sourceIndex=-1 if the current character began in the previous buffer */
209             sourceIndex=byteIndex==0 ? 0 : -1;
210             nextSourceIndex=0;            
211             
212             directMode:  while (true) {
213                 if (inDirectMode==1) {
214                     /* 
215                      * In Direct Mode, most US-ASCII characters are encoded directly, i.e.,
216                      * with their US-ASCII byte values.
217                      * Backslash and Tilde and most control characters are not alled in UTF-7.
218                      * A plus sign starts Unicode (or "escape") Mode.
219                      * An ampersand starts Unicode Mode for IMAP.
220                      * 
221                      * In Direct Mode, only the sourceIndex is used.
222                      */
223                     byteIndex=0;
224                     length=source.remaining();
225                     //targetCapacity=target.remaining();
226                     //Commented out because length of source may be larger than target when it comes to bytes 
227                     /*if (useIMAP && length > targetCapacity) {
228                         length=targetCapacity;
229                     }*/
230                     while (length > 0) {
231                         b=(char)(source.get());
232                         sourceArrayIndex++;
233                         if (!isLegal(b, useIMAP)) {
234                             toUBytesArray[0]=(byte)b;
235                             byteIndex=1;
236                             cr=CoderResult.malformedForLength(sourceArrayIndex);
237                             break;
238                         } else if ((!useIMAP && b!=PLUS) || (useIMAP && b!=AMPERSAND)) {
239                             // write directly encoded character
240                             if (target.hasRemaining()) { // Check to make sure that there is room in target.
241                                 target.put(b);
242                                 if (offsets!= null) {
243                                     offsets.put(sourceIndex++);
244                                 }
245                             } else {  // Get out and set the CoderResult.
246                                 charErrorBufferArray[charErrorBufferLength++] = b;
247                                 cr = CoderResult.OVERFLOW;
248                                 break;
249                             }
250                         } else { /* PLUS or (AMPERSAND in IMAP)*/
251                             /* switch to Unicode mode */
252                             nextSourceIndex=++sourceIndex;
253                             inDirectMode=0;
254                             byteIndex=0;
255                             bits=0;
256                             base64Counter=-1;
257                             continue directMode;
258                         }
259                         --length;
260                     }//end of while
261                     if (source.hasRemaining() && target.position() >= target.limit()) {
262                         /* target is full */
263                         cr=CoderResult.OVERFLOW;
264                     }
265                     break directMode;
266                 } else { /* Unicode Mode*/
267                     /* 
268                      * In Unicode Mode, UTF-16BE is base64-encoded.
269                      * The base64 sequence ends with any character that is not in the base64 alphabet.
270                      * A terminating minus sign is consumed.
271                      * 
272                      * In Unicode Mode, the sourceIndex has the index to the start of the current
273                      * base64 bytes, while nextSourceIndex is precisely parallel to source,
274                      * keeping the index to the following byte.
275                      */
276                     while(source.hasRemaining()) {
277                         if (target.hasRemaining()) {
278                             b=(char)source.get();
279                             sourceArrayIndex++;
280                             toUBytesArray[byteIndex++]=(byte)b;
281                             base64Value = -3; /* initialize as illegal */
282                             if ((!useIMAP && (b>=126 || (base64Value=FROM_BASE_64[b])==-3 || base64Value==-1)) || (useIMAP && b>0x7e)) {
283                                 /* either
284                                  * base64Value==-1 for any legal character except base64 and minus sign, or
285                                  * base64Value==-3 for illegal characters:
286                                  * 1. In either case, leave Unicode mode.
287                                  * 2.1. If we ended with an incomplete UChar or none after the +, then
288                                  *      generate an error for the preceding erroneous sequence and deal with
289                                  *      the current (possibly illegal) character next time through.
290                                  * 2.2. Else the current char comes after a complete UChar, which was already
291                                  *      pushed to the output buf, so:
292                                  * 2.2.1. If the current char is legal, just save it for processing next time.
293                                  *        It may be for example, a plus which we need to deal with in direct mode.
294                                  * 2.2.2. Else if the current char is illegal, we might as well deal with it here.
295                                  */
296                                 inDirectMode=1;
297                                 
298                                 if(base64Counter==-1) {
299                                     /* illegal: + immediately followed by something other than base64 or minus sign */
300                                     /* include the plus sign in the reported sequence, but not the subsequent char */
301                                     source.position(source.position() -1);
302                                     toUBytesArray[0]=PLUS;
303                                     byteIndex=1;
304                                     cr=CoderResult.malformedForLength(sourceArrayIndex);
305                                     break directMode;
306                                 } else if(bits!=0) {
307                                     /* bits are illegally left over, a UChar is incomplete */
308                                     /* don't include current char (legal or illegal) in error seq */
309                                     source.position(source.position() -1);
310                                     --byteIndex;
311                                     cr=CoderResult.malformedForLength(sourceArrayIndex);
312                                     break directMode;
313                                 } else {
314                                     /* previous UChar was complete */
315                                     if(base64Value==-3) {
316                                         /* current character is illegal, deal with it here */
317                                         cr=CoderResult.malformedForLength(sourceArrayIndex);
318                                         break directMode;
319                                     } else {
320                                         /* un-read the current character in case it is a plus sign */
321                                         source.position(source.position() -1);
322                                         sourceIndex=nextSourceIndex-1;
323                                         continue directMode;
324                                     }
325                                 }
326                             } else if ((!useIMAP && (base64Value=FROM_BASE_64[b])>=0) || (useIMAP && (base64Value=FROM_BASE64_IMAP(b))>=0)) {
327                                 /* collect base64 bytes */
328                                 switch (base64Counter) {
329                                 case -1: /* -1 is immediately after the + */
330                                 case 0:
331                                     bits=(char)base64Value;
332                                     base64Counter=1;
333                                     break;
334                                 case 1:
335                                 case 3:
336                                 case 4:
337                                 case 6:
338                                     bits=(char)((bits<<6) | base64Value);
339                                     ++base64Counter;
340                                     break;
341                                 case 2:
342                                     c=(char)((bits<<4) | (base64Value>>2));
343                                     if (useIMAP && isLegal(c, useIMAP)) {
344                                         // illegal
345                                         inDirectMode=1;
346                                         cr=CoderResult.malformedForLength(sourceArrayIndex);
347                                         // goto endloop;
348                                         break directMode;
349                                     }
350                                     target.put(c);
351                                     if (offsets != null) {
352                                         offsets.put(sourceIndex);
353                                         sourceIndex=nextSourceIndex - 1;
354                                     }
355                                     toUBytesArray[0]=(byte)b; /* keep this byte in case an error occurs */
356                                     byteIndex=1;
357                                     bits=(char)(base64Value&3);
358                                     base64Counter=3;
359                                     break;
360                                 case 5:
361                                     c=(char)((bits<<2) | (base64Value>>4));
362                                     if(useIMAP && isLegal(c, useIMAP)) {
363                                         // illegal
364                                         inDirectMode=1;
365                                         cr=CoderResult.malformedForLength(sourceArrayIndex);
366                                         // goto endloop;
367                                         break directMode;
368                                     }
369                                     target.put(c);
370                                     if (offsets != null) {
371                                         offsets.put(sourceIndex);
372                                         sourceIndex=nextSourceIndex - 1;
373                                     }
374                                     toUBytesArray[0]=(byte)b; /* keep this byte in case an error occurs */
375                                     byteIndex=1;
376                                     bits=(char)(base64Value&15);
377                                     base64Counter=6;
378                                     break;
379                                 case 7:
380                                     c=(char)((bits<<6) | base64Value);
381                                     if (useIMAP && isLegal(c, useIMAP)) {
382                                         // illegal
383                                         inDirectMode=1;
384                                         cr=CoderResult.malformedForLength(sourceArrayIndex);
385                                         // goto endloop;
386                                         break directMode;
387                                     }
388                                     target.put(c);
389                                     if (offsets != null) {
390                                         offsets.put(sourceIndex);
391                                         sourceIndex=nextSourceIndex;
392                                     }
393                                     byteIndex=0;
394                                     bits=0;
395                                     base64Counter=0;
396                                     break;
397                                 //default:                  
398                                     /* will never occur */
399                                     //break;                                                           
400                                 }//end of switch
401                             } else if (!useIMAP || (useIMAP && base64Value==-2)) {
402                                 /* minus sign terminates the base64 sequence */
403                                 inDirectMode=1;
404                                 if (base64Counter==-1) {
405                                     /* +- i.e. a minus immediately following a plus */
406                                     target.put(useIMAP ? (char)AMPERSAND : (char)PLUS);
407                                     if (offsets != null) {
408                                         offsets.put(sourceIndex - 1);
409                                     }
410                                 } else {
411                                     /* absorb the minus and leave the Unicode Mode */
412                                     if (bits!=0 || (useIMAP && base64Counter!=0 && base64Counter!=3 && base64Counter!=6)) {
413                                         /*bits are illegally left over, a unicode character is incomplete */
414                                         cr=CoderResult.malformedForLength(sourceArrayIndex);
415                                         break;
416                                     }
417                                 }
418                                 sourceIndex=nextSourceIndex;
419                                 continue directMode;
420                             } else if (useIMAP) { 
421                                 if (base64Counter==-1) {
422                                     // illegal: & immediately followed by something other than base64 or minus sign
423                                     // include the ampersand in the reported sequence
424                                     --sourceIndex;
425                                     toUBytesArray[0]=AMPERSAND;
426                                     toUBytesArray[1]=(byte)b;
427                                     byteIndex=2;
428                                 }
429                                 /* base64Value==-3 for illegal characters */
430                                 /* illegal */
431                                 inDirectMode=1;
432                                 cr=CoderResult.malformedForLength(sourceArrayIndex);
433                                 break;
434                             }
435                         } else {
436                             /* target is full */
437                             cr=CoderResult.OVERFLOW;
438                             break;
439                         }
440                     } //end of while
441                     break directMode;
442                 }
443             }//end of direct mode label
444             if (useIMAP) {
445                 if (!cr.isError() && inDirectMode==0 && flush && byteIndex==0 && !source.hasRemaining()) {
446                     if (base64Counter==-1) {
447                         /* & at the very end of the input */
448                         /* make the ampersand the reported sequence */
449                         toUBytesArray[0]=AMPERSAND;
450                         byteIndex=1;
451                     }
452                     /* else if (base64Counter!=-1) byteIndex remains 0 because ther is no particular byte sequence */
453                     inDirectMode=1;
454                     cr=CoderResult.malformedForLength(sourceIndex);
455                 }
456                 
457             } else {
458                 if (!cr.isError() && flush && !source.hasRemaining() && bits  ==0) {
459                     /*
460                      * if we are in Unicode Mode, then the byteIndex might not be 0,
461                      * but that is ok if bits -- 0
462                      * -> we set byteIndex=0 at the end of the stream to avoid a truncated error 
463                      * (not true for IMAP-mailbox-name where we must end in direct mode)
464                      */
465                     if (!cr.isOverflow()) {
466                         byteIndex=0;
467                     }
468                 }
469             }
470             /* set the converter state */
471             toUnicodeStatus=(inDirectMode<<24 | (((short)base64Counter & UConverterConstants.UNSIGNED_BYTE_MASK)<<16) | (int)bits);
472             toULength=byteIndex;
473    
474             return cr;
475         }
476     }
477     
478     class CharsetEncoderUTF7 extends CharsetEncoderICU {
479         public CharsetEncoderUTF7(CharsetICU cs) {
480             super(cs, fromUSubstitution);
481             implReset();
482         }
483         
484         protected void implReset() {
485             super.implReset();
486             fromUnicodeStatus=(fromUnicodeStatus & 0xf0000000) | 0x1000000;
487         }
488         
489         protected CoderResult encodeLoop(CharBuffer source, ByteBuffer target, IntBuffer offsets, boolean flush) {
490             CoderResult cr=CoderResult.UNDERFLOW;
491             byte inDirectMode;
492             byte encodeDirectly[];
493             int status;
494             
495             int length, targetCapacity, sourceIndex;
496             
497             byte base64Counter;
498             char bits;
499             char c;
500             char b;
501             /* get the state machine state */
502             {
503                 status=fromUnicodeStatus;
504                 encodeDirectly=(((long)status) < 0x10000000) ? ENCODE_DIRECTLY_MAXIMUM : ENCODE_DIRECTLY_RESTRICTED;
505                 inDirectMode=(byte)((status >> 24) & 1);
506                 base64Counter=(byte)(status >> 16);
507                 bits=(char)((byte)status);
508             }
509             /* UTF-7 always encodes UTF-16 code units, therefore we need only a simple sourceIndex */
510             sourceIndex=0;
511             
512             directMode: while(true) {
513             if(inDirectMode==1) {
514                 length=source.remaining();
515                 targetCapacity=target.remaining();
516                 if(length > targetCapacity) {
517                     length=targetCapacity;
518                 }
519                 while (length > 0) {
520                     c=source.get();
521                     /* UTF7: currently always encode CR LF SP TAB directly */
522                     /* IMAP: encode 0x20..0x7e except '&' directly */
523                     if ((!useIMAP && c<=127 && encodeDirectly[c]==1) || (useIMAP && inSetDIMAP(c))) {
524                         /* encode directly */
525                         target.put((byte)c);
526                         if (offsets != null) {
527                             offsets.put(sourceIndex++);
528                         }
529                     } else if ((!useIMAP && c==PLUS) || (useIMAP && c==AMPERSAND)) {
530                         /* IMAP: output &- for & */
531                         /* UTF-7: output +- for + */
532                         target.put(useIMAP ? AMPERSAND : PLUS);
533                         if (target.hasRemaining()) {
534                             target.put(MINUS);
535                             if (offsets != null) {
536                                 offsets.put(sourceIndex);
537                                 offsets.put(sourceIndex++);
538                             }
539                             /* realign length and targetCapacity */
540                             continue directMode;
541                         } else {
542                             if (offsets != null) {
543                                 offsets.put(sourceIndex++);
544                             }
545                             errorBuffer[0]=MINUS;
546                             errorBufferLength=1;
547                             cr=CoderResult.OVERFLOW;
548                             break;
549                         }
550                     } else {
551                         /* un-read this character and switch to unicode mode */
552                         source.position(source.position() - 1);
553                         target.put(useIMAP ? AMPERSAND : PLUS);
554                         if (offsets != null) {
555                             offsets.put(sourceIndex);
556                         }
557                         inDirectMode=0;
558                         base64Counter=0;
559                         continue directMode;
560                     }
561                     --length;
562                 } //end of while
563                 if (source.hasRemaining() && !target.hasRemaining()) {
564                     /* target is full */
565                     cr=CoderResult.OVERFLOW;
566                 }
567                 break directMode;
568             } else { 
569                 /* Unicode Mode */
570                 while (source.hasRemaining()) {
571                     if (target.hasRemaining()) {
572                         c=source.get();
573                         if ((!useIMAP && c<=127 && encodeDirectly[c]==1) || (useIMAP && isLegal(c, useIMAP))) {
574                             /* encode directly */
575                             inDirectMode=1;
576                             
577                             /* trick: back out this character to make this easier */
578                             source.position(source.position() - 1);
579                             
580                             /* terminate the base64 sequence */
581                             if (base64Counter!=0) {
582                                 /* write remaining bits for the previous character */
583                                 target.put(useIMAP ? TO_BASE64_IMAP(bits) : TO_BASE_64[bits]);
584                                 if (offsets!=null) {
585                                     offsets.put(sourceIndex-1);
586                                 }
587                             }
588                             if (FROM_BASE_64[c]!=-1 || useIMAP) {
589                                 /* need to terminate with a minus */
590                                 if (target.hasRemaining()) {
591                                     target.put(MINUS);
592                                     if (offsets!=null) {
593                                         offsets.put(sourceIndex-1);
594                                     }
595                                 } else {
596                                     errorBuffer[0]=MINUS;
597                                     errorBufferLength=1;
598                                     cr=CoderResult.OVERFLOW;
599                                     break;
600                                 }
601                             }
602                             continue directMode;
603                         } else {
604                             /*
605                              * base64 this character:
606                              * Output 2 or 3 base64 bytres for the remaining bits of the previous character
607                              * and the bits of this character, each implicitly in UTF-16BE.
608                              * 
609                              * Here, bits is an 8-bit variable because only 6 bits need to be kept from one
610                              * character to the next.  The actual 2 or 4 bits are shifted to the left edge
611                              * of the 6-bits filed 5..0 to make the termination of the base64 sequence easier.
612                              */
613                             switch (base64Counter) {
614                             case 0:
615                                 b=(char)(c>>10);
616                                 target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
617                                 if (target.hasRemaining()) {
618                                     b=(char)((c>>4)&0x3f);
619                                     target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
620                                     if (offsets!=null) {
621                                         offsets.put(sourceIndex);
622                                         offsets.put(sourceIndex++);
623                                     }
624                                 } else {
625                                     if (offsets!=null) {
626                                         offsets.put(sourceIndex++);
627                                     }
628                                     b=(char)((c>>4)&0x3f);
629                                     errorBuffer[0]=useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b];
630                                     errorBufferLength=1;
631                                     cr=CoderResult.OVERFLOW;
632                                 }
633                                 bits=(char)((c&15)<<2);
634                                 base64Counter=1;
635                                 break;
636                             case 1:
637                                 b=(char)(bits|(c>>14));
638                                 target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
639                                 if (target.hasRemaining()) {
640                                     b=(char)((c>>8)&0x3f);
641                                     target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
642                                     if (target.hasRemaining()) {
643                                         b=(char)((c>>2)&0x3f);
644                                         target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
645                                         if (offsets!=null) {
646                                             offsets.put(sourceIndex);
647                                             offsets.put(sourceIndex);
648                                             offsets.put(sourceIndex++);
649                                         }
650                                     } else {
651                                         if (offsets!=null) {
652                                             offsets.put(sourceIndex);
653                                             offsets.put(sourceIndex++);
654                                         }
655                                         b=(char)((c>>2)&0x3f);
656                                         errorBuffer[0]=useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b];
657                                         errorBufferLength=1;
658                                         cr=CoderResult.OVERFLOW;
659                                     }
660                                 } else {
661                                     if (offsets!=null) {
662                                         offsets.put(sourceIndex++);
663                                     }
664                                     b=(char)((c>>8)&0x3f);
665                                     errorBuffer[0]=useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b];
666                                     b=(char)((c>>2)&0x3f);
667                                     errorBuffer[1]=useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b];
668                                     errorBufferLength=2;
669                                     cr=CoderResult.OVERFLOW;
670                                 }
671                                 bits=(char)((c&3)<<4);
672                                 base64Counter=2;
673                                 break;
674                             case 2:
675                                 b=(char)(bits|(c>>12));
676                                 target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
677                                 if (target.hasRemaining()) {
678                                     b=(char)((c>>6)&0x3f);
679                                     target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
680                                     if (target.hasRemaining()) {
681                                         b=(char)(c&0x3f);
682                                         target.put(useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b]);
683                                         if (offsets!=null) {
684                                             offsets.put(sourceIndex);
685                                             offsets.put(sourceIndex);
686                                             offsets.put(sourceIndex++);
687                                         }
688                                     } else {
689                                         if (offsets!=null) {
690                                             offsets.put(sourceIndex);
691                                             offsets.put(sourceIndex++);
692                                         }
693                                         b=(char)(c&0x3f);
694                                         errorBuffer[0]=useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b];
695                                         errorBufferLength=1;
696                                         cr=CoderResult.OVERFLOW;
697                                     }
698                                 } else {
699                                     if (offsets!=null) {
700                                         offsets.put(sourceIndex++);
701                                     }
702                                     b=(char)((c>>6)&0x3f);
703                                     errorBuffer[0]=useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b];
704                                     b=(char)(c&0x3f);
705                                     errorBuffer[1]=useIMAP ? TO_BASE64_IMAP(b) : TO_BASE_64[b];
706                                     errorBufferLength=2;
707                                     cr=CoderResult.OVERFLOW;
708                                 }
709                                 bits=0;
710                                 base64Counter=0;
711                                 break;
712                            //default:
713                                /* will never occur */
714                                //break;
715                            } //end of switch 
716                         }                      
717                     } else {
718                         /* target is full */
719                         cr=CoderResult.OVERFLOW;
720                         break;
721                     }
722                 } //end of while
723                 break directMode;
724             }
725             } //end of directMode label
726             
727             if (flush && !source.hasRemaining()) {
728                 /* flush remaining bits to the target */
729                 if (inDirectMode==0) {
730                     if (base64Counter!=0) {
731                         if (target.hasRemaining()) {
732                             target.put(useIMAP ? TO_BASE64_IMAP(bits) : TO_BASE_64[bits]);
733                             if (offsets!=null) {
734                                 offsets.put(sourceIndex - 1);
735                             }
736                         } else {
737                             errorBuffer[errorBufferLength++]=useIMAP ? TO_BASE64_IMAP(bits) : TO_BASE_64[bits];
738                             cr=CoderResult.OVERFLOW;
739                         }
740                     }
741                     
742                     /* need to terminate with a minus */
743                     if (target.hasRemaining()) {
744                         target.put(MINUS);
745                         if (offsets!=null) {
746                             offsets.put(sourceIndex - 1);
747                         }
748                     } else {
749                         errorBuffer[errorBufferLength++]=MINUS;
750                         cr=CoderResult.OVERFLOW;
751                     }
752                 }
753                 /*reset the state for the next conversion */
754                 fromUnicodeStatus=((status&0xf0000000) | 0x1000000); /* keep version, inDirectMode=TRUE */
755             } else {
756                 /* set the converter state back */
757                 fromUnicodeStatus=((status&0xf0000000) | (inDirectMode<<24) | (((short)base64Counter & UConverterConstants.UNSIGNED_BYTE_MASK)<<16) | ((int)bits));
758             }
759             
760             return cr;
761         }
762     }
763     
764     public CharsetDecoder newDecoder() {
765         return new CharsetDecoderUTF7(this);
766     }
767     
768     public CharsetEncoder newEncoder() {
769         return new CharsetEncoderUTF7(this);
770     }
771     
772     void getUnicodeSetImpl( UnicodeSet setFillIn, int which){
773         getCompleteUnicodeSet(setFillIn);
774     }
775 }