XrefHeader.java revision 1384
1384N/A/*
1384N/A * CDDL HEADER START
1384N/A *
1384N/A * The contents of this file are subject to the terms of the
1384N/A * Common Development and Distribution License (the "License").
1384N/A * You may not use this file except in compliance with the License.
1384N/A *
1384N/A * See LICENSE.txt included in this distribution for the specific
1384N/A * language governing permissions and limitations under the License.
1384N/A *
1384N/A * When distributing Covered Code, include this CDDL HEADER in each
1384N/A * file and include the License file at LICENSE.txt.
1384N/A * If applicable, add the following below this CDDL HEADER, with the
1384N/A * fields enclosed by brackets "[]" replaced with your own identifying
1384N/A * information: Portions Copyright [yyyy] [name of copyright owner]
1384N/A *
1384N/A * CDDL HEADER END
1384N/A */
1384N/A
1384N/A/*
1384N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
1384N/A * Portions Copyright 2012 Jens Elkner.
1384N/A */
1384N/Apackage org.opensolaris.opengrok.analysis;
1384N/A
1384N/Aimport java.io.IOException;
1384N/Aimport java.io.InputStream;
1384N/Aimport java.io.OutputStream;
1384N/Aimport java.nio.ByteBuffer;
1384N/Aimport java.nio.ByteOrder;
1384N/Aimport java.util.logging.Logger;
1384N/A
1384N/Aimport org.opensolaris.opengrok.analysis.FileAnalyzer.Genre;
1384N/A
1384N/A/**
1384N/A * The header of a crossfile.
1384N/A *
1384N/A * @author Jens Elkner
1384N/A * @version $Revision$
1384N/A */
1384N/Apublic class XrefHeader {
1384N/A private static final Logger logger = Logger.getLogger(XrefHeader.class.getName());
1384N/A /** the default format version of a crossfile */
1384N/A public static int VERSION = 1;
1384N/A private static final byte[] MAGIC = { 'O', 'p', 'E', 'n', 'G', 'r', 'O', 'k' };
1384N/A /** the size of the header in bytes */
1384N/A public static int HEADER_SZ = 32;
1384N/A
1384N/A private int version;
1384N/A private int lines;
1384N/A private long chars;
1384N/A private boolean compressed;
1384N/A private Genre genre;
1384N/A
1384N/A /**
1384N/A * Create a new default header for a crossfile of the given genre. Data
1384N/A * section is assumed to be uncompressed and line and char counts are set
1384N/A * to -1.
1384N/A * @param genre genre of the file.
1384N/A * @see XrefHeader#XrefHeader(Genre, boolean)
1384N/A */
1384N/A public XrefHeader(Genre genre) {
1384N/A this(genre, false);
1384N/A }
1384N/A
1384N/A /**
1384N/A * Create a new default header for a crossfile of the given genre and
1384N/A * parameters. Line and char counts are set to -1.
1384N/A * @param genre genre of the file.
1384N/A * @param compressed {@code true} if data section is compressed
1384N/A * @see XrefHeader#XrefHeader(Genre, boolean, int, long)
1384N/A */
1384N/A public XrefHeader(Genre genre, boolean compressed) {
1384N/A this(genre, compressed, -1, -1L);
1384N/A }
1384N/A
1384N/A /**
1384N/A * Create a new default header for a crossfile of the given genre and
1384N/A * parameters.
1384N/A * @param genre genre of the data section.
1384N/A * @param compressed {@code true} if data section is compressed
1384N/A * @param lines number of lines represented by the data section. {@code -1}
1384N/A * implies unknown.
1384N/A * @param chars number of characters in the [compressed] data section.
1384N/A */
1384N/A public XrefHeader(Genre genre, boolean compressed, int lines, long chars) {
1384N/A if (genre == null) {
1384N/A throw new IllegalArgumentException("genre null is not allowed");
1384N/A }
1384N/A this.genre = genre;
1384N/A version = VERSION;
1384N/A this.compressed = compressed;
1384N/A this.lines = lines;
1384N/A this.chars = chars;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Creates a ByteBuffer backed by an new byte array of {@link #HEADER_SZ}
1384N/A * and fills in all relevant metadata.
1384N/A *
1384N/A * @return an unshared byte buffer
1384N/A */
1384N/A public ByteBuffer getBytes() {
1384N/A ByteBuffer bb = ByteBuffer.wrap(new byte[HEADER_SZ]);
1384N/A bb.order(ByteOrder.BIG_ENDIAN);
1384N/A bb.put(MAGIC);
1384N/A bb.putInt(version);
1384N/A bb.putInt(lines);
1384N/A bb.putLong(chars);
1384N/A bb.put((byte) genre.ordinal()); // or should we take the first char?
1384N/A bb.put((byte) (compressed ? 1 : 0));
1384N/A return bb;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Create a new instance by reading the required number of bytes
1384N/A * from the given byte array starting at index 0.
1384N/A * @param header byte array containing the header bytes.
1384N/A * @throws IOException if the header is invalid.
1384N/A */
1384N/A public XrefHeader(byte[] header) throws IOException {
1384N/A ByteBuffer bb = ByteBuffer.wrap(header);
1384N/A bb.order(ByteOrder.BIG_ENDIAN);
1384N/A for (int i = 0; i < MAGIC.length; i++) {
1384N/A if (bb.get() != MAGIC[i]) {
1384N/A throw new IOException("invalid header");
1384N/A }
1384N/A }
1384N/A this.version = bb.getInt();
1384N/A if (VERSION != version) {
1384N/A logger.warning("Found xref file format version " + version
1384N/A + " this may lead to unexpected results (supported is "
1384N/A + VERSION + ").");
1384N/A }
1384N/A this.lines = bb.getInt();
1384N/A this.chars = bb.getLong();
1384N/A int g = bb.get();
1384N/A Genre[] values = Genre.values();
1384N/A if (g < 0 || g >= values.length) {
1384N/A throw new IOException("invalid header");
1384N/A }
1384N/A genre = values[g];
1384N/A this.compressed = bb.get() != 0;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Create a new instance by reading the appropriate number of header bytes
1384N/A * from the given stream.
1384N/A * @param in from where to read the header.
1384N/A * @throws IOException if the header is invalid or other error occures when
1384N/A * reading the stream.
1384N/A */
1384N/A public XrefHeader(InputStream in) throws IOException {
1384N/A this(readHeader(in));
1384N/A }
1384N/A
1384N/A private static final byte[] readHeader(InputStream in) throws IOException {
1384N/A byte[] header = new byte[HEADER_SZ];
1384N/A int count = 0;
1384N/A while (count < header.length) {
1384N/A int i = in.read(header, count, header.length - count);
1384N/A if (i < 0) {
1384N/A throw new IOException("invalid header");
1384N/A }
1384N/A count += i;
1384N/A }
1384N/A return header;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Write the header to the given stream.
1384N/A * @param out where to write the header.
1384N/A * @throws IOException
1384N/A */
1384N/A public void write(OutputStream out) throws IOException {
1384N/A out.write(getBytes().array());
1384N/A }
1384N/A
1384N/A /**
1384N/A * Get the number of characters, which follow the header. NOTE: NOT the
1384N/A * compressed size!
1384N/A * @return number of characters in the data section. {@code -1} implies
1384N/A * unknown.
1384N/A */
1384N/A public long getSize() {
1384N/A return chars;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Set the number of characters, which follow the header. NOTE: NOT the
1384N/A * compressed size!
1384N/A * @param size number of characters in the data section. {@code -1} implies
1384N/A * unknown.
1384N/A */
1384N/A public void setSize(long size) {
1384N/A this.chars = size < 0 ? -1L : size;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Get the number of lines represented by the data section.
1384N/A * @return number of lines. {@code -1} implies unknown.
1384N/A */
1384N/A public int getLines() {
1384N/A return lines;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Set the number of lines represented by the data section.
1384N/A * @param lines number of lines. {@code -1} implies unknown.
1384N/A */
1384N/A public void setLines(int lines) {
1384N/A this.lines = lines < 0 ? -1 : lines;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Get the version of the header (file format).
1384N/A * @return a number &gt; 0.
1384N/A */
1384N/A public int getVersion() {
1384N/A return version;
1384N/A }
1384N/A
1384N/A /**
1384N/A * The genre to which the data section belongs to.
1384N/A * @return a non-{@code null} value.
1384N/A */
1384N/A public Genre getGenre() {
1384N/A return genre;
1384N/A }
1384N/A
1384N/A /**
1384N/A * Check, whether the data section of the file is compressed.
1384N/A * @return {@code true} if compressed.
1384N/A */
1384N/A public boolean isCompressed() {
1384N/A return compressed;
1384N/A }
1384N/A
1384N/A /**
1384N/A * {@inheritDoc}
1384N/A */
1384N/A @Override
1384N/A public String toString() {
1384N/A return "Header: Version=" + version + ", Genre=" + genre.name()
1384N/A + ", SourceLines=" + (lines < 0 ? "?" : Integer.toString(lines))
1384N/A + ", Characters=" + (chars < 0 ? "?" : Long.toString(chars));
1384N/A }
1384N/A}