001: package net.sf.saxon.value;
002:
003: import net.sf.saxon.expr.XPathContext;
004: import net.sf.saxon.om.FastStringBuffer;
005: import net.sf.saxon.trans.DynamicError;
006: import net.sf.saxon.trans.XPathException;
007: import net.sf.saxon.type.*;
008:
009: /**
010: * A value of type xs:hexBinary
011: */
012:
013: public class HexBinaryValue extends AtomicValue {
014:
015: private byte[] binaryValue;
016:
017: /**
018: * Constructor: create a hexBinary value from a supplied string, in which
019: * each octet is represented by a pair of values from 0-9, a-f, A-F
020: */
021:
022: public HexBinaryValue(CharSequence s) throws XPathException {
023: if ((s.length() & 1) != 0) {
024: DynamicError err = new DynamicError(
025: "A hexBinary value must contain an even number of characters");
026: err.setErrorCode("FORG0001");
027: throw err;
028: }
029: binaryValue = new byte[s.length() / 2];
030: for (int i = 0; i < binaryValue.length; i++) {
031: binaryValue[i] = (byte) ((fromHex(s.charAt(2 * i)) << 4) + (fromHex(s
032: .charAt(2 * i + 1))));
033: }
034: }
035:
036: /**
037: * Constructor: create a hexBinary value from a given array of bytes
038: */
039:
040: public HexBinaryValue(byte[] value) {
041: this .binaryValue = value;
042: }
043:
044: /**
045: * Get the binary value
046: */
047:
048: public byte[] getBinaryValue() {
049: return binaryValue;
050: }
051:
052: /**
053: * Decode a single hex digit
054: * @param c the hex digit
055: * @return the numeric value of the hex digit
056: * @throws XPathException if it isn't a hex digit
057: */
058:
059: private int fromHex(char c) throws XPathException {
060: int d = "0123456789ABCDEFabcdef".indexOf(c);
061: if (d > 15) {
062: d = d - 6;
063: }
064: if (d < 0) {
065: DynamicError err = new DynamicError(
066: "Invalid hexadecimal digit");
067: err.setErrorCode("FORG0001");
068: throw err;
069: }
070: return d;
071: }
072:
073: /**
074: * Convert to target data type
075: * @param requiredType an integer identifying the required atomic type
076: * @param context
077: * @return an AtomicValue, a value of the required type; or an ErrorValue
078: */
079:
080: public AtomicValue convertPrimitive(BuiltInAtomicType requiredType,
081: boolean validate, XPathContext context) {
082: switch (requiredType.getPrimitiveType()) {
083: case Type.HEX_BINARY:
084: case Type.ANY_ATOMIC:
085: case Type.ITEM:
086: return this ;
087: case Type.STRING:
088: return new StringValue(getStringValueCS());
089: case Type.UNTYPED_ATOMIC:
090: return new UntypedAtomicValue(getStringValueCS());
091: case Type.BASE64_BINARY:
092: return new Base64BinaryValue(binaryValue);
093:
094: default:
095: ValidationException err = new ValidationException(
096: "Cannot convert hexBinarry to "
097: + requiredType.getDisplayName());
098: err.setErrorCode("XPTY0004");
099: err.setIsTypeError(true);
100: return new ValidationErrorValue(err);
101: }
102: }
103:
104: /**
105: * Convert to string
106: * @return the canonical representation.
107: */
108:
109: public String getStringValue() {
110: String digits = "0123456789ABCDEF";
111: FastStringBuffer sb = new FastStringBuffer(
112: binaryValue.length * 2);
113: for (int i = 0; i < binaryValue.length; i++) {
114: sb.append(digits.charAt((binaryValue[i] >> 4) & 0xf));
115: sb.append(digits.charAt(binaryValue[i] & 0xf));
116: }
117: return sb.toString();
118: }
119:
120: /**
121: * Determine the data type of the exprssion
122: * @return Type.HEX_BINARY_TYPE
123: * @param th
124: */
125:
126: public ItemType getItemType(TypeHierarchy th) {
127: return Type.HEX_BINARY_TYPE;
128: }
129:
130: /**
131: * Get the number of octets in the value
132: */
133:
134: public int getLengthInOctets() {
135: return binaryValue.length;
136: }
137:
138: /**
139: * Convert to Java object (for passing to external functions)
140: */
141:
142: public Object convertToJava(Class target, XPathContext context)
143: throws XPathException {
144:
145: if (target.isAssignableFrom(HexBinaryValue.class)) {
146: return this ;
147: } else if (target.isAssignableFrom(String.class)) {
148: return getStringValue();
149: } else {
150: Object o = super .convertToJava(target, context);
151: if (o == null) {
152: throw new DynamicError("Conversion of hexBinary to "
153: + target.getName() + " is not supported");
154: }
155: return o;
156: }
157: }
158:
159: /**
160: * Test if the two hexBinary values are equal.
161: */
162:
163: public boolean equals(Object other) {
164: HexBinaryValue v2;
165: if (other instanceof HexBinaryValue) {
166: v2 = (HexBinaryValue) other;
167: } else if (other instanceof AtomicValue) {
168: try {
169: v2 = (HexBinaryValue) ((AtomicValue) other).convert(
170: Type.HEX_BINARY, null);
171: } catch (XPathException err) {
172: return false;
173: }
174: } else {
175: return false;
176: }
177: if (binaryValue.length != v2.binaryValue.length) {
178: return false;
179: }
180: ;
181: for (int i = 0; i < binaryValue.length; i++) {
182: if (binaryValue[i] != v2.binaryValue[i]) {
183: return false;
184: }
185: ;
186: }
187: return true;
188: }
189:
190: public int hashCode() {
191: return Base64BinaryValue.byteArrayHashCode(binaryValue);
192: }
193:
194: }
195:
196: //
197: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
198: // you may not use this file except in compliance with the License. You may obtain a copy of the
199: // License at http://www.mozilla.org/MPL/
200: //
201: // Software distributed under the License is distributed on an "AS IS" basis,
202: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
203: // See the License for the specific language governing rights and limitations under the License.
204: //
205: // The Original Code is: all this file.
206: //
207: // The Initial Developer of the Original Code is Michael H. Kay, Saxonica.
208: //
209: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
210: //
211: // Contributor(s): none.
212: //
|