1e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/*******************************************************************************
2398ee59bebad6835dab57b60157eff16d511709eMarc R. Hoffmann * Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors
3e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * All rights reserved. This program and the accompanying materials
4e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * are made available under the terms of the Eclipse Public License v1.0
5e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * which accompanies this distribution, and is available at
6e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * http://www.eclipse.org/legal/epl-v10.html
7e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *
8e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Contributors:
9e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *    Marc R. Hoffmann - initial API and implementation
10e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *
11e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *******************************************************************************/
12e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpackage org.jacoco.core.data;
13e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
14e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.ByteArrayOutputStream;
15e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.IOException;
16e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.io.OutputStream;
17e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
18e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.internal.data.CompactDataOutput;
19e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
20e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/**
21e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Serialization of execution data into binary streams.
22e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */
23e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpublic class ExecutionDataWriter implements ISessionInfoVisitor,
24e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		IExecutionDataVisitor {
25e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
26e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/** File format version, will be incremented for each incompatible change. */
27873114568ee148ea2e15cd036d57bf7b43ba154dMarc R. Hoffmann	public static final char FORMAT_VERSION = 0x1007;
28e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
29e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/** Magic number in header for file format identification. */
30e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public static final char MAGIC_NUMBER = 0xC0C0;
31e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
32e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/** Block identifier for file headers. */
33e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public static final byte BLOCK_HEADER = 0x01;
34e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
35e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/** Block identifier for session information. */
36e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public static final byte BLOCK_SESSIONINFO = 0x10;
37e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
38e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/** Block identifier for execution data of a single class. */
39e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public static final byte BLOCK_EXECUTIONDATA = 0x11;
40e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
41e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/** Underlying data output */
42e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	protected final CompactDataOutput out;
43e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
44e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
45e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Creates a new writer based on the given output stream. Depending on the
46e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * nature of the underlying stream output should be buffered as most data is
47e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * written in single bytes.
48e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
49e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @param output
50e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *            binary stream to write execution data to
51e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
52e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *             if the header can't be written
53e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
54e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public ExecutionDataWriter(final OutputStream output) throws IOException {
55e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		this.out = new CompactDataOutput(output);
56e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		writeHeader();
57e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
58e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
59e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
60e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Writes an file header to identify the stream and its protocol version.
61e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
62e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
6357f7cf06888f1e34f9ab2e3129c3d433826ecbe1Marc R. Hoffmann	 *             if the header can't be written
64e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
65e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	private void writeHeader() throws IOException {
66e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		out.writeByte(BLOCK_HEADER);
67e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		out.writeChar(MAGIC_NUMBER);
68e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		out.writeChar(FORMAT_VERSION);
69e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
70e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
71e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
72e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Flushes the underlying stream.
73e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
74e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @throws IOException
7557f7cf06888f1e34f9ab2e3129c3d433826ecbe1Marc R. Hoffmann	 *             if the underlying stream can't be flushed
76e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
77e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public void flush() throws IOException {
78e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		out.flush();
79e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
80e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
81e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public void visitSessionInfo(final SessionInfo info) {
82e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		try {
83e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.writeByte(BLOCK_SESSIONINFO);
84e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.writeUTF(info.getId());
85e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.writeLong(info.getStartTimeStamp());
86e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.writeLong(info.getDumpTimeStamp());
87e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		} catch (final IOException e) {
88e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throw new RuntimeException(e);
89e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
90e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
91e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
92e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public void visitClassExecution(final ExecutionData data) {
93e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		try {
94e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.writeByte(BLOCK_EXECUTIONDATA);
95e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.writeLong(data.getId());
96e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			out.writeUTF(data.getName());
9727e32e433ba0ac1fdec9290d3454d5b369c969ccMarc R. Hoffmann			out.writeBooleanArray(data.getProbes());
98e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		} catch (final IOException e) {
99e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throw new RuntimeException(e);
100e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
101e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
102e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
103e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	/**
104e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * Returns the first bytes of a file that represents a valid execution data
105e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * file. In any case every execution data file starts with the three bytes
106e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * <code>0x01 0xC0 0xC0</code>.
107e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 *
108e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 * @return first bytes of a execution data file
109e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	 */
110e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	public static final byte[] getFileHeader() {
111e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
112e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		try {
113e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			new ExecutionDataWriter(buffer);
114e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		} catch (final IOException e) {
115e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			// Must not happen with ByteArrayOutputStream
116e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov			throw new AssertionError(e);
117e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		}
118e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov		return buffer.toByteArray();
119e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov	}
120e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov
121e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov}
122