package com.thaiopensource.datatype.xsd; import org.relaxng.datatype.ValidationContext; class Base64BinaryDatatype extends BinaryDatatype { static private final byte[] weightTable = makeWeightTable(); static private final byte INVALID = (byte)-1; static private final byte WHITESPACE = (byte)-2; static private final byte PADDING = (byte)-3; // for efficiency, don't assume whitespace normalized boolean lexicallyAllows(String str) { return byteCount(str) >= 0; } String getLexicalSpaceKey() { return "base64"; } private static int byteCount(String str) { int nChars = 0; int nPadding = 0; int lastCharWeight = -1; for (int i = 0, len = str.length(); i < len; i++) { char c = str.charAt(i); if (c >= 128) return -1; int w = weightTable[c]; switch (w) { case WHITESPACE: break; case PADDING: if (++nPadding > 2) return -1; break; case INVALID: return -1; default: if (nPadding > 0) return -1; lastCharWeight = w; nChars++; break; } } if (((nChars + nPadding) & 0x3) != 0) return -1; switch (nPadding) { case 1: // 1 padding char; last quartet specifies 2 bytes = 16 bits = 6 + 6 + 4 bits // lastChar must have 6 - 4 = 2 unused bits if ((lastCharWeight & 0x3) != 0) return -1; break; case 2: // 2 padding chars; last quartet specifies 1 byte = 8 bits = 6 + 2 bits // lastChar must have 6 - 2 = 4 unused bits if ((lastCharWeight & 0xF) != 0) return -1; break; } return ((nChars + nPadding) >> 2)*3 - nPadding; } Object getValue(String str, ValidationContext vc) { int nBytes = byteCount(str); byte[] value = new byte[nBytes]; int valueIndex = 0; int nBytesAccum = 0; int accum = 0; for (int i = 0, len = str.length(); i < len; i++) { int w = weightTable[str.charAt(i)]; if (w != WHITESPACE) { accum <<= 6; if (w != PADDING) accum |= w; if (++nBytesAccum == 4) { for (int shift = 16; shift >= 0; shift -= 8) { if (valueIndex < nBytes) value[valueIndex++] = (byte)((accum >> shift) & 0xFF); } nBytesAccum = 0; accum = 0; } } } return value; } static private byte[] makeWeightTable() { byte[] w = new byte[128]; byte n = INVALID; for (int i = 0; i < 128; i++) w[i] = n; n = 0; for (int i = 'A'; i <= 'Z'; i++, n++) w[i] = n; for (int i = 'a'; i <= 'z'; i++, n++) w[i] = n; for (int i = '0'; i <= '9'; i++, n++) w[i] = n; w['+'] = n++; w['/'] = n++; w[' '] = w['\t'] = w['\r'] = w['\n'] = WHITESPACE; w['='] = PADDING; return w; } }