1 22 23 package org.xquark.schema.datatypes; 24 25 import java.text.ParseException ; 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 RCSRevision = "$Revision: 1.4 $"; 32 private static final String 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 toValidType(Object 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 valueSpace) throws SchemaException { 74 super.checkFacets(valueSpace); 75 super.checkLength(((ByteArray) valueSpace).getLength(), valueSpace); 76 } 77 78 protected Object toValueSpace(String value, ValidationContextProvider context) throws SchemaException { 79 try { 80 return new Value(decode(value)); 81 } catch (ParseException 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 value) throws ParseException { 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 ("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 ("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 ("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 ("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 ("Invalid characted in base64 encoded string", prevIndex); 135 return 3*(count/4)+1; 136 } 137 } 138 139 public byte[] decode(String value) throws ParseException { 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 encode(byte[] data) { 179 int decLen = data.length; 180 int encLen = (decLen % 3 == 0) ? 4*(decLen/3) : 4*(decLen/3+1); 181 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 (encodedData); 210 } 211 212 public String toXMLString(Object 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 ("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 obj) { 229 return obj instanceof Value; 230 } 231 232 public String toString() { 233 return encode(getData()); 234 } 235 236 } 237 } 238 | Popular Tags |