KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > schema > datatypes > Base64BinaryType


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.schema.datatypes;
24
25 import java.text.ParseException JavaDoc;
26
27 import org.xquark.schema.SchemaException;
28 import org.xquark.schema.validation.ValidationContextProvider;
29
30 class Base64BinaryType extends MesureableType {
31     private static final String JavaDoc RCSRevision = "$Revision: 1.4 $";
32     private static final String JavaDoc RCSName = "$Name: $";
33     private static final byte PAD = (byte) '=';
34     private static byte[] decodeMap = new byte[256];
35     private static byte[] encodeMap = new byte[64];
36
37     static {
38         for (int i = 0; i < 256; i++) {
39             decodeMap[i] = -1;
40         }
41
42         for (int i = 'A'; i <= 'Z'; i++)
43             decodeMap[i] = (byte) (i - 'A');
44         for (int i = 'a'; i <= 'z'; i++)
45             decodeMap[i] = (byte) (i - 'a' + 26);
46         for (int i = '0'; i <= '9'; i++)
47             decodeMap[i] = (byte) (i - '0' + 52);
48         decodeMap['+'] = 62;
49         decodeMap['/'] = 63;
50
51         for (int i = 0; i < 26; i++)
52             encodeMap[i] = (byte) ('A' + i);
53         for (int i = 26; i < 52; i++)
54             encodeMap[i] = (byte) ('a' + i - 26);
55         for (int i = 52; i < 62; i++)
56             encodeMap[i] = (byte) ('0' + i - 52);
57         encodeMap[62] = (byte) '+';
58         encodeMap[63] = (byte) '/';
59     }
60
61     Base64BinaryType() {
62         super("base64Binary", PrimitiveType.BASE64_BINARY);
63     }
64
65     protected Object JavaDoc toValidType(Object JavaDoc data) {
66         if (data instanceof byte[]) {
67             return new Value((byte[])data);
68         } else {
69             return (ByteArray) data;
70         }
71     }
72
73     public void checkFacets(Object JavaDoc valueSpace) throws SchemaException {
74         super.checkFacets(valueSpace);
75         super.checkLength(((ByteArray) valueSpace).getLength(), valueSpace);
76     }
77
78     protected Object JavaDoc toValueSpace(String JavaDoc value, ValidationContextProvider context) throws SchemaException {
79         try {
80             return new Value(decode(value));
81         } catch (ParseException JavaDoc ee) {
82             super.invalidValue(value.toString());
83             return null;
84         }
85     }
86
87     private boolean isBase64(char c) {
88       return (decodeMap[c] != -1);
89     }
90
91     private boolean isBase64Final2(char c) {
92         return (decodeMap[c] & 0xF) == 0;
93     }
94     
95     private boolean isBase64Final1(char c) {
96         return (decodeMap[c] & 0x3) == 0;
97     }
98
99     private int computeSize(String JavaDoc value) throws ParseException JavaDoc {
100         int count = 0;
101         int charLen = value.length();
102         char c;
103         char prev = 0;
104         int prevIndex = 0;
105         int padCount = 0;
106         for (int i = 0; i < charLen; i++) {
107             c = value.charAt(i);
108             if (!Character.isWhitespace(c)) {
109                 if (padCount > 0 && (c != PAD || padCount > 1)) {
110                     throw new ParseException JavaDoc("Illegal character after padding in base64 encoded string", i);
111                 } else if (c == PAD) {
112                     padCount++;
113                 } else if (!isBase64(c)) {
114                     throw new ParseException JavaDoc("Invalid characted in base64 encoded string", i);
115                 } else {
116                     prev = c;
117                     prevIndex = i;
118                     count++;
119                 }
120             }
121         }
122         if ((count+padCount) % 4 > 0)
123             throw new ParseException JavaDoc("base64 encoded string has invalid length", charLen);
124         switch (padCount) {
125             case 0:
126                 return 3*(count/4);
127             case 1:
128                 if (!isBase64Final1(prev))
129                     throw new ParseException JavaDoc("Invalid characted in base64 encoded string", prevIndex);
130                 return 3*(count/4)+2;
131             case 2:
132             default:
133                 if (!isBase64Final2(prev))
134                     throw new ParseException JavaDoc("Invalid characted in base64 encoded string", prevIndex);
135                 return 3*(count/4)+1;
136         }
137     }
138
139     public byte[] decode(String JavaDoc value) throws ParseException JavaDoc {
140         int decLen = computeSize(value);
141         byte[] decodedData = new byte[decLen];
142         int charIndex = 0;
143         for (int i = 0; i < decLen/3; i++) {
144             int tmp = 0;
145             for (int j = 0; j < 4; j++) {
146                 char c = value.charAt(charIndex++);
147                 while (Character.isWhitespace(c))
148                     c = value.charAt(charIndex++);
149                 tmp |= (decodeMap[c] << (6*(3-j)));
150             }
151             decodedData[3*i] = (byte)((tmp >> 16) & 0xFF);
152             decodedData[3*i+1] = (byte)((tmp >> 8) & 0xFF);
153             decodedData[3*i+2] = (byte)(tmp & 0xFF);
154         }
155         if (decLen%3 == 1) {
156             int tmp = 0;
157             for (int j = 0; j < 2; j++) {
158                 char c = value.charAt(charIndex++);
159                 while (Character.isWhitespace(c))
160                     c = value.charAt(charIndex++);
161                 tmp |= (decodeMap[c] << (6*(3-j)));
162             }
163             decodedData[decLen-1] = (byte)((tmp >> 16) & 0xFF);
164         } else if (decLen%3 == 2) {
165             int tmp = 0;
166             for (int j = 0; j < 3; j++) {
167                 char c = value.charAt(charIndex++);
168                 while (Character.isWhitespace(c))
169                     c = value.charAt(charIndex++);
170                 tmp |= (decodeMap[c] << (6*(3-j)));
171             }
172             decodedData[decLen-2] = (byte)((tmp >> 16) & 0xFF);
173             decodedData[decLen-1] = (byte)((tmp >> 8) & 0xFF);
174         }
175         return decodedData;
176     }
177
178     public String JavaDoc encode(byte[] data) {
179         int decLen = data.length;
180         int encLen = (decLen % 3 == 0) ? 4*(decLen/3) : 4*(decLen/3+1);
181         // The encoded string is split into lines of 76 characters
182
encLen += (encLen-1)/76;
183         byte[] encodedData = new byte[encLen];
184         int nLines = 0;
185         for (int i = 0; i < decLen/3; i++) {
186             int tmp = ((0xFF&data[3*i]) << 16) | ((0xFF&data[3*i+1]) << 8) | (0xFF&data[3*i+2]);
187             int encIndex = 4*i+nLines;
188             encodedData[encIndex] = encodeMap[(byte)((tmp >> 18) & 0x3F)];
189             encodedData[encIndex+1] = encodeMap[(byte)((tmp >> 12) & 0x3F)];
190             encodedData[encIndex+2] = encodeMap[(byte)((tmp >> 6) & 0x3F)];
191             encodedData[encIndex+3] = encodeMap[(byte)(tmp & 0x3F)];
192             if ((i+1) % 19 == 0 && encIndex + 4 < encLen) {
193                 encodedData[encIndex+4] = (byte)0xA;
194                 nLines++;
195             }
196         }
197         if (decLen % 3 == 1) {
198             int tmp = (0xFF&data[decLen-1]) << 16;
199             encodedData[encLen - 4] = encodeMap[(byte)((tmp >> 18) & 0x3F)];
200             encodedData[encLen - 3] = encodeMap[(byte)((tmp >> 12) & 0x3F)];
201             encodedData[encLen - 2] = encodedData[encLen - 1] = PAD;
202         } else if (decLen %3 == 2) {
203             int tmp = ((0xFF&data[decLen-2]) << 16) | ((0xFF&data[decLen-1]) << 8);
204             encodedData[encLen - 4] = encodeMap[(byte)((tmp >> 18) & 0x3F)];
205             encodedData[encLen - 3] = encodeMap[(byte)((tmp >> 12) & 0x3F)];
206             encodedData[encLen - 2] = encodeMap[(byte)((tmp >> 6) & 0x3F)];
207             encodedData[encLen - 1] = PAD;
208         }
209         return new String JavaDoc(encodedData);
210     }
211     
212     public String JavaDoc toXMLString(Object JavaDoc data, ValidationContextProvider context) {
213         if (data instanceof ByteArray) {
214             return encode(((ByteArray)data).getData());
215         } else if (data instanceof byte[]) {
216             return encode((byte[])data);
217         } else {
218             throw new IllegalArgumentException JavaDoc("Not a byte array");
219         }
220     }
221
222     class Value extends ByteArray {
223
224         Value(byte[] value) {
225             super(value);
226         }
227
228         protected boolean checkClass(Object JavaDoc obj) {
229             return obj instanceof Value;
230         }
231
232         public String JavaDoc toString() {
233             return encode(getData());
234         }
235
236     }
237 }
238
Popular Tags