/* * Copyright 2011 Future Systems * * Licensed 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.krakenapps.logstorage.file; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Arrays; public class LogFileHeader { public static final String MAGIC_STRING_DATA = "NCHOVY_BEAST_DAT"; public static final String MAGIC_STRING_INDEX = "NCHOVY_BEAST_IDX"; public static final short ALIGNED_HEADER_SIZE_BASE = 22; public static final short ALIGNED_HEADER_SIZE_POS = 20; private String magicString; private short bom = (short) 0xFEFF; private short version; private short headerSize; private byte[] extraData; public LogFileHeader(short version, String magicString) { this.version = version; this.magicString = magicString; if (magicString.length() != 16) { throw new IllegalStateException(); } updateHeaderSize(); } public short version() { return version; } public int size() { return headerSize; } public byte[] getExtraData() { return extraData; } public void setExtraData(byte[] e) { extraData = Arrays.copyOf(e, e.length); updateHeaderSize(); } private int getAlignedHeaderSize() { int extraDataLength = 0; if (extraData != null) extraDataLength = extraData.length; return (ALIGNED_HEADER_SIZE_BASE + extraDataLength - 1 + 4) / 4 * 4; } private void updateHeaderSize() { headerSize = (short) getAlignedHeaderSize(); } public byte[] serialize() { ByteBuffer buf = ByteBuffer.allocate(getAlignedHeaderSize()); try { buf.put(magicString.getBytes("Latin1"), 0, 16); buf.putShort((short) bom); buf.putShort(version); int hdrSizePos = buf.position(); // XXX if (hdrSizePos != 20) throw new IllegalStateException(); buf.putShort((short) getAlignedHeaderSize()); // headerSize if (extraData != null) buf.put(extraData); int headerSize = buf.position(); // XXX if (headerSize > getAlignedHeaderSize()) { throw new IllegalStateException(); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return Arrays.copyOfRange(buf.array(), 0, getAlignedHeaderSize()); } public static LogFileHeader extractHeader(RandomAccessFile f, File path) throws IOException, InvalidLogFileHeaderException { if (f.length() < ALIGNED_HEADER_SIZE_BASE) { throw new InvalidLogFileHeaderException("File size is too small: " + path.getAbsolutePath()); } f.seek(ALIGNED_HEADER_SIZE_POS); short hdrSize = f.readShort(); if (hdrSize > 65536) { throw new InvalidLogFileHeaderException("Invalid header size: " + path.getAbsolutePath()); } f.seek(0); byte[] hdr = new byte[hdrSize]; f.readFully(hdr); return unserialize(hdr); } public static LogFileHeader extractHeader(BufferedRandomAccessFileReader f, File path) throws IOException, InvalidLogFileHeaderException { if (f.length() < ALIGNED_HEADER_SIZE_BASE) { throw new InvalidLogFileHeaderException("File size is too small: " + path.getAbsolutePath()); } f.seek(ALIGNED_HEADER_SIZE_POS); short hdrSize = f.readShort(); if (hdrSize > 65536) { throw new InvalidLogFileHeaderException("Invalid header size: " + path.getAbsolutePath()); } f.seek(0); byte[] hdr = new byte[hdrSize]; f.readFully(hdr); return unserialize(hdr); } public static LogFileHeader unserialize(byte[] array) throws InvalidLogFileHeaderException { try { ByteBuffer buf = ByteBuffer.wrap(array); byte[] magicStringBuf = new byte[16]; buf.get(magicStringBuf); String magicString = new String(magicStringBuf, Charset.forName("Latin1")); short bom = buf.getShort(); short version = buf.getShort(); short headerSize = buf.getShort(); byte[] extraData = null; if (headerSize != buf.position()) extraData = Arrays.copyOfRange(buf.array(), buf.position(), headerSize); LogFileHeader hdr = new LogFileHeader(version, magicString); hdr.bom = bom; hdr.version = version; hdr.headerSize = headerSize; hdr.extraData = extraData; validate(hdr); return hdr; } catch (Exception e) { throw new InvalidLogFileHeaderException(e); } } private static void validate(LogFileHeader hdr) throws InvalidLogFileHeaderException { if (!MAGIC_STRING_DATA.equals(hdr.magicString) && !MAGIC_STRING_INDEX.equals(hdr.magicString)) throw new InvalidLogFileHeaderException("File starts with invalid magic string."); } }