KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > value > Base64BinaryValue


1 package net.sf.saxon.value;
2
3 import net.sf.saxon.expr.XPathContext;
4 import net.sf.saxon.om.FastStringBuffer;
5 import net.sf.saxon.trans.DynamicError;
6 import net.sf.saxon.trans.XPathException;
7 import net.sf.saxon.type.*;
8 import net.sf.saxon.ConversionContext;
9
10 import java.io.ByteArrayOutputStream JavaDoc;
11
12 /**
13  * A value of type xs:base64Binary
14  */

15
16 public class Base64BinaryValue extends AtomicValue {
17
18     private byte[] binaryValue;
19
20
21     /**
22      * Constructor: create a base64Binary value from a supplied string, in which
23      * each octet is represented by a pair of values from 0-9, a-f, A-F
24      */

25
26     public Base64BinaryValue(CharSequence JavaDoc s) {
27         Base64Decoder decoder = new Base64Decoder();
28         decoder.translate(s);
29         binaryValue = decoder.getByteArray();
30     }
31
32     /**
33      * Constructor: create a base64Binary value from a given array of bytes
34      */

35
36     public Base64BinaryValue(byte[] value) {
37         this.binaryValue = value;
38     }
39
40     /**
41      * Get the binary value
42      */

43
44     public byte[] getBinaryValue() {
45         return binaryValue;
46     }
47
48     /**
49      * Convert to target data type
50      * @param requiredType an integer identifying the required atomic type
51      * @param conversion
52      * @return an AtomicValue, a value of the required type; or an ErrorValue
53      */

54
55     public AtomicValue convertPrimitive(BuiltInAtomicType requiredType, boolean validate, ConversionContext conversion) {
56         switch (requiredType.getPrimitiveType()) {
57         case Type.BASE64_BINARY:
58         case Type.ATOMIC:
59         case Type.ITEM:
60             return this;
61         case Type.STRING:
62             return new StringValue(getStringValueCS());
63         case Type.UNTYPED_ATOMIC:
64             return new UntypedAtomicValue(getStringValueCS());
65         case Type.HEX_BINARY:
66             return new HexBinaryValue(binaryValue);
67         default:
68             ValidationException err = new ValidationException("Cannot convert base64Binary to " +
69                                      requiredType.getDisplayName());
70             err.setErrorCode("FORG0001");
71             return new ValidationErrorValue(err);
72         }
73     }
74
75     /**
76      * Convert to string
77      * @return the canonical representation.
78      */

79
80     public String JavaDoc getStringValue() {
81         Base64Encoder encoder = new Base64Encoder();
82         encoder.translate(binaryValue);
83         return new String JavaDoc(encoder.getCharArray());
84     }
85
86     /**
87       * Get the number of octets in the value
88       */

89
90      public int getLengthInOctets() {
91          return binaryValue.length;
92      }
93
94     /**
95      * Determine the data type of the exprssion
96      * @return Type.BASE64_BINARY_TYPE
97      */

98
99     public ItemType getItemType() {
100         return Type.BASE64_BINARY_TYPE;
101     }
102
103     /**
104      * Convert to Java object (for passing to external functions)
105      */

106
107     public Object JavaDoc convertToJava(Class JavaDoc target, XPathContext context) throws XPathException {
108
109         if (target.isAssignableFrom(Base64BinaryValue.class)) {
110             return this;
111         } else if (target == String JavaDoc.class || target == CharSequence JavaDoc.class) {
112             return getStringValue();
113         } else if (target == Object JavaDoc.class) {
114             return getStringValue();
115         } else {
116             Object JavaDoc o = super.convertToJava(target, context);
117             if (o == null) {
118                 throw new DynamicError("Conversion of base64Binary to " + target.getName() +
119                         " is not supported");
120             }
121             return o;
122         }
123     }
124
125
126     /**
127      * Test if the two base64Binary values are equal.
128      */

129
130     public boolean equals(Object JavaDoc other) {
131         Base64BinaryValue v2;
132         if (other instanceof Base64BinaryValue) {
133             v2 = (Base64BinaryValue)other;
134         } else if (other instanceof AtomicValue) {
135             try {
136                 v2 = (Base64BinaryValue)((AtomicValue)other).convert(Type.BASE64_BINARY, null);
137             } catch (XPathException err) {
138                 return false;
139             }
140         } else {
141             return false;
142         }
143         if (binaryValue.length != v2.binaryValue.length) {
144             return false;
145         }
146         ;
147         for (int i = 0; i < binaryValue.length; i++) {
148             if (binaryValue[i] != v2.binaryValue[i]) {
149                 return false;
150             }
151             ;
152         }
153         return true;
154     }
155
156     public int hashCode() {
157         return byteArrayHashCode(binaryValue);
158     }
159
160     protected static int byteArrayHashCode(byte[] value) {
161         long h = 0;
162         for (int i=0; i<Math.min(value.length, 64); i++) {
163             h = (h<<1) ^ value[i];
164         }
165         return (int)((h>>32)^h)&0xffffffff;
166     }
167
168      /*
169      *
170      * The contents of this [inner class] are subject to the Netscape Public
171      * License Version 1.1 (the "License"); you may not use this file
172      * except in compliance with the License. You may obtain a copy of
173      * the License at http://www.mozilla.org/NPL/
174      *
175      * Software distributed under the License is distributed on an "AS
176      * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
177      * implied. See the License for the specific language governing
178      * rights and limitations under the License.
179      *
180      * The Original Code is mozilla.org code.
181      *
182      * The Initial Developer of the Original Code is Netscape
183      * Communications Corporation. Portions created by Netscape are
184      * Copyright (C) 1999 Netscape Communications Corporation. All
185      * Rights Reserved.
186      *
187      * Contributor(s):
188      */

189
190     /**
191      * Byte to text encoder using base 64 encoding. To create a base 64
192      * encoding of a byte stream call {@link #translate} for every
193      * sequence of bytes and {@link #getCharArray} to mark closure of
194      * the byte stream and retrieve the text presentation.
195      *
196      * @author Based on code from the Mozilla Directory SDK
197      */

198     private static final class Base64Encoder {
199
200         private FastStringBuffer out = new FastStringBuffer(256);
201
202         private int buf = 0; // a 24-bit quantity
203

204         private int buf_bytes = 0; // how many octets are set in it
205

206         private char line[] = new char[74]; // output buffer
207

208         private int line_length = 0; // output buffer fill pointer
209

210         //static private final byte crlf[] = "\r\n".getBytes();
211

212         private static final char map[] = {
213             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0-7
214
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8-15
215
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16-23
216
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24-31
217
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32-39
218
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40-47
219
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48-55
220
'4', '5', '6', '7', '8', '9', '+', '/', // 56-63
221
};
222
223
224         private void encode_token() {
225             int i = line_length;
226             line[i] = map[0x3F & (buf >> 18)]; // sextet 1 (octet 1)
227
line[i + 1] = map[0x3F & (buf >> 12)]; // sextet 2 (octet 1 and 2)
228
line[i + 2] = map[0x3F & (buf >> 6)]; // sextet 3 (octet 2 and 3)
229
line[i + 3] = map[0x3F & buf]; // sextet 4 (octet 3)
230
line_length += 4;
231             buf = 0;
232             buf_bytes = 0;
233         }
234
235
236         private void encode_partial_token() {
237             int i = line_length;
238             line[i] = map[0x3F & (buf >> 18)]; // sextet 1 (octet 1)
239
line[i + 1] = map[0x3F & (buf >> 12)]; // sextet 2 (octet 1 and 2)
240

241             if (buf_bytes == 1)
242                 line[i + 2] = '=';
243             else
244                 line[i + 2] = map[0x3F & (buf >> 6)]; // sextet 3 (octet 2 and 3)
245

246             if (buf_bytes <= 2)
247                 line[i + 3] = '=';
248             else
249                 line[i + 3] = map[0x3F & buf]; // sextet 4 (octet 3)
250
line_length += 4;
251             buf = 0;
252             buf_bytes = 0;
253         }
254
255
256         private void flush_line() {
257             out.append(line, 0, line_length);
258             line_length = 0;
259         }
260
261
262         /**
263          * Given a sequence of input bytes, produces a sequence of output bytes
264          * using the base64 encoding. If there are bytes in `out' already, the
265          * new bytes are appended, so the caller should do `out.setLength(0)'
266          * first if that's desired.
267          */

268         public final void translate(byte[] in) {
269             int in_length = in.length;
270
271             for (int i = 0; i < in_length; i++) {
272                 if (buf_bytes == 0)
273                     buf = (buf & 0x00FFFF) | (in[i] << 16);
274                 else if (buf_bytes == 1)
275                     buf = (buf & 0xFF00FF) | ((in[i] << 8) & 0x00FFFF);
276                 else
277                     buf = (buf & 0xFFFF00) | (in[i] & 0x0000FF);
278
279                 if ((++buf_bytes) == 3) {
280                     encode_token();
281                     if (line_length >= 72) {
282                         flush_line();
283                     }
284                 }
285
286                 if (i == (in_length - 1)) {
287                     if ((buf_bytes > 0) && (buf_bytes < 3))
288                         encode_partial_token();
289                     if (line_length > 0)
290                         flush_line();
291                 }
292             }
293
294             for (int i = 0; i < line.length; i++)
295                 line[i] = 0;
296         }
297
298
299         public char[] getCharArray() {
300             char[] ch;
301
302             if (buf_bytes != 0)
303                 encode_partial_token();
304             flush_line();
305             for (int i = 0; i < line.length; i++)
306                 line[i] = 0;
307             ch = new char[out.length()];
308             if (out.length() > 0)
309                 out.getChars(0, out.length(), ch, 0);
310             return ch;
311         }
312     }
313
314     /*
315      *
316      * The contents of this [inner class] are subject to the Netscape Public
317      * License Version 1.1 (the "License"); you may not use this file
318      * except in compliance with the License. You may obtain a copy of
319      * the License at http://www.mozilla.org/NPL/
320      *
321      * Software distributed under the License is distributed on an "AS
322      * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
323      * implied. See the License for the specific language governing
324      * rights and limitations under the License.
325      *
326      * The Original Code is mozilla.org code.
327      *
328      * The Initial Developer of the Original Code is Netscape
329      * Communications Corporation. Portions created by Netscape are
330      * Copyright (C) 1999 Netscape Communications Corporation. All
331      * Rights Reserved.
332      *
333      * Contributor(s):
334      */

335
336
337     /**
338      * Base 64 text to byte decoder. To produce the binary array from
339      * base 64 encoding call {@link #translate} for each sequence of
340      * characters and {@link #getByteArray} to mark closure of the
341      * character stream and retrieve the binary contents.
342      *
343      * @author Based on code from the Mozilla Directory SDK
344      */

345
346     private static final class Base64Decoder {
347         private ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
348
349         private byte token[] = new byte[4]; // input buffer
350

351         private byte bytes[] = new byte[3]; // output buffer
352

353         private int token_length = 0; // input buffer length
354

355         private static final byte NUL = 127; // must be out of range 0-64
356

357         private static final byte EOF = 126; // must be out of range 0-64
358

359         private static final byte[] map = {
360             NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 000-007
361
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 010-017
362
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 020-027
363
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 030-037
364
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 040-047 !"#$%&'
365
NUL, NUL, NUL, 62, NUL, NUL, NUL, 63, // 050-057 ()*+,-./
366
52, 53, 54, 55, 56, 57, 58, 59, // 060-067 01234567
367
60, 61, NUL, NUL, NUL, EOF, NUL, NUL, // 070-077 89:;<=>?
368

369             NUL, 0, 1, 2, 3, 4, 5, 6, // 100-107 @ABCDEFG
370
7, 8, 9, 10, 11, 12, 13, 14, // 110-117 HIJKLMNO
371
15, 16, 17, 18, 19, 20, 21, 22, // 120-127 PQRSTUVW
372
23, 24, 25, NUL, NUL, NUL, NUL, NUL, // 130-137 XYZ[\]^_
373
NUL, 26, 27, 28, 29, 30, 31, 32, // 140-147 `abcdefg
374
33, 34, 35, 36, 37, 38, 39, 40, // 150-157 hijklmno
375
41, 42, 43, 44, 45, 46, 47, 48, // 160-167 pqrstuvw
376
49, 50, 51, NUL, NUL, NUL, NUL, NUL, // 170-177 xyz{|}~
377

378             NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 200-207
379
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 210-217
380
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 220-227
381
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 230-237
382
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 240-247
383
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 250-257
384
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 260-267
385
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 270-277
386

387             NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 300-307
388
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 310-317
389
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 320-327
390
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 330-337
391
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 340-347
392
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 350-357
393
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 360-367
394
NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 370-377
395
};
396
397
398         // Fast routine that assumes full 4-char tokens with no '=' in them.
399
//
400
private void decode_token() {
401             int num = ((token[0] << 18) |
402                     (token[1] << 12) |
403                     (token[2] << 6) |
404                     (token[3]));
405
406             bytes[0] = (byte)(0xFF & (num >> 16));
407             bytes[1] = (byte)(0xFF & (num >> 8));
408             bytes[2] = (byte)(0xFF & num);
409
410             out.write(bytes, 0, 3);
411         }
412
413
414         // Hairier routine that deals with the final token, which can have fewer
415
// than four characters, and that might be padded with '='.
416
//
417
private void decode_final_token() {
418
419             byte b0 = token[0];
420             byte b1 = token[1];
421             byte b2 = token[2];
422             byte b3 = token[3];
423
424             int eq_count = 0;
425
426             if (b0 == EOF) {
427                 b0 = 0;
428                 eq_count++;
429             }
430             if (b1 == EOF) {
431                 b1 = 0;
432                 eq_count++;
433             }
434             if (b2 == EOF) {
435                 b2 = 0;
436                 eq_count++;
437             }
438             if (b3 == EOF) {
439                 b3 = 0;
440                 eq_count++;
441             }
442
443             int num = ((b0 << 18) | (b1 << 12) | (b2 << 6) | (b3));
444
445             // eq_count will be 0, 1, or 2.
446
// No "=" padding means 4 bytes mapped to 3, the normal case,
447
// not handled in this routine.
448
// "xxx=" means 3 bytes mapped to 2.
449
// "xx==" means 2 bytes mapped to 1.
450
// "x===" can't happen, because "x" would then be encoding
451
// only 6 bits, not 8, the minimum possible.
452

453             out.write((byte)(num >> 16)); // byte 1, count = 0 or 1 or 2
454
if (eq_count <= 1) {
455                 out.write((byte)((num >> 8) & 0xFF)); // byte 2, count = 0 or 1
456
if (eq_count == 0) {
457                     out.write((byte)(num & 0xFF)); // byte 3, count = 0
458
}
459             }
460         }
461
462
463         public final void translate(CharSequence JavaDoc str) {
464             if (token == null) // already saw eof marker?
465
return;
466             int length = str.length();
467             for (int i = 0; i < length; i++) {
468                 byte t = map[(str.charAt(i) & 0xff)];
469
470                 if (t == EOF) {
471                     eof();
472                 } else if (t != NUL) {
473                     token[token_length++] = t;
474                 }
475                 if (token_length == 4) {
476                     decode_token();
477                     token_length = 0;
478                 }
479             }
480         }
481
482         private void eof() {
483             if (token != null && token_length != 0) {
484                 while (token_length < 4)
485                     token[token_length++] = EOF;
486                 decode_final_token();
487             }
488             token_length = 0;
489             token = new byte[4];
490             bytes = new byte[3];
491         }
492
493         public byte[] getByteArray() {
494             eof();
495             return out.toByteArray();
496         }
497     }
498
499 }
500
501 //
502
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
503
// you may not use this file except in compliance with the License. You may obtain a copy of the
504
// License at http://www.mozilla.org/MPL/
505
//
506
// Software distributed under the License is distributed on an "AS IS" basis,
507
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
508
// See the License for the specific language governing rights and limitations under the License.
509
//
510
// The Original Code is: all this file, with the exception of the two subclasses which
511
// were originated by Mozilla/Netscape and reached Saxon via Castor.
512
//
513
// The Initial Developer of the Original Code is Michael H. Kay, Saxonica.
514
//
515
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
516
//
517
// Contributor(s): none.
518
//
519

520
Popular Tags