package org.basex.io.out;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.basex.io.IO;
import org.basex.io.IOFile;
import org.basex.util.Num;
import org.basex.util.Token;
import org.basex.util.list.IntList;
/**
* This is an output stream for project specific data types.
* It bears resemblance to Java's {@link DataOutputStream}.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class DataOutput extends OutputStream {
/** The underlying output stream. */
private final OutputStream os;
/** Number of written bytes. */
private long size;
/**
* Constructor, specifying an output stream.
* @param out output stream to operate on
*/
public DataOutput(final OutputStream out) {
os = out;
}
/**
* Constructor, specifying a file.
* @param db name of the database
* @throws IOException I/O exception
*/
public DataOutput(final IOFile db) throws IOException {
this(db, IO.BLOCKSIZE);
}
/**
* Constructor, specifying a file and a buffer size.
* The specified buffer size is used.
* @param db name of the database
* @param bufs size of the buffer to use
* @throws IOException I/O exception
*/
public DataOutput(final IOFile db, final int bufs) throws IOException {
os = new BufferOutput(new FileOutputStream(db.file()), bufs);
}
@Override
public void write(final int b) throws IOException {
os.write(b);
++size;
}
/**
* Writes a boolean value.
* @param b boolean value
* @throws IOException I/O exception
*/
public void writeBool(final boolean b) throws IOException {
write(b ? 1 : 0);
}
/**
* Writes a token, represented by its compressed length and its byte array.
* @param tok array to be written
* @return number of written bytes
* @throws IOException I/O exception
*/
public int writeToken(final byte[] tok) throws IOException {
final int s = writeNum(tok.length);
writeBytes(tok);
return s + tok.length;
}
/**
* Writes a double value.
* @param num array to be written
* @return number of written bytes
* @throws IOException I/O exception
*/
public int writeDouble(final double num) throws IOException {
return writeToken(Token.token(num));
}
/**
* Writes tokens. {@code null} references are replaced by an empty array.
* @param array array to be written
* @throws IOException I/O exception
*/
public void writeTokens(final byte[][] array) throws IOException {
writeNum(array.length);
for(final byte[] a : array) writeToken(a != null ? a : Token.EMPTY);
}
/**
* Writes distances between integers.
* @param array array to be written
* @throws IOException I/O exception
*/
public void writeDiffs(final IntList array) throws IOException {
final int al = array.size();
writeNum(al);
int c = 0;
for(int a = 0; a < al; a++) {
final int t = array.get(a);
writeNum(t - c);
c = t;
}
}
/**
* Writes compressed numbers; see {@link Num} for more.
* @param array array to be written
* @throws IOException I/O exception
*/
public void writeNums(final int[] array) throws IOException {
writeNum(array.length);
for(final int a : array) writeNum(a);
}
/**
* Writes a compressed integer value; see {@link Num} for more.
* By compressing, the size of the database files is reduced.
* @param v value to be written
* @return number of written values
* @throws IOException I/O exception
*/
public int writeNum(final int v) throws IOException {
if(v < 0 || v > 0x3FFFFFFF) {
write(0xC0); write(v >>> 24); write(v >>> 16); write(v >>> 8); write(v);
return 5;
}
if(v > 0x3FFF) {
write(v >>> 24 | 0x80); write(v >>> 16); write(v >>> 8); write(v);
return 4;
}
if(v > 0x3F) {
write(v >>> 8 | 0x40); write(v);
return 2;
}
write(v);
return 1;
}
/**
* Writes long values.
* NOTE: the long values are not compressed!
* @param array array to be written
* @throws IOException I/O exception
*/
public void writeLongs(final long[] array) throws IOException {
writeNum(array.length);
for(final long a : array) write8(a);
}
/**
* Writes a byte value.
* @param v value to be written
* @throws IOException I/O exception
*/
public void write1(final int v) throws IOException {
write(v);
}
/**
* Writes a short value.
* @param v value to be written
* @throws IOException I/O exception
*/
public void write2(final int v) throws IOException {
write(v >>> 8);
write(v);
}
/**
* Writes an integer value.
* @param v value to be written
* @throws IOException I/O exception
*/
public void write4(final int v) throws IOException {
write(v >>> 24);
write(v >>> 16);
write(v >>> 8);
write(v);
}
/**
* Writes 5 bytes of a long value.
* @param v value to be written
* @throws IOException I/O exception
*/
public void write5(final long v) throws IOException {
write((byte) (v >>> 32));
write((byte) (v >>> 24));
write((byte) (v >>> 16));
write((byte) (v >>> 8));
write((byte) v);
}
/**
* Writes a long value.
* @param v value to be written
* @throws IOException I/O exception
*/
void write8(final long v) throws IOException {
write((byte) (v >>> 56));
write((byte) (v >>> 48));
write((byte) (v >>> 40));
write((byte) (v >>> 32));
write((byte) (v >>> 24));
write((byte) (v >>> 16));
write((byte) (v >>> 8));
write((byte) v);
}
/**
* Writes a byte array.
* @param bytes array to be written
* @throws IOException I/O exception
*/
public void writeBytes(final byte[] bytes) throws IOException {
for(final byte b : bytes) write(b);
}
/**
* Returns the number of written bytes.
* This is not necessarily e.g. the file size.
* @return number of written bytes
*/
public long size() {
return size;
}
@Override
public void flush() throws IOException {
os.flush();
}
@Override
public void close() throws IOException {
os.close();
}
}