OSDN Git Service

Add new source files
[armadillo/armadillo1.git] / src / jp / sfjp / armadillo / compression / lzhuf / LzssOutputStream.java
1 package jp.sfjp.armadillo.compression.lzhuf;
2
3 import java.io.*;
4
5 public final class LzssOutputStream extends FilterOutputStream {
6
7     private final int dictionarySize;
8     private final int matchSize;
9     private final int threshold;
10
11     private boolean closed;
12     private LzssEncoderWritable output;
13     private byte[] buffer;
14     private int index;
15     private int limit;
16
17     public LzssOutputStream(LzssEncoderWritable output,
18                             int dictionarySize,
19                             int matchSize,
20                             int threshold) {
21         super(null);
22         this.closed = false;
23         this.output = output;
24         this.dictionarySize = dictionarySize;
25         this.matchSize = matchSize;
26         this.threshold = threshold;
27         this.buffer = new byte[dictionarySize];
28     }
29
30     @Override
31     public void write(int b) throws IOException {
32         write(new byte[]{(byte)b}, 0, 1);
33     }
34
35     @Override
36     public void write(byte[] b, int off, int len) throws IOException {
37         if (closed)
38             throw new IOException("stream already closed");
39         int remaining = len;
40         int offset = off;
41         while (remaining > 0) {
42             final int rest = dictionarySize - limit;
43             final int length = (rest < remaining) ? rest : remaining;
44             System.arraycopy(b, offset, buffer, limit, length);
45             remaining -= length;
46             offset += length;
47             limit += length;
48             if (length == rest)
49                 encode();
50         }
51     }
52
53     @Override
54     public void flush() throws IOException {
55         if (closed)
56             throw new IOException("stream already closed");
57         encode();
58         output.flush();
59     }
60
61     private void encode() throws IOException {
62         while (index < limit) {
63             /*
64              * linear search (and the performance is not good enough.)
65              */
66             int mark = -1;
67             int length = 0;
68             for (int i = index - 1; i >= 0; i--) {
69                 if (i + length >= limit
70                     || index + length >= limit
71                     || buffer[i] != buffer[index]
72                     || buffer[i + length] != buffer[index + length])
73                     continue;
74                 int matched = 0;
75                 while (matched < matchSize && index + matched < limit)
76                     if (buffer[i + matched] == buffer[index + matched])
77                         ++matched;
78                     else
79                         break;
80                 if (matched > length) {
81                     mark = i;
82                     length = matched;
83                 }
84             }
85             final int offset = (length >= threshold) ? index - mark : -1;
86             if (offset >= 0) {
87                 output.writeMatched(offset, length);
88                 index += length;
89             }
90             else
91                 output.write(buffer[index++] & 0xFF);
92         }
93         if (limit > dictionarySize - matchSize) {
94             index -= matchSize;
95             limit -= matchSize;
96             System.arraycopy(buffer, matchSize, buffer, 0, limit);
97         }
98     }
99
100     @Override
101     public void close() throws IOException {
102         if (closed)
103             throw new IOException("stream already closed");
104         try {
105             flush();
106         }
107         finally {
108             buffer = null;
109             output.close();
110             output = null;
111         }
112     }
113
114 }