ExecutionDataReader.java

    1/*******************************************************************************
    2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
    3 * All rights reserved. This program and the accompanying materials
    4 * are made available under the terms of the Eclipse Public License v1.0
    5 * which accompanies this distribution, and is available at
    6 * http://www.eclipse.org/legal/epl-v10.html
    7 *
    8 * Contributors:
    9 *    Marc R. Hoffmann - initial API and implementation
   10 *    
   11 * $Id: $
   12 *******************************************************************************/
   13package org.jacoco.core.data;
   14
   15import static java.lang.String.format;
   16
   17import java.io.EOFException;
   18import java.io.IOException;
   19import java.io.InputStream;
   20
   21/**
   22 * Deserialization of execution data from binary streams.
   23 * 
   24 * @author Marc R. Hoffmann
   25 * @version $Revision: $
   26 */
   27public class ExecutionDataReader {
   28
   29    private final CompactDataInput in;
   30
   31    private IExecutionDataVisitor executionDataVisitor;
   32
   33    /**
   34     * Creates a new reader based on the given input stream input. Depending on
   35     * the nature of the underlying stream input should be buffered as most data
   36     * is read in single bytes.
   37     * 
   38     * @param input
   39     *            input stream to read execution data from
   40     */
   41    public ExecutionDataReader(final InputStream input) {
   42        this.in = new CompactDataInput(input);
   43    }
   44
   45    /**
   46     * Sets an listener for execution data.
   47     * 
   48     * @param visitor
   49     */
   50    public void setExecutionDataVisitor(final IExecutionDataVisitor visitor) {
   51        this.executionDataVisitor = visitor;
   52    }
   53
   54    /**
   55     * Reads all data and reports it to the corresponding visitors.
   56     * 
   57     * @throws IOException
   58     *             might be thrown by the underlying input stream
   59     */
   60    public void read() throws IOException {
   61        try {
   62            while (true) {
   63                final byte block = in.readByte();
   64                switch (block) {
   65                case ExecutionDataWriter.BLOCK_HEADER:
   66                    readHeader();
   67                    break;
   68                case ExecutionDataWriter.BLOCK_EXECUTIONDATA:
   69                    readExecutionData();
   70                    break;
   71                default:
   72                    throw new IOException(format("Unknown block type %x.",
   73                            Integer.valueOf(block)));
   74                }
   75            }
   76        } catch (final EOFException e) {
   77            // expected at the end of the stream
   78        }
   79    }
   80
   81    private void readHeader() throws IOException {
   82        if (in.readChar() != ExecutionDataWriter.MAGIC_NUMBER) {
   83            throw new IOException("Invalid execution data file.");
   84        }
   85        final char version = in.readChar();
   86        if (version != ExecutionDataWriter.FORMAT_VERSION) {
   87            throw new IOException(format("Incompatible format version %x.",
   88                    Integer.valueOf(version)));
   89        }
   90    }
   91
   92    private void readExecutionData() throws IOException {
   93        final long classid = in.readLong();
   94        final String name = in.readUTF();
   95        final boolean[] data = new boolean[in.readVarInt()];
   96        for (int i = 0; i < data.length; i++) {
   97            data[i] = in.readPackedBoolean();
   98        }
   99        in.finishPackedBoolean();
  100        if (executionDataVisitor != null) {
  101            executionDataVisitor.visitClassExecution(classid, name, data);
  102        }
  103    }
  104
  105}