/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.pig.data; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.util.Arrays; import org.apache.hadoop.io.WritableComparator; import org.apache.pig.classification.InterfaceAudience; import org.apache.pig.classification.InterfaceStability; /** * An implementation of byte array. This is done as an object because we * need to be able to implement compareTo, toString, hashCode, and some * other methods. */ @InterfaceAudience.Public @InterfaceStability.Stable public class DataByteArray implements Comparable, Serializable { private static final long serialVersionUID = 1L; byte[] mData = null; /** * Default constructor. The data array will not be allocated when this * constructor is called. */ public DataByteArray() { } /** * Construct a byte array using the provided bytes as the content. * @param b byte array to use as content. A reference to the bytes * will be taken, the underlying bytes will not be copied. */ public DataByteArray(byte[] b) { mData = b; } /** * Construct a byte array concatenating the two provided * byte arrays as the content. * @param b the first byte array to use as content. * @param c the other byte array to use as content. * */ public DataByteArray(DataByteArray b, DataByteArray c) { byte[] ba = (b == null) ? null : b.get(); byte[] ca = (c == null) ? null : c.get(); int baLength = (ba == null) ? 0 : ba.length; int caLength = (ca == null) ? 0 : ca.length; int totalSize = baLength + caLength; if(totalSize == 0) { return; } System.arraycopy(ba, 0, mData = new byte[totalSize], 0, baLength); System.arraycopy(ca, 0, mData,baLength, caLength); } /** * Construct a byte array using a portion of the provided bytes as content. * @param b byte array to read from. A copy of the underlying bytes will be * made. * @param start starting point to copy from * @param end ending point to copy to, exclusive. */ public DataByteArray(byte[] b, int start, int end) { System.arraycopy(b, start, mData = new byte[end - start], 0, end-start); } /** * Construct a byte array from a String. The contents of the string * are copied. * @param s String to make a byte array out of. */ public DataByteArray(String s) { try { mData = s.getBytes("UTF8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Find the size of the byte array. * @return number of bytes in the array. */ public int size() { return mData.length; } /** * Get the underlying byte array. This is the real thing, not a copy, * so don't mess with it! * @return underlying byte[] */ public byte[] get() { return mData; } /** * Set the internal byte array. This should not be called unless the * default constructor was used. * @param b byte array to store. The contents of the byte array are * not copied. */ public void set(byte[] b) { mData = b; } /** * Set the internal byte array. This should not be called unless the * default constructor was used. * @param s String to copy. The contents of the string are copied. */ public void set(String s) { mData = s.getBytes(); } /** * Append given byte array to the internal byte array. * @param b byte array who's contents to append. The contents of the byte array are * copied. */ public DataByteArray append(DataByteArray b) { byte[] ba = (b == null) ? null : b.get(); return append(ba, 0, ba == null ? 0 : ba.length); } public DataByteArray append(byte [] ba){ return append(ba, 0, ba.length); } public DataByteArray append(byte [] ba, int start, int baLength){ int mDataLength = (mData == null) ? 0 : mData.length; int totalSize = mDataLength + baLength; if(totalSize == 0) { return this; } byte[] oldData = mData == null ? new byte[0] : mData.clone(); System.arraycopy(oldData, 0, mData = new byte[totalSize], 0, mDataLength); System.arraycopy(ba, start, mData, mDataLength, baLength); return this; } public DataByteArray append(String str){ try { return append(str.getBytes("UTF8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //TODO: better error here throw new RuntimeException("Unable to append str: " + str); } /** * Convert the byte array to a string. UTF8 encoding will be assumed. */ @Override public String toString() { String r=""; try { r = new String(mData, "UTF8"); } catch (Exception e) { // TODO: handle exception } return r; } /** * Compare two byte arrays. Comparison is done first using byte values then * length. So "g" will be greater than "abcdefg", but "hello worlds" is * greater than "hello world". If the other object is not a DataByteArray, * {@link DataType#compare} will be called. * * @param other Other object to compare to. * @return -1 if less than, 1 if greater than, 0 if equal. */ public int compareTo(Object other) { if (other instanceof DataByteArray) { DataByteArray dba = (DataByteArray) other; return compare(mData, dba.mData); } else { return DataType.compare(this, other); } } public static int compare(byte[] b1, byte[] b2) { return WritableComparator.compareBytes(b1, 0, b1.length, b2, 0, b2.length); } @Override public boolean equals(Object other) { return (compareTo(other) == 0); } @Override public int hashCode() { return hashCode(mData); } public static int hashCode(byte[] buf) { return Arrays.hashCode(buf); } }