1
|
|
/*
|
2
|
|
* JBind
|
3
|
|
*
|
4
|
|
* Copyright (c) by Stefan Wachter. All rights reserved.
|
5
|
|
*
|
6
|
|
* Usage, modification, and redistribution is subject to license terms that are
|
7
|
|
* available at 'http://www.jbind.org'. The JBind license is like the
|
8
|
|
* 'Apache Software License V 1.1'.
|
9
|
|
*/
|
10
|
|
package org.jbind.xml.instance.data;
|
11
|
|
|
12
|
|
import org.jbind.xml.core.data.IAnyTypeData;
|
13
|
|
import org.jbind.xml.core.data.IBase64Binary;
|
14
|
|
import org.jbind.xml.core.data.IBase64BinaryData;
|
15
|
|
import org.jbind.xml.msg.IConstraintViolations;
|
16
|
|
import org.jbind.xml.msg.XmlException;
|
17
|
|
import org.jbind.xml.msg.XmlMessages;
|
18
|
|
|
19
|
|
/**
|
20
|
|
* Base64 encoded data (cf. http://www.ietf.org/rfc/rfc2045.txt).
|
21
|
|
*/
|
22
|
|
public class Base64BinaryData extends AbstractSimpleData implements IBase64BinaryData {
|
23
|
|
|
24
|
|
private IBase64Binary myValue;
|
25
|
|
|
26
|
8
|
private static final int getInt(char aChar) {
|
27
|
8
|
if ((aChar >= 'A') && (aChar <= 'Z')) {
|
28
|
3
|
return aChar - 'A';
|
29
|
|
}
|
30
|
5
|
if ((aChar >= 'a') && (aChar <= 'z')) {
|
31
|
2
|
return aChar - 'a' + 26;
|
32
|
|
}
|
33
|
3
|
if ((aChar >= '0') && (aChar <= '9')) {
|
34
|
1
|
return aChar - '0' + 52;
|
35
|
|
}
|
36
|
2
|
if (aChar == '+') {
|
37
|
0
|
return 62;
|
38
|
|
}
|
39
|
2
|
if (aChar == '/') {
|
40
|
0
|
return 63;
|
41
|
|
}
|
42
|
2
|
if (aChar == '=') {
|
43
|
1
|
return -1;
|
44
|
|
}
|
45
|
1
|
return -2;
|
46
|
|
}
|
47
|
|
|
48
|
1
|
protected void doAccept(String aString) throws XmlException {
|
49
|
1
|
super.doAccept(aString);
|
50
|
1
|
int strLength = aString.length();
|
51
|
1
|
int maxNbBytes = (strLength * 3 / 4) + 1;
|
52
|
1
|
byte[] array = new byte[maxNbBytes];
|
53
|
1
|
int nbBytes = 0;
|
54
|
|
|
55
|
2
|
for (int charIndex = 0; charIndex < strLength; ) {
|
56
|
2
|
int chars = 0;
|
57
|
2
|
int value = 0;
|
58
|
|
|
59
|
2
|
do {
|
60
|
8
|
char c = aString.charAt(charIndex++);
|
61
|
8
|
int i = getInt(c);
|
62
|
8
|
if (i == -1) {
|
63
|
1
|
break;
|
64
|
|
}
|
65
|
7
|
if (i == -2) {
|
66
|
1
|
continue;
|
67
|
|
}
|
68
|
6
|
value = (value << 6) | i;
|
69
|
6
|
chars++;
|
70
|
7
|
} while ((chars < 4) && (charIndex < strLength));
|
71
|
|
|
72
|
2
|
if (chars == 1) {
|
73
|
0
|
throw new XmlException(XmlMessages.truncatedBase64Encoding(getImpl_()));
|
74
|
2
|
} else if (((chars == 2) && (!(aString.charAt(charIndex) == '=') || !(aString.charAt(charIndex - 1) == '='))) || ((chars == 3) && (!(aString.charAt(charIndex - 1) == '=')))) {
|
75
|
0
|
throw new XmlException(XmlMessages.missingPaddingInBase64Encoding(getImpl_()));
|
76
|
|
}
|
77
|
|
|
78
|
2
|
int bytes = (chars == 4) ? 3 : ((chars == 3) ? 2 : ((chars == 2) ? 1 : 0));
|
79
|
2
|
if (bytes == 1) {
|
80
|
1
|
if (0 != (value & 0xF)) {
|
81
|
0
|
throw new XmlException(XmlMessages.truncatedBase64Encoding(getImpl_()));
|
82
|
|
}
|
83
|
1
|
value = value >> 4;
|
84
|
1
|
} else if (bytes == 2) {
|
85
|
0
|
if (0 != (value & 0x3)) {
|
86
|
0
|
throw new XmlException(XmlMessages.truncatedBase64Encoding(getImpl_()));
|
87
|
|
}
|
88
|
0
|
value = value >> 2;
|
89
|
|
}
|
90
|
2
|
for (int b = bytes; --b >= 0; ) {
|
91
|
4
|
array[nbBytes + b] = (byte)(0xFF & value);
|
92
|
4
|
value = value >> 8;
|
93
|
|
}
|
94
|
2
|
nbBytes += bytes;
|
95
|
|
|
96
|
2
|
if (chars < 4) {
|
97
|
1
|
break;
|
98
|
|
}
|
99
|
|
}
|
100
|
|
|
101
|
1
|
byte[] a = new byte[nbBytes];
|
102
|
1
|
System.arraycopy(array, 0, a, 0, nbBytes);
|
103
|
1
|
myValue = new Base64Binary(a);
|
104
|
|
}
|
105
|
|
|
106
|
2
|
public IBase64Binary getBase64Binary() {
|
107
|
2
|
return myValue;
|
108
|
|
}
|
109
|
|
|
110
|
0
|
public void setBase64Binary(IBase64Binary aNewValue) throws XmlException {
|
111
|
0
|
IBase64Binary oldValue = myValue;
|
112
|
0
|
myValue = aNewValue;
|
113
|
0
|
IConstraintViolations violations = completeSimpleStorageAssignment_();
|
114
|
0
|
if (!violations.isEmpty()) {
|
115
|
0
|
myValue = oldValue;
|
116
|
0
|
throw new XmlException(violations);
|
117
|
|
}
|
118
|
|
}
|
119
|
|
|
120
|
0
|
public int getLength() {
|
121
|
0
|
return myValue.getBytes().length;
|
122
|
|
}
|
123
|
|
|
124
|
0
|
public String getCanonicalForm_() {
|
125
|
0
|
return myValue.toString();
|
126
|
|
}
|
127
|
|
|
128
|
0
|
public boolean simpleStorageValueEquals(IAnyTypeData aData) {
|
129
|
0
|
return (aData instanceof IBase64BinaryData) && myValue.equals(((IBase64BinaryData)aData).getBase64Binary());
|
130
|
|
}
|
131
|
|
|
132
|
0
|
public int simpleStorageValueHashCode() {
|
133
|
0
|
return myValue.hashCode();
|
134
|
|
}
|
135
|
|
|
136
|
0
|
public Object getSimpleStorageObject() {
|
137
|
0
|
return myValue;
|
138
|
|
}
|
139
|
|
|
140
|
0
|
public void setSimpleStorageObject(Object aValue) {
|
141
|
0
|
myValue = (IBase64Binary)aValue;
|
142
|
|
}
|
143
|
|
|
144
|
|
// public static void main(String[] anArgs) {
|
145
|
|
// try {
|
146
|
|
// Base64BinaryData bd = new Base64BinaryData();
|
147
|
|
// for (int nbBytes = 0; nbBytes < 5; nbBytes++) {
|
148
|
|
// byte[] bytes = new byte[nbBytes];
|
149
|
|
// for (byte b = -128; true; b++) {
|
150
|
|
// for (int i = 0; i < nbBytes; i++) bytes[i] = b;
|
151
|
|
// Base64Binary binary = new Base64Binary(bytes);
|
152
|
|
// String stringBytes = String.valueOf(binary);
|
153
|
|
// bd.doAccept(stringBytes);
|
154
|
|
// byte[] newBytes = bd.getBase64Binary().getBytes();
|
155
|
|
// if (!Arrays.equals(bytes, newBytes)) {
|
156
|
|
// Console.out.println("bytes: " + toString(bytes) + "; stringBytes: " + stringBytes + "; newBytes: " + toString(newBytes));
|
157
|
|
// assert false;
|
158
|
|
// }
|
159
|
|
// if (b == 127) break;
|
160
|
|
// }
|
161
|
|
// }
|
162
|
|
// } catch (XmlException e) {
|
163
|
|
// e.printStackTrace();
|
164
|
|
// }
|
165
|
|
// }
|
166
|
|
//
|
167
|
|
//
|
168
|
|
// public static void main(String[] anArgs) {
|
169
|
|
// String data = "Az9B";
|
170
|
|
// try {
|
171
|
|
// Base64BinaryData bd = new Base64BinaryData();
|
172
|
|
// bd.doAccept(data);
|
173
|
|
// byte[] ba = bd.getBase64Binary().getBytes();
|
174
|
|
// String s = bd.getBase64Binary().toString();
|
175
|
|
// assert data.equals(s);
|
176
|
|
// } catch (Exception e) {
|
177
|
|
// e.printStackTrace();
|
178
|
|
// }
|
179
|
|
// }
|
180
|
|
//
|
181
|
|
|
182
|
0
|
private static String toString(byte[] aBytes) {
|
183
|
0
|
StringBuffer sb = new StringBuffer();
|
184
|
0
|
for (int i = 0; i < aBytes.length; i++) {
|
185
|
0
|
sb.append(aBytes[i]).append((i < aBytes.length - 1) ? ", " : "");
|
186
|
|
}
|
187
|
0
|
return sb.toString();
|
188
|
|
}
|
189
|
|
}
|
190
|
|
|