ExecutionDataReader.java

    1/*******************************************************************************
    2 * Copyright (c) 2009 Mountainminds GmbH & Co. KG and others
    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[][] blockdata = new boolean[in.readVarInt()][];
   96        // 1. Read block sizes
   97        for (int i = 0; i < blockdata.length; i++) {
   98            blockdata[i] = new boolean[in.readVarInt()];
   99        }
  100        // 2. Read block data
  101        for (int i = 0; i < blockdata.length; i++) {
  102            for (int j = 0; j < blockdata[i].length; j++) {
  103                blockdata[i][j] = in.readPackedBoolean();
  104            }
  105        }
  106        in.finishPackedBoolean();
  107        if (executionDataVisitor != null) {
  108            executionDataVisitor.visitClassExecution(classid, name, blockdata);
  109        }
  110    }
  111
  112}