1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 package org.apache.commons.compress.archivers;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 
25 /**
26  * Archive output stream implementations are expected to override the
27  * {@link #write(byte[], int, int)} method to improve performance.
28  * They should also override {@link #close()} to ensure that any necessary
29  * trailers are added.
30  *
31  * <p>The normal sequence of calls when working with ArchiveOutputStreams is:</p>
32  * <ul>
33  *   <li>Create ArchiveOutputStream object,</li>
34  *   <li>optionally write SFX header (Zip only),</li>
35  *   <li>repeat as needed:
36  *     <ul>
37  *       <li>{@link #putArchiveEntry(ArchiveEntry)} (writes entry header),
38  *       <li>{@link #write(byte[])} (writes entry data, as often as needed),
39  *       <li>{@link #closeArchiveEntry()} (closes entry),
40  *     </ul>
41  *   </li>
42  *   <li> {@link #finish()} (ends the addition of entries),</li>
43  *   <li> optionally write additional data, provided format supports it,</li>
44  *   <li>{@link #close()}.</li>
45  * </ul>
46  */
47 public abstract class ArchiveOutputStream extends OutputStream {
48 
49     /** Temporary buffer used for the {@link #write(int)} method */
50     private final byte[] oneByte = new byte[1];
51     static final int BYTE_MASK = 0xFF;
52 
53     /** holds the number of bytes written to this stream */
54     private long bytesWritten = 0;
55     // Methods specific to ArchiveOutputStream
56 
57     /**
58      * Writes the headers for an archive entry to the output stream.
59      * The caller must then write the content to the stream and call
60      * {@link #closeArchiveEntry()} to complete the process.
61      *
62      * @param entry describes the entry
63      * @throws IOException if an I/O error occurs
64      */
putArchiveEntry(ArchiveEntry entry)65     public abstract void putArchiveEntry(ArchiveEntry entry) throws IOException;
66 
67     /**
68      * Closes the archive entry, writing any trailer information that may
69      * be required.
70      * @throws IOException if an I/O error occurs
71      */
closeArchiveEntry()72     public abstract void closeArchiveEntry() throws IOException;
73 
74     /**
75      * Finishes the addition of entries to this stream, without closing it.
76      * Additional data can be written, if the format supports it.
77      *
78      * @throws IOException if the user forgets to close the entry.
79      */
finish()80     public abstract void finish() throws IOException;
81 
82     /**
83      * Create an archive entry using the inputFile and entryName provided.
84      *
85      * @param inputFile the file to create the entry from
86      * @param entryName name to use for the entry
87      * @return the ArchiveEntry set up with details from the file
88      *
89      * @throws IOException if an I/O error occurs
90      */
createArchiveEntry(File inputFile, String entryName)91     public abstract ArchiveEntry createArchiveEntry(File inputFile, String entryName) throws IOException;
92 
93     // Generic implementations of OutputStream methods that may be useful to sub-classes
94 
95     /**
96      * Writes a byte to the current archive entry.
97      *
98      * <p>This method simply calls {@code write( byte[], 0, 1 )}.
99      *
100      * <p>MUST be overridden if the {@link #write(byte[], int, int)} method
101      * is not overridden; may be overridden otherwise.
102      *
103      * @param b The byte to be written.
104      * @throws IOException on error
105      */
106     @Override
write(final int b)107     public void write(final int b) throws IOException {
108         oneByte[0] = (byte) (b & BYTE_MASK);
109         write(oneByte, 0, 1);
110     }
111 
112     /**
113      * Increments the counter of already written bytes.
114      * Doesn't increment if EOF has been hit ({@code written == -1}).
115      *
116      * @param written the number of bytes written
117      */
count(final int written)118     protected void count(final int written) {
119         count((long) written);
120     }
121 
122     /**
123      * Increments the counter of already written bytes.
124      * Doesn't increment if EOF has been hit ({@code written == -1}).
125      *
126      * @param written the number of bytes written
127      * @since 1.1
128      */
count(final long written)129     protected void count(final long written) {
130         if (written != -1) {
131             bytesWritten = bytesWritten + written;
132         }
133     }
134 
135     /**
136      * Returns the current number of bytes written to this stream.
137      * @return the number of written bytes
138      * @deprecated this method may yield wrong results for large
139      * archives, use #getBytesWritten instead
140      */
141     @Deprecated
getCount()142     public int getCount() {
143         return (int) bytesWritten;
144     }
145 
146     /**
147      * Returns the current number of bytes written to this stream.
148      * @return the number of written bytes
149      * @since 1.1
150      */
getBytesWritten()151     public long getBytesWritten() {
152         return bytesWritten;
153     }
154 
155     /**
156      * Whether this stream is able to write the given entry.
157      *
158      * <p>Some archive formats support variants or details that are
159      * not supported (yet).</p>
160      *
161      * @param archiveEntry
162      *            the entry to test
163      * @return This implementation always returns true.
164      * @since 1.1
165      */
canWriteEntryData(final ArchiveEntry archiveEntry)166     public boolean canWriteEntryData(final ArchiveEntry archiveEntry) {
167         return true;
168     }
169 }
170