/////////////////////////////////////////////////////////////////////////////
// This file is part of the "Java-DAP" project, a Java implementation
// of the OPeNDAP Data Access Protocol.
//
// Copyright (c) 2010, OPeNDAP, Inc.
// Copyright (c) 2002,2003 OPeNDAP, Inc.
//
// Author: James Gallagher <jgallagher@opendap.org>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms,
// with or without modification, are permitted provided
// that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// - Neither the name of the OPeNDAP nor the names of its contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/////////////////////////////////////////////////////////////////////////////
package opendap.dap;
import java.io.*;
/**
* A vector of bytes.
*
* @author jehamby
* @version $Revision: 15901 $
* @see PrimitiveVector
*/
public class BytePrimitiveVector extends PrimitiveVector
{
/**
* the array of <code>byte</code> values.
*/
private byte vals[];
/**
* Constructs a new <code>BytePrimitiveVector</code>.
*
* @param var the template <code>BaseType</code> to use.
*/
public BytePrimitiveVector(BaseType var) {
super(var);
}
/**
* Returns the number of elements in the array.
*
* @return the number of elements in the array.
*/
public int getLength() {
return vals.length;
}
/**
* Sets the number of elements in the array. Allocates a new primitive
* array of the desired size. Note that if this is called multiple times,
* the old array and its contents will be lost.
* <p/>
* Only called inside of <code>deserialize</code> method or in derived
* classes on server.
*
* @param len the number of elements in the array.
*/
public void setLength(int len) {
vals = new byte[len];
}
/**
* Return the i'th value as a <code>byte</code>.
*
* @param i the index of the value to return.
* @return the i'th value.
*/
public final byte getValue(int i) {
return vals[i];
}
/**
* Set the i'th value of the array.
*
* @param i the index of the value to set.
* @param newVal the new value.
*/
public final void setValue(int i, byte newVal) {
vals[i] = newVal;
}
/**
* Prints the value of all variables in this vector. This
* method is primarily intended for debugging OPeNDAP applications and
* text-based clients such as geturl.
*
* @param os the <code>PrintWriter</code> on which to print the value.
* @param space this value is passed to the <code>printDecl</code> method,
* and controls the leading spaces of the output.
* @see BaseType#printVal(PrintWriter, String, boolean)
*/
public final void printVal(PrintWriter os, String space) {
int len = vals.length;
for (int i = 0; i < len - 1; i++) {
// convert to unsigned and print
os.print(((int) vals[i]) & 0xFF);
os.print(", ");
}
// print last value, if any, without trailing comma
if (len > 0)
os.print(((int) vals[len - 1]) & 0xFF);
}
/**
* Prints the value of a single variable in this vector.
* method is used by <code>DArray</code>'s <code>printVal</code> method.
*
* @param os the <code>PrintWriter</code> on which to print the value.
* @param index the index of the variable to print.
* @see DArray#printVal(PrintWriter, String, boolean)
*/
public void printSingleVal(PrintWriter os, int index) {
// convert to unsigned and print
os.print(((int) vals[index]) & 0xFF);
}
/**
* Reads data from a <code>DataInputStream</code>. This method is only used
* on the client side of the OPeNDAP client/server connection.
*
* @param source a <code>DataInputStream</code> to read from.
* @param sv The <code>ServerVersion</code> returned by the server.
* (used by <code>DSequence</code> to determine which protocol version was
* used).
* @param statusUI The <code>StatusUI</code> object to use for GUI updates
* and user cancellation notification (may be null).
* @throws DataReadException when invalid data is read, or if the user
* cancels the download.
* @throws EOFException if EOF is found before the variable is completely
* deserialized.
* @throws IOException thrown on any other InputStream exception.
* @see ClientIO#deserialize(DataInputStream, ServerVersion, StatusUI)
*/
public synchronized void deserialize(DataInputStream source,
ServerVersion sv,
StatusUI statusUI)
throws IOException, EOFException, DataReadException {
int modFour = vals.length % 4;
// number of bytes to pad
int pad = (modFour != 0) ? (4 - modFour) : 0;
for (int i = 0; i < vals.length; i++) {
vals[i] = source.readByte();
if (statusUI != null) {
statusUI.incrementByteCount(1);
if (statusUI.userCancelled())
throw new DataReadException("User cancelled");
}
}
// pad out to a multiple of four bytes
byte unused;
for (int i = 0; i < pad; i++)
unused = source.readByte();
if (statusUI != null)
statusUI.incrementByteCount(pad);
}
/**
* Writes data to a <code>DataOutputStream</code>. This method is used
* primarily by GUI clients which need to download OPeNDAP data, manipulate
* it, and then re-save it as a binary file.
*
* @param sink a <code>DataOutputStream</code> to write to.
* @throws IOException thrown on any <code>OutputStream</code>
* exception.
*/
public void externalize(DataOutputStream sink) throws IOException {
int modFour = vals.length % 4;
// number of bytes to pad
int pad = (modFour != 0) ? (4 - modFour) : 0;
for (int i = 0; i < vals.length; i++) {
sink.writeByte(vals[i]);
}
// pad out to a multiple of four bytes
for (int i = 0; i < pad; i++)
sink.writeByte(0);
}
/**
* Write a subset of the data to a <code>DataOutputStream</code>.
*
* @param sink a <code>DataOutputStream</code> to write to.
* @param start starting index (i=start)
* @param stop ending index (i<=stop)
* @param stride index stride (i+=stride)
* @throws IOException thrown on any <code>OutputStream</code> exception.
*/
public void externalize(DataOutputStream sink, int start, int stop, int stride) throws IOException {
int count = 0;
for (int i = start; i <= stop; i += stride) {
sink.writeByte(vals[i]);
count++;
}
// pad out to a multiple of four bytes
int modFour = count % 4;
int pad = (modFour != 0) ? (4 - modFour) : 0;
for (int i = 0; i < pad; i++)
sink.writeByte(0);
}
/**
* Create a new primitive vector using a subset of the data.
*
* @param start starting index (i=start)
* @param stop ending index (i<=stop)
* @param stride index stride (i+=stride)
* @return new primitive vector, of type BytePrimitiveVector.
*/
public PrimitiveVector subset(int start, int stop, int stride) {
BytePrimitiveVector n = new BytePrimitiveVector(getTemplate());
stride = Math.max(stride, 1);
stop = Math.max(start, stop);
int length = 1 + (stop - start) / stride;
n.setLength(length);
int count = 0;
for (int i = start; i <= stop; i += stride) {
n.setValue(count, vals[i]);
count++;
}
return n;
}
/**
* Returns (a reference to) the internal storage for this PrimitiveVector
* object.
* <h2>WARNING:</h2>
* Because this method breaks encapsulation rules the user must beware!
* If we (the OPeNDAP prgramming team) choose to change the internal
* representation(s) of these types your code will probably break.
* <p/>
* This method is provided as an optimization to eliminate massive
* copying of data.
*
* @return The internal array of bytes.
*/
public Object getInternalStorage() {
return (vals);
}
/**
* Set the internal storage for PrimitiveVector.
* <h2><i>WARNING:</i></h2>
* Because this method breaks encapsulation rules the user must beware!
* If we (the OPeNDAP prgramming team) choose to change the internal
* representation(s) of these types your code will probably break.
* <p/>
* This method is provided as an optimization to eliminate massive
* copying of data.
*/
public void setInternalStorage(Object o) {
vals = (byte []) o;
}
/**
* Returns a clone of this <code>Attribute</code>.
* See DAPNode.cloneDag()
*
* @param map track previously cloned nodes
* @return a clone of this <code>Attribute</code>.
*/
public DAPNode cloneDAG(CloneMap map)
throws CloneNotSupportedException
{
BytePrimitiveVector v = (BytePrimitiveVector) super.cloneDAG(map);
if (vals != null) {
v.vals = new byte[vals.length];
System.arraycopy(vals, 0, v.vals, 0, vals.length);
}
return v;
}
}