1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package com.beetstra.jutf7;
25
26 import java.nio.ByteBuffer;
27 import java.nio.CharBuffer;
28 import java.nio.charset.CharsetDecoder;
29 import java.nio.charset.CoderResult;
30
31
32
33
34
35
36
37 class UTF7StyleCharsetDecoder extends CharsetDecoder {
38 private final Base64Util base64;
39 private final byte shift;
40 private final byte unshift;
41 private final boolean strict;
42 private boolean base64mode;
43 private int bitsRead;
44 private int tempChar;
45 private boolean justShifted;
46 private boolean justUnshifted;
47
48 UTF7StyleCharsetDecoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) {
49 super(cs, 0.6f, 1.0f);
50 this.base64 = base64;
51 this.strict = strict;
52 this.shift = cs.shift();
53 this.unshift = cs.unshift();
54 }
55
56
57
58
59 protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
60 while (in.hasRemaining()) {
61 byte b = in.get();
62 if (base64mode) {
63 if (b == unshift) {
64 if (base64bitsWaiting())
65 return malformed(in);
66 if (justShifted) {
67 if (!out.hasRemaining())
68 return overflow(in);
69 out.put((char) shift);
70 } else
71 justUnshifted = true;
72 setUnshifted();
73 } else {
74 if (!out.hasRemaining())
75 return overflow(in);
76 CoderResult result = handleBase64(in, out, b);
77 if (result != null)
78 return result;
79 }
80 justShifted = false;
81 } else {
82 if (b == shift) {
83 base64mode = true;
84 if (justUnshifted && strict)
85 return malformed(in);
86 justShifted = true;
87 continue;
88 }
89 if (!out.hasRemaining())
90 return overflow(in);
91 out.put((char) b);
92 justUnshifted = false;
93 }
94 }
95 return CoderResult.UNDERFLOW;
96 }
97
98 private CoderResult overflow(ByteBuffer in) {
99 in.position(in.position() - 1);
100 return CoderResult.OVERFLOW;
101 }
102
103
104
105
106
107
108
109
110
111
112
113 private CoderResult handleBase64(ByteBuffer in, CharBuffer out, byte lastRead) {
114 CoderResult result = null;
115 int sextet = base64.getSextet(lastRead);
116 if (sextet >= 0) {
117 bitsRead += 6;
118 if (bitsRead < 16) {
119 tempChar += sextet << (16 - bitsRead);
120 } else {
121 bitsRead -= 16;
122 tempChar += sextet >> (bitsRead);
123 out.put((char) tempChar);
124 tempChar = (sextet << (16 - bitsRead)) & 0xFFFF;
125 }
126 } else {
127 if (strict)
128 return malformed(in);
129 out.put((char) lastRead);
130 if (base64bitsWaiting())
131 result = malformed(in);
132 setUnshifted();
133 }
134 return result;
135 }
136
137
138
139
140 protected CoderResult implFlush(CharBuffer out) {
141 if ((base64mode && strict) || base64bitsWaiting())
142 return CoderResult.malformedForLength(1);
143 return CoderResult.UNDERFLOW;
144 }
145
146
147
148
149 protected void implReset() {
150 setUnshifted();
151 justUnshifted = false;
152 }
153
154
155
156
157
158
159
160
161 private CoderResult malformed(ByteBuffer in) {
162 in.position(in.position() - 1);
163 return CoderResult.malformedForLength(1);
164 }
165
166
167
168
169 private boolean base64bitsWaiting() {
170 return tempChar != 0 || bitsRead >= 6;
171 }
172
173
174
175
176
177 private void setUnshifted() {
178 base64mode = false;
179 bitsRead = 0;
180 tempChar = 0;
181 }
182 }