/*
* Copyright (c) 2007-2012 The Broad Institute, Inc.
* SOFTWARE COPYRIGHT NOTICE
* This software and its documentation are the copyright of the Broad Institute, Inc. All rights are reserved.
*
* This software is supplied without any warranty or guaranteed support whatsoever. The Broad Institute is not responsible for its use, misuse, or functionality.
*
* This software is licensed under the terms of the GNU Lesser General Public License (LGPL),
* Version 2.1 which is available at http://www.opensource.org/licenses/lgpl-2.1.php.
*/
package org.broad.igv.bbfile;
import htsjdk.samtools.seekablestream.SeekableStream;
import org.apache.log4j.Logger;
import htsjdk.tribble.util.LittleEndianInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
/**
* Created by IntelliJ IDEA.
* User: martind
* Date: Jan 14, 2010
* Time: 3:59:55 PM
* To change this template use File | Settings | File Templates.
*/
public class RPTreeHeader {
private static Logger log = Logger.getLogger(RPTreeHeader.class);
public final int RPTREE_HEADER_SIZE = 48;
public final int RPTREE_MAGIC_LTH = 0x2468ACE0;
public final int RPTREE_MAGIC_HTL = 0xE0AC6824;
// defines the R+ Tree access
private long rpTreeOffset; // BBFile file offset for mChromosome region tree
private boolean headerOK; // R+ Tree header read OK
// R+ Tree header - Table K
private int magic; // magic number identifies it as B+ header
private int blockSize; // number of children per block
private long itemCount; // number of chromosomes/contigs in B+ tree
private int startChromID; // ID of the first mChromosome in item
private int startBase; // Position of first base in item
private int endChromID; // ID of the first mChromosome in item
private int endBase; // Position of first base in item
private long endFileOffset; // file position marking mEndBase of data
private int itemsPerSlot; // number of items per leaf
private long reserved; // Currently 0
// constructor - reads from file input stream
/*
* Constructor
*
* Parameters:
* fis - file input stream handle
* fileOffset - file offset to the RP tree header
* isLowToHigh - if true, indicates low to high byte order, else high to low
* */
public RPTreeHeader(SeekableStream fis, long fileOffset, boolean isLowToHigh) {
long itemsCount;
rpTreeOffset = fileOffset;
// Note: a bad R+ Tree header will result in false returned
headerOK = readHeader(fis, rpTreeOffset, isLowToHigh);
}
public boolean isHeaderOK() {
return headerOK;
}
public int getHeaderSize() {
return RPTREE_HEADER_SIZE;
}
public long getTreeOffset() {
return rpTreeOffset;
}
public int getMagic() {
return magic;
}
public int getBlockSize() {
return blockSize;
}
public long getItemCount() {
return itemCount;
}
public int getStartChromID() {
return startChromID;
}
public int getStartBase() {
return startBase;
}
public int getEndChromID() {
return endChromID;
}
public int getEndBase() {
return endBase;
}
public long getMEndFileOffset() {
return endFileOffset;
}
public int getItemsPerSlot() {
return itemsPerSlot;
}
public long getReserved() {
return reserved;
}
// prints out the B+ Tree Header
public void print() {
// note if read successfully
if(headerOK){
log.debug("R+ tree header has " + RPTREE_HEADER_SIZE + " bytes.");
log.debug("R+ tree header magic = " + magic);
}
else {
log.debug("R+ Tree header is unrecognized type, header magic = " + magic);
return;
}
// Table E - Chromosome B+ Tree Header
log.debug("R+ Tree file offset = " + rpTreeOffset);
log.debug("magic = " + magic);
log.debug("Block size = " + blockSize);
log.debug("ItemCount = " + itemCount);
log.debug("StartChromID = " + startChromID);
log.debug("StartBase = " + startBase);
log.debug("EndChromID = " + endChromID);
log.debug("EndBase = " + endBase);
log.debug("EndFileOffset = " + endFileOffset);
log.debug("ItemsPerSlot = " + itemsPerSlot);
log.debug("Reserved = " + reserved);
}
/*
* Reads in the R+ Tree Header.
*
* Returns status of for tree header read; true if read, false if not.
* */
private boolean readHeader(SeekableStream fis, long fileOffset, boolean isLowToHigh){
LittleEndianInputStream lbdis;
DataInputStream bdis;
byte[] buffer = new byte[RPTREE_HEADER_SIZE];
try {
// Read R+ tree header into a buffer
fis.seek(fileOffset);
fis.readFully(buffer);
// decode header
if(isLowToHigh){
lbdis = new LittleEndianInputStream(new ByteArrayInputStream(buffer));
magic = lbdis.readInt();
// check for a valid B+ Tree Header
if(magic != RPTREE_MAGIC_LTH)
return false;
// Get mChromosome B+ header information
blockSize = lbdis.readInt();
itemCount = lbdis.readLong();
startChromID = lbdis.readInt();
startBase = lbdis.readInt();
endChromID = lbdis.readInt();
endBase = lbdis.readInt();
endFileOffset = lbdis.readLong();
itemsPerSlot = lbdis.readInt();
reserved = lbdis.readInt();
}
else {
bdis = new DataInputStream(new ByteArrayInputStream(buffer));
// check for a valid B+ Tree Header
magic = bdis.readInt();
if(magic != RPTREE_MAGIC_HTL)
return false;
// Get mChromosome B+ header information
blockSize = bdis.readInt();
itemCount = bdis.readLong();
startChromID = bdis.readInt();
startBase = bdis.readInt();
endChromID = bdis.readInt();
endBase = bdis.readInt();
endFileOffset = bdis.readLong();
itemsPerSlot = bdis.readInt();
reserved = bdis.readInt();
}
}catch(IOException ex) {
log.error("Error reading R+ tree header " + ex);
throw new RuntimeException("Error reading R+ tree header ", ex);
}
// success
return true;
}
}