/*
 * 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.cassandra.io.util;

import java.io.DataOutput;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;

import org.apache.cassandra.utils.memory.MemoryUtil;

import com.google.common.base.Function;

Base class for DataOutput implementations that does not have an optimized implementations of Plus methods and does no buffering.

Unlike BufferedDataOutputStreamPlus this is capable of operating as an unbuffered output stream. Currently necessary because SequentialWriter implements its own buffering along with mark/reset/truncate.

/** * Base class for DataOutput implementations that does not have an optimized implementations of Plus methods * and does no buffering. * <p> * Unlike BufferedDataOutputStreamPlus this is capable of operating as an unbuffered output stream. * Currently necessary because SequentialWriter implements its own buffering along with mark/reset/truncate. * </p> */
public abstract class UnbufferedDataOutputStreamPlus extends DataOutputStreamPlus { private static final byte[] zeroBytes = new byte[2]; protected UnbufferedDataOutputStreamPlus() { super(); } protected UnbufferedDataOutputStreamPlus(WritableByteChannel channel) { super(channel); } /* !! DataOutput methods below are copied from the implementation in Apache Harmony RandomAccessFile. */
Writes the entire contents of the byte array buffer to this RandomAccessFile starting at the current file pointer.
Params:
  • buffer – the buffer to be written.
Throws:
  • IOException – If an error occurs trying to write to this RandomAccessFile.
/** * Writes the entire contents of the byte array <code>buffer</code> to * this RandomAccessFile starting at the current file pointer. * * @param buffer the buffer to be written. * @throws IOException If an error occurs trying to write to this RandomAccessFile. */
public void write(byte[] buffer) throws IOException { write(buffer, 0, buffer.length); }
Writes count bytes from the byte array buffer starting at offset to this RandomAccessFile starting at the current file pointer..
Params:
  • buffer – the bytes to be written
  • offset – offset in buffer to get bytes
  • count – number of bytes in buffer to write
Throws:
/** * Writes <code>count</code> bytes from the byte array <code>buffer</code> * starting at <code>offset</code> to this RandomAccessFile starting at * the current file pointer.. * * @param buffer the bytes to be written * @param offset offset in buffer to get bytes * @param count number of bytes in buffer to write * @throws IOException If an error occurs attempting to write to this * RandomAccessFile. * @throws IndexOutOfBoundsException If offset or count are outside of bounds. */
public abstract void write(byte[] buffer, int offset, int count) throws IOException;
Writes the specified byte oneByte to this RandomAccessFile starting at the current file pointer. Only the low order byte of oneByte is written.
Params:
  • oneByte – the byte to be written
Throws:
  • IOException – If an error occurs attempting to write to this RandomAccessFile.
/** * Writes the specified byte <code>oneByte</code> to this RandomAccessFile * starting at the current file pointer. Only the low order byte of * <code>oneByte</code> is written. * * @param oneByte the byte to be written * @throws IOException If an error occurs attempting to write to this * RandomAccessFile. */
public abstract void write(int oneByte) throws IOException;
Writes a boolean to this output stream.
Params:
  • val – the boolean value to write to the OutputStream
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes a boolean to this output stream. * * @param val the boolean value to write to the OutputStream * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeBoolean(boolean val) throws IOException { write(val ? 1 : 0); }
Writes a 8-bit byte to this output stream.
Params:
  • val – the byte value to write to the OutputStream
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes a 8-bit byte to this output stream. * * @param val the byte value to write to the OutputStream * @throws java.io.IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeByte(int val) throws IOException { write(val & 0xFF); }
Writes the low order 8-bit bytes from a String to this output stream.
Params:
  • str – the String containing the bytes to write to the OutputStream
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes the low order 8-bit bytes from a String to this output stream. * * @param str the String containing the bytes to write to the OutputStream * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeBytes(String str) throws IOException { byte bytes[] = new byte[str.length()]; for (int index = 0; index < str.length(); index++) { bytes[index] = (byte) (str.charAt(index) & 0xFF); } write(bytes); }
Writes the specified 16-bit character to the OutputStream. Only the lower 2 bytes are written with the higher of the 2 bytes written first. This represents the Unicode value of val.
Params:
  • val – the character to be written
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes the specified 16-bit character to the OutputStream. Only the lower * 2 bytes are written with the higher of the 2 bytes written first. This * represents the Unicode value of val. * * @param val the character to be written * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeChar(int val) throws IOException { write((val >>> 8) & 0xFF); write((val >>> 0) & 0xFF); }
Writes the specified 16-bit characters contained in str to the OutputStream. Only the lower 2 bytes of each character are written with the higher of the 2 bytes written first. This represents the Unicode value of each character in str.
Params:
  • str – the String whose characters are to be written.
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes the specified 16-bit characters contained in str to the * OutputStream. Only the lower 2 bytes of each character are written with * the higher of the 2 bytes written first. This represents the Unicode * value of each character in str. * * @param str the String whose characters are to be written. * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeChars(String str) throws IOException { byte newBytes[] = new byte[str.length() * 2]; for (int index = 0; index < str.length(); index++) { int newIndex = index == 0 ? index : index * 2; newBytes[newIndex] = (byte) ((str.charAt(index) >> 8) & 0xFF); newBytes[newIndex + 1] = (byte) (str.charAt(index) & 0xFF); } write(newBytes); }
Writes a 64-bit double to this output stream. The resulting output is the 8 bytes resulting from calling Double.doubleToLongBits().
Params:
  • val – the double to be written.
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes a 64-bit double to this output stream. The resulting output is the * 8 bytes resulting from calling Double.doubleToLongBits(). * * @param val the double to be written. * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeDouble(double val) throws IOException { writeLong(Double.doubleToLongBits(val)); }
Writes a 32-bit float to this output stream. The resulting output is the 4 bytes resulting from calling Float.floatToIntBits().
Params:
  • val – the float to be written.
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes a 32-bit float to this output stream. The resulting output is the * 4 bytes resulting from calling Float.floatToIntBits(). * * @param val the float to be written. * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeFloat(float val) throws IOException { writeInt(Float.floatToIntBits(val)); }
Writes a 32-bit int to this output stream. The resulting output is the 4 bytes, highest order first, of val.
Params:
  • val – the int to be written.
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes a 32-bit int to this output stream. The resulting output is the 4 * bytes, highest order first, of val. * * @param val the int to be written. * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public void writeInt(int val) throws IOException { write((val >>> 24) & 0xFF); write((val >>> 16) & 0xFF); write((val >>> 8) & 0xFF); write((val >>> 0) & 0xFF); }
Writes a 64-bit long to this output stream. The resulting output is the 8 bytes, highest order first, of val.
Params:
  • val – the long to be written.
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes a 64-bit long to this output stream. The resulting output is the 8 * bytes, highest order first, of val. * * @param val the long to be written. * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public void writeLong(long val) throws IOException { write((int) (val >>> 56) & 0xFF); write((int) (val >>> 48) & 0xFF); write((int) (val >>> 40) & 0xFF); write((int) (val >>> 32) & 0xFF); write((int) (val >>> 24) & 0xFF); write((int) (val >>> 16) & 0xFF); write((int) (val >>> 8) & 0xFF); write((int) (val >>> 0) & 0xFF); }
Writes the specified 16-bit short to the OutputStream. Only the lower 2 bytes are written with the higher of the 2 bytes written first.
Params:
  • val – the short to be written
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes the specified 16-bit short to the OutputStream. Only the lower 2 * bytes are written with the higher of the 2 bytes written first. * * @param val the short to be written * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public void writeShort(int val) throws IOException { writeChar(val); }
Writes the specified String out in UTF format to the provided DataOutput
Params:
  • str – the String to be written in UTF format.
  • out – the DataOutput to write the UTF encoded string to
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes the specified String out in UTF format to the provided DataOutput * * @param str the String to be written in UTF format. * @param out the DataOutput to write the UTF encoded string to * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public static void writeUTF(String str, DataOutput out) throws IOException { int length = str.length(); if (length == 0) { out.write(zeroBytes); return; } int utfCount = 0; int maxSize = 2; for (int i = 0 ; i < length ; i++) { int ch = str.charAt(i); if ((ch > 0) & (ch <= 127)) utfCount += 1; else if (ch <= 2047) utfCount += 2; else utfCount += maxSize = 3; } if (utfCount > 65535) throw new UTFDataFormatException(); //$NON-NLS-1$ byte[] utfBytes = retrieveTemporaryBuffer(utfCount + 2); int bufferLength = utfBytes.length; if (utfCount == length) { utfBytes[0] = (byte) (utfCount >> 8); utfBytes[1] = (byte) utfCount; int firstIndex = 2; for (int offset = 0 ; offset < length ; offset += bufferLength) { int runLength = Math.min(bufferLength - firstIndex, length - offset) + firstIndex; offset -= firstIndex; for (int i = firstIndex ; i < runLength; i++) utfBytes[i] = (byte) str.charAt(offset + i); out.write(utfBytes, 0, runLength); firstIndex = 0; } } else { int utfIndex = 2; int offset = 0; utfBytes[0] = (byte) (utfCount >> 8); utfBytes[1] = (byte) utfCount; while (length > 0) { int charRunLength = (utfBytes.length - utfIndex) / maxSize; if (charRunLength < 128 && charRunLength < length) { out.write(utfBytes, 0, utfIndex); utfIndex = 0; } if (charRunLength > length) charRunLength = length; for (int i = 0 ; i < charRunLength ; i++) { char ch = str.charAt(offset + i); if ((ch > 0) && (ch <= 127)) { utfBytes[utfIndex++] = (byte) ch; } else if (ch <= 2047) { utfBytes[utfIndex++] = (byte) (0xc0 | (0x1f & (ch >> 6))); utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & ch)); } else { utfBytes[utfIndex++] = (byte) (0xe0 | (0x0f & (ch >> 12))); utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & (ch >> 6))); utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & ch)); } } offset += charRunLength; length -= charRunLength; } out.write(utfBytes, 0, utfIndex); } }
Writes the specified String out in UTF format.
Params:
  • str – the String to be written in UTF format.
Throws:
  • IOException – If an error occurs attempting to write to this DataOutputStream.
/** * Writes the specified String out in UTF format. * * @param str the String to be written in UTF format. * @throws IOException If an error occurs attempting to write to this * DataOutputStream. */
public final void writeUTF(String str) throws IOException { writeUTF(str, this); } // ByteBuffer to use for defensive copies private final ByteBuffer hollowBufferD = MemoryUtil.getHollowDirectByteBuffer(); @Override public void write(ByteBuffer buf) throws IOException { if (buf.hasArray()) { write(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining()); } else { assert buf.isDirect(); MemoryUtil.duplicateDirectByteBuffer(buf, hollowBufferD); while (hollowBufferD.hasRemaining()) channel.write(hollowBufferD); } } public void write(Memory memory, long offset, long length) throws IOException { for (ByteBuffer buffer : memory.asByteBuffers(offset, length)) write(buffer); } @Override public <R> R applyToChannel(Function<WritableByteChannel, R> f) throws IOException { return f.apply(channel); } }