• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * SimpleOutputStream
3  *
4  * Author: Lasse Collin <lasse.collin@tukaani.org>
5  *
6  * This file has been put into the public domain.
7  * You can do whatever you want with this file.
8  */
9 
10 package org.tukaani.xz;
11 
12 import java.io.IOException;
13 import org.tukaani.xz.simple.SimpleFilter;
14 
15 class SimpleOutputStream extends FinishableOutputStream {
16     private static final int FILTER_BUF_SIZE = 4096;
17 
18     private FinishableOutputStream out;
19     private final SimpleFilter simpleFilter;
20 
21     private final byte[] filterBuf = new byte[FILTER_BUF_SIZE];
22     private int pos = 0;
23     private int unfiltered = 0;
24 
25     private IOException exception = null;
26     private boolean finished = false;
27 
28     private final byte[] tempBuf = new byte[1];
29 
getMemoryUsage()30     static int getMemoryUsage() {
31         return 1 + FILTER_BUF_SIZE / 1024;
32     }
33 
SimpleOutputStream(FinishableOutputStream out, SimpleFilter simpleFilter)34     SimpleOutputStream(FinishableOutputStream out,
35                        SimpleFilter simpleFilter) {
36         if (out == null)
37             throw new NullPointerException();
38 
39         this.out = out;
40         this.simpleFilter = simpleFilter;
41     }
42 
write(int b)43     public void write(int b) throws IOException {
44         tempBuf[0] = (byte)b;
45         write(tempBuf, 0, 1);
46     }
47 
write(byte[] buf, int off, int len)48     public void write(byte[] buf, int off, int len) throws IOException {
49         if (off < 0 || len < 0 || off + len < 0 || off + len > buf.length)
50             throw new IndexOutOfBoundsException();
51 
52         if (exception != null)
53             throw exception;
54 
55         if (finished)
56             throw new XZIOException("Stream finished or closed");
57 
58         while (len > 0) {
59             // Copy more unfiltered data into filterBuf.
60             int copySize = Math.min(len, FILTER_BUF_SIZE - (pos + unfiltered));
61             System.arraycopy(buf, off, filterBuf, pos + unfiltered, copySize);
62             off += copySize;
63             len -= copySize;
64             unfiltered += copySize;
65 
66             // Filter the data in filterBuf.
67             int filtered = simpleFilter.code(filterBuf, pos, unfiltered);
68             assert filtered <= unfiltered;
69             unfiltered -= filtered;
70 
71             // Write out the filtered data.
72             try {
73                 out.write(filterBuf, pos, filtered);
74             } catch (IOException e) {
75                 exception = e;
76                 throw e;
77             }
78 
79             pos += filtered;
80 
81             // If end of filterBuf was reached, move the pending unfiltered
82             // data to the beginning of the buffer so that more data can
83             // be copied into filterBuf on the next loop iteration.
84             if (pos + unfiltered == FILTER_BUF_SIZE) {
85                 System.arraycopy(filterBuf, pos, filterBuf, 0, unfiltered);
86                 pos = 0;
87             }
88         }
89     }
90 
writePending()91     private void writePending() throws IOException {
92         assert !finished;
93 
94         if (exception != null)
95             throw exception;
96 
97         try {
98             out.write(filterBuf, pos, unfiltered);
99         } catch (IOException e) {
100             exception = e;
101             throw e;
102         }
103 
104         finished = true;
105     }
106 
flush()107     public void flush() throws IOException {
108         throw new UnsupportedOptionsException("Flushing is not supported");
109     }
110 
finish()111     public void finish() throws IOException {
112         if (!finished) {
113             // If it fails, don't call out.finish().
114             writePending();
115 
116             try {
117                 out.finish();
118             } catch (IOException e) {
119                 exception = e;
120                 throw e;
121             }
122         }
123     }
124 
close()125     public void close() throws IOException {
126         if (out != null) {
127             if (!finished) {
128                 // out.close() must be called even if writePending() fails.
129                 // writePending() saves the possible exception so we can
130                 // ignore exceptions here.
131                 try {
132                     writePending();
133                 } catch (IOException e) {}
134             }
135 
136             try {
137                 out.close();
138             } catch (IOException e) {
139                 // If there is an earlier exception, the exception
140                 // from out.close() is lost.
141                 if (exception == null)
142                     exception = e;
143             }
144 
145             out = null;
146         }
147 
148         if (exception != null)
149             throw exception;
150     }
151 }
152