blob: ce4fb710fb5c5fb0a3e0c4ef629a5e844ea5cc12 [file] [log] [blame]
/*
* 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.uima.cas.impl;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import org.apache.uima.UIMARuntimeException;
/**
* Common de/serialization
*/
public class CommonSerDes {
int version1;
int version2;
boolean isDelta;
boolean isCompressed;
/*********************************************
* HEADERS
* Serialization versioning
* There are 1 or 2 words used for versioning.
* Compressed formats and plain formats with bit xx on in first word use 2nd word
*
* First word:
*
* - bit in 0x01 position: on for binary non-delta (redundant)
* - bit in 0x02 position: on means delta, off - not delta
* - bit in 0x04 position: on means compressed, off means plain binary
* - bit in 0x08 position: on means typer system included
* - bits 0xF8 reserved
*
* - byte in 0xFF 00 position: incrementing (starting w/ 0) version
*
* Form 4: 0 = original (UIMA v2)
* 1 = fixes to original found during V3 development
* 2 = V3
*
* - byte in 0xFF 00 00 position: special flags with some shared meaning
* -- bit 0x01 00 00: V3 formats
*
* Second word:
* - bit in 0x01 position: on means form6, off = form 4
*********************************************/
public static class Header {
boolean isDelta;
boolean isCompressed;
boolean isV3style;
boolean form4;
boolean form6;
boolean typeSystemIncluded;
byte seqVersionNbr;
boolean isV3;
boolean swap;
int v; // for error messages
Reading reading;
public Header delta() {isDelta = true; return this; }
public Header delta(boolean v2) {isDelta = v2; return this; }
public Header form4() {isCompressed = form4 = true; form6 = false; return this; }
public Header form6() {isCompressed = form6 = true; form4 = false; return this; }
public Header typeSystemIncluded(boolean f) {typeSystemIncluded = f; return this; }
public Header seqVer(int v2) { assert (v2 >= 0 && v2 < 256); seqVersionNbr = (byte)v2; return this; }
public Header v3() {isV3 = true; return this; }
public void write(DataOutputStream dos) throws IOException {
v = (!isCompressed && !isDelta) ? 1 : 0;
if (isDelta) v |= 0x02;
if (isCompressed) v |= 0x04;
if (typeSystemIncluded) v |= 0x08;
v |= (seqVersionNbr << 8);
if (isV3) v |= 0x010000;
byte[] uima = new byte[4];
uima[0] = 85; // U
uima[1] = 73; // I
uima[2] = 77; // M
uima[3] = 65; // A
ByteBuffer buf = ByteBuffer.wrap(uima);
int key = buf.asIntBuffer().get();
dos.writeInt(key);
dos.writeInt(v);
if (isCompressed) {
dos.writeInt(form6 ? 1 : 0);
}
}
public boolean isDelta() {
return isDelta;
}
public boolean isCompressed() {
return isCompressed;
}
public boolean isV3style() {
return isV3style;
}
public boolean isForm4() {
return form4;
}
public boolean isForm6() {
return form6;
}
public boolean isTypeSystemIncluded() {
return typeSystemIncluded;
}
public byte getSeqVersionNbr() {
return seqVersionNbr;
}
public boolean isV3() {
return isV3;
}
}
public static Header createHeader() {
return new Header();
}
public static boolean isBinaryHeader(DataInputStream dis) {
dis.mark(4);
byte[] bytebuf = new byte[4];
try {
bytebuf[0] = dis.readByte(); // U
bytebuf[1] = dis.readByte(); // I
bytebuf[2] = dis.readByte(); // M
bytebuf[3] = dis.readByte(); // A
String s = new String(bytebuf, "UTF-8");
return s.equals("UIMA") || s.equals("AMIU");
} catch (IOException e) {
return false;
} finally {
try {
dis.reset();
} catch (IOException e) {
throw new UIMARuntimeException(e);
}
}
}
public static Header readHeader(DataInputStream dis) throws IOException {
Header h = new Header();
// key
// determine if byte swap if needed based on key
byte[] bytebuf = new byte[4];
bytebuf[0] = dis.readByte(); // U
bytebuf[1] = dis.readByte(); // I
bytebuf[2] = dis.readByte(); // M
bytebuf[3] = dis.readByte(); // A
h.swap = (bytebuf[0] != 85);
Reading r = new Reading(dis, h.swap);
h.reading = r;
int v = h.v = r.readInt(); // h.v for error message use
h.isDelta = (v & 2) != 0;
h.isCompressed = (v & 4) != 0;
h.typeSystemIncluded = (v & 8) != 0;
h.seqVersionNbr = (byte) ((v & 0xFF00) >> 8);
if (h.isCompressed) {
v = r.readInt();
h.form4 = v == 0;
h.form6 = v == 1;
}
return h;
}
public static DataOutputStream maybeWrapToDataOutputStream(OutputStream os) {
if (os instanceof DataOutputStream) {
return (DataOutputStream) os;
}
return new DataOutputStream(os);
}
public static DataInputStream maybeWrapToDataInputStream(InputStream os) {
if (os instanceof DataInputStream) {
return (DataInputStream) os;
}
return new DataInputStream(os);
}
/**
* byte swapping reads of integer forms
*/
public static class Reading {
final DataInputStream dis;
final boolean swap;
Reading(DataInputStream dis, boolean swap) {
this.dis = dis;
this.swap = swap;
}
long readLong() throws IOException {
long v = dis.readLong();
return swap ? Long.reverseBytes(v) : v;
}
int readInt() throws IOException {
int v = dis.readInt();
return swap ? Integer.reverseBytes(v) : v;
}
short readShort() throws IOException {
short v = dis.readShort();
return swap ? Short.reverseBytes(v) : v;
}
}
}