1/*******************************************************************************
2 * Copyright (c) 2009, 2015 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 *******************************************************************************/
12package org.jacoco.report;
13
14import java.io.IOException;
15import java.io.OutputStream;
16import java.util.zip.ZipEntry;
17import java.util.zip.ZipOutputStream;
18
19/**
20 * Implementation of {@link IMultiReportOutput} that writes files into a
21 * {@link ZipOutputStream}.
22 */
23public class ZipMultiReportOutput implements IMultiReportOutput {
24
25	private final ZipOutputStream zip;
26
27	private OutputStream currentEntry;
28
29	/**
30	 * Creates a new instance based on the given {@link ZipOutputStream}.
31	 *
32	 * @param zip
33	 *            stream to write file entries to
34	 */
35	public ZipMultiReportOutput(final ZipOutputStream zip) {
36		this.zip = zip;
37	}
38
39	/**
40	 * Creates a new instance based on the given {@link OutputStream}.
41	 *
42	 * @param out
43	 *            stream to write file entries to
44	 */
45	public ZipMultiReportOutput(final OutputStream out) {
46		this(new ZipOutputStream(out));
47	}
48
49	public OutputStream createFile(final String path) throws IOException {
50		if (currentEntry != null) {
51			currentEntry.close();
52		}
53		final ZipEntry entry = new ZipEntry(path);
54		zip.putNextEntry(entry);
55		currentEntry = new EntryOutput();
56		return currentEntry;
57	}
58
59	public void close() throws IOException {
60		zip.close();
61	}
62
63	private final class EntryOutput extends OutputStream {
64
65		private boolean closed = false;
66
67		@Override
68		public void write(final byte[] b, final int off, final int len)
69				throws IOException {
70			ensureNotClosed();
71			zip.write(b, off, len);
72		}
73
74		@Override
75		public void write(final byte[] b) throws IOException {
76			ensureNotClosed();
77			zip.write(b);
78		}
79
80		@Override
81		public void write(final int b) throws IOException {
82			ensureNotClosed();
83			zip.write(b);
84		}
85
86		@Override
87		public void flush() throws IOException {
88			ensureNotClosed();
89			zip.flush();
90		}
91
92		@Override
93		public void close() throws IOException {
94			if (!closed) {
95				closed = true;
96				zip.closeEntry();
97			}
98		}
99
100		private void ensureNotClosed() throws IOException {
101			if (closed) {
102				throw new IOException("Zip entry already closed.");
103			}
104		}
105
106	}
107
108}
109