mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-05 10:49:24 +02:00
zip/epub optimizations
git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@897 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
parent
e372718dc1
commit
eebd831047
11 changed files with 289 additions and 287 deletions
|
@ -4,14 +4,15 @@ final class CircularBuffer {
|
|||
static final int DICTIONARY_LENGTH = (1 << 15);
|
||||
private static final int DICTIONARY_MASK = DICTIONARY_LENGTH - 1;
|
||||
|
||||
private final byte[] myBuffer;
|
||||
private final byte[] myBuffer = new byte[DICTIONARY_LENGTH];
|
||||
private int myBytesReady; // number of bytes can be read
|
||||
private int myCurrentPosition; // the next byte to read is
|
||||
// myDictionary[myCurrentPosition]
|
||||
|
||||
public CircularBuffer() {
|
||||
myBuffer = new byte[DICTIONARY_LENGTH];
|
||||
}
|
||||
void reset() {
|
||||
myBytesReady = 0;
|
||||
myCurrentPosition = 0;
|
||||
}
|
||||
|
||||
public int available() {
|
||||
return myBytesReady;
|
||||
|
|
|
@ -3,122 +3,101 @@ package org.amse.ys.zip;
|
|||
public class CodeBuilder {
|
||||
public static final int MAX_HUFFMAN_CODE_LENGTH = 15;
|
||||
|
||||
final private int[] myCodeArray;
|
||||
final private int[] myLengthArray;
|
||||
private int myNumberOfCodes;
|
||||
private boolean myCodesAreBuild;
|
||||
|
||||
public CodeBuilder(int maxNumberOfCodes) {
|
||||
myCodeArray = new int[maxNumberOfCodes];
|
||||
myLengthArray = new int[maxNumberOfCodes];
|
||||
myNumberOfCodes = maxNumberOfCodes;
|
||||
myLengthArray = new int[maxNumberOfCodes];
|
||||
}
|
||||
|
||||
public void addCodeLength(int codeNumber, int codeLen) {
|
||||
if (!myCodesAreBuild) {
|
||||
myLengthArray[codeNumber] = codeLen;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Trying to addCodeLength after biulding huffman codes");
|
||||
}
|
||||
myLengthArray[codeNumber] = codeLen;
|
||||
}
|
||||
|
||||
private void buildCodes() {
|
||||
// counting number of codes for definite length
|
||||
int[] b1_count = new int[MAX_HUFFMAN_CODE_LENGTH + 1];
|
||||
for (int i = 0; i < myNumberOfCodes; i++) {
|
||||
b1_count[myLengthArray[i]]++;
|
||||
}
|
||||
b1_count[0] = 0;
|
||||
public void buildTable(int[] table) {
|
||||
final int arrayLength = myLengthArray.length;
|
||||
|
||||
// step 2
|
||||
int[] next_code = new int[MAX_HUFFMAN_CODE_LENGTH + 1];
|
||||
int code = 0;
|
||||
for (int bits = 1; bits <= MAX_HUFFMAN_CODE_LENGTH; bits++) {
|
||||
code = ((code + b1_count[bits - 1]) << 1);
|
||||
next_code[bits] = code;
|
||||
}
|
||||
// counting number of codes for definite length
|
||||
int[] b1_count = new int[MAX_HUFFMAN_CODE_LENGTH + 1];
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
b1_count[myLengthArray[i]]++;
|
||||
}
|
||||
b1_count[0] = 0;
|
||||
|
||||
// step 3
|
||||
for (int i = 0; i < myNumberOfCodes; i++) {
|
||||
int len = myLengthArray[i];
|
||||
if (len != 0) {
|
||||
myCodeArray[i] = next_code[len];
|
||||
next_code[len]++;
|
||||
}
|
||||
}
|
||||
myCodesAreBuild = true;
|
||||
// step 2
|
||||
int[] next_code = new int[MAX_HUFFMAN_CODE_LENGTH + 1];
|
||||
int code = 0;
|
||||
for (int bits = 1; bits <= MAX_HUFFMAN_CODE_LENGTH; bits++) {
|
||||
code = ((code + b1_count[bits - 1]) << 1);
|
||||
next_code[bits] = code;
|
||||
}
|
||||
|
||||
// step 3
|
||||
for (int i = 0; i < arrayLength; ++i) {
|
||||
final int codeLength = myLengthArray[i];
|
||||
if (codeLength > 0) {
|
||||
int revertedCode = next_code[codeLength]++;
|
||||
int c = 0;
|
||||
for (int j = 0; j < codeLength; ++j) {
|
||||
c = (c << 1) + (revertedCode & 1);
|
||||
revertedCode >>= 1;
|
||||
}
|
||||
final int value = (codeLength << 16) + i;
|
||||
for (int j = 0; j < (1 << (15 - codeLength)); ++j) {
|
||||
table[(j << codeLength) + c] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int[] returnArrayOfCodes() {
|
||||
if (!myCodesAreBuild) {
|
||||
buildCodes();
|
||||
}
|
||||
return myCodeArray;
|
||||
}
|
||||
|
||||
public int[] returnArrayOfLengths() {
|
||||
return myLengthArray;
|
||||
}
|
||||
|
||||
public int[] buildTable() {
|
||||
final int[] table = new int[1 << 15];
|
||||
|
||||
if (!myCodesAreBuild) {
|
||||
buildCodes();
|
||||
}
|
||||
final int length = myCodeArray.length;
|
||||
public void buildTable(int[] codeArray, int[] table) {
|
||||
final int length = codeArray.length;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
final int codeLength = myLengthArray[i];
|
||||
if (codeLength > 0) {
|
||||
int revertedCode = myCodeArray[i];
|
||||
int code = 0;
|
||||
for (int j = 0; j < codeLength; ++j) {
|
||||
code = (code << 1) + (revertedCode & 1);
|
||||
revertedCode >>= 1;
|
||||
}
|
||||
final int value = (codeLength << 16) + i;
|
||||
for (int j = 0; j < (1 << (15 - codeLength)); ++j) {
|
||||
table[(j << codeLength) + code] = value;
|
||||
}
|
||||
}
|
||||
final int codeLength = myLengthArray[i];
|
||||
if (codeLength > 0) {
|
||||
int revertedCode = codeArray[i];
|
||||
int code = 0;
|
||||
for (int j = 0; j < codeLength; ++j) {
|
||||
code = (code << 1) + (revertedCode & 1);
|
||||
revertedCode >>= 1;
|
||||
}
|
||||
final int value = (codeLength << 16) + i;
|
||||
for (int j = 0; j < (1 << (15 - codeLength)); ++j) {
|
||||
table[(j << codeLength) + code] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private void loadFixed() {
|
||||
for (int i = 0; i <= 143; i++) {
|
||||
//
|
||||
myCodeArray[i] = 48 + i;
|
||||
myLengthArray[i] = 8;
|
||||
}
|
||||
for (int i = 144; i <= 255; i++) {
|
||||
myLengthArray[i] = 9;
|
||||
myCodeArray[i] = 256 + i;
|
||||
}
|
||||
for (int i = 256; i <= 279; i++) {
|
||||
myLengthArray[i] = 7;
|
||||
myCodeArray[i] = 0 + i - 256;
|
||||
}
|
||||
for (int i = 280; i <= 287; i++) {
|
||||
myCodeArray[i] = 192 + i - 280;
|
||||
myLengthArray[i] = 8;
|
||||
}
|
||||
public static void buildFixedHuffmanCodes(int[] table) {
|
||||
CodeBuilder builder = new CodeBuilder(288);
|
||||
final int[] codeArray = new int[288];
|
||||
for (int i = 0; i <= 143; i++) {
|
||||
builder.myLengthArray[i] = 8;
|
||||
codeArray[i] = 48 + i;
|
||||
}
|
||||
for (int i = 144; i <= 255; i++) {
|
||||
builder.myLengthArray[i] = 9;
|
||||
codeArray[i] = 256 + i;
|
||||
}
|
||||
for (int i = 256; i <= 279; i++) {
|
||||
builder.myLengthArray[i] = 7;
|
||||
codeArray[i] = 0 + i - 256;
|
||||
}
|
||||
for (int i = 280; i <= 287; i++) {
|
||||
builder.myLengthArray[i] = 8;
|
||||
codeArray[i] = 192 + i - 280;
|
||||
}
|
||||
builder.buildTable(codeArray, table);
|
||||
}
|
||||
|
||||
public static CodeBuilder buildFixedHuffmanCodes() {
|
||||
CodeBuilder builder = new CodeBuilder(288);
|
||||
builder.loadFixed();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static CodeBuilder buildFixedDistanceCodes() {
|
||||
CodeBuilder builder = new CodeBuilder(32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
builder.myCodeArray[i] = i;
|
||||
builder.myLengthArray[i] = 5;
|
||||
}
|
||||
return builder;
|
||||
public static void buildFixedDistanceCodes(int[] table) {
|
||||
CodeBuilder builder = new CodeBuilder(32);
|
||||
final int[] codeArray = new int[32];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
codeArray[i] = i;
|
||||
builder.myLengthArray[i] = 5;
|
||||
}
|
||||
builder.buildTable(codeArray, table);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
package org.amse.ys.zip;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public abstract class Decompressor {
|
||||
public Decompressor(MyBufferedInputStream is, LocalFileHeader header) {
|
||||
|
||||
}
|
||||
|
||||
public abstract int read(byte b[], int off, int len) throws IOException, WrongZipFormatException;
|
||||
public abstract int read() throws IOException, WrongZipFormatException;
|
||||
|
||||
protected Decompressor() {
|
||||
}
|
||||
|
||||
private static Queue<DeflatingDecompressor> ourDeflators = new LinkedList<DeflatingDecompressor>();
|
||||
|
||||
static void storeDecompressor(Decompressor decompressor) {
|
||||
if (decompressor instanceof DeflatingDecompressor) {
|
||||
synchronized (ourDeflators) {
|
||||
ourDeflators.add((DeflatingDecompressor)decompressor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Decompressor init(MyBufferedInputStream is, LocalFileHeader header)
|
||||
|
@ -20,10 +29,16 @@ public abstract class Decompressor {
|
|||
case 0:
|
||||
return new NoCompressionDecompressor(is, header);
|
||||
case 8:
|
||||
synchronized (ourDeflators) {
|
||||
if (!ourDeflators.isEmpty()) {
|
||||
DeflatingDecompressor decompressor = ourDeflators.poll();
|
||||
decompressor.reset(is, header);
|
||||
return decompressor;
|
||||
}
|
||||
}
|
||||
return new DeflatingDecompressor(is, header);
|
||||
default:
|
||||
throw new WrongZipFormatException(
|
||||
"Unsupported method of compression");
|
||||
throw new WrongZipFormatException("Unsupported method of compression");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,31 +10,52 @@ public class DeflatingDecompressor extends Decompressor {
|
|||
private static final int ST_END_OF_FILE = 5;
|
||||
|
||||
// common variables
|
||||
private final LocalFileHeader myHeader;
|
||||
private final MyBufferedInputStream myStream;
|
||||
private MyBufferedInputStream myStream;
|
||||
private LocalFileHeader myHeader;
|
||||
private int myState;
|
||||
private int myTotalLength;
|
||||
private int myBytesRead;
|
||||
private int myCurrentPosition;
|
||||
private boolean myTheBlockIsFinal = false;
|
||||
private boolean myTheBlockIsFinal;
|
||||
|
||||
// for bit reader
|
||||
private int myBitsInBuffer;
|
||||
private int myTempInt; // should contain 16 bit available for reading
|
||||
|
||||
// output buffer
|
||||
private final CircularBuffer myOutputBuffer;
|
||||
private final CircularBuffer myOutputBuffer = new CircularBuffer();
|
||||
|
||||
// for no compression method
|
||||
private int myCurrentBlockLength;
|
||||
private int myReadInBlock;
|
||||
|
||||
// for Huffman codes
|
||||
private int[] myHuffmanCodes;
|
||||
private int[] myDistanceCodes;
|
||||
private final int[] myHuffmanCodes = new int[1 << 15];
|
||||
private final int[] myDistanceCodes = new int[1 << 15];
|
||||
private final int[] myAuxCodes = new int[1 << 15];
|
||||
|
||||
public DeflatingDecompressor(MyBufferedInputStream inputStream, LocalFileHeader header) {
|
||||
super();
|
||||
reset(inputStream, header);
|
||||
}
|
||||
|
||||
void reset(MyBufferedInputStream inputStream, LocalFileHeader header) {
|
||||
myStream = inputStream;
|
||||
myHeader = header;
|
||||
myTotalLength = header.getCompressedSize();
|
||||
myBytesRead = 0;
|
||||
myCurrentPosition = 0;
|
||||
myTheBlockIsFinal = false;
|
||||
myState = ST_HEADER;
|
||||
myOutputBuffer.reset();
|
||||
myBitsInBuffer = 0;
|
||||
myTempInt = 0;
|
||||
myCurrentBlockLength = 0;
|
||||
myReadInBlock = 0;
|
||||
}
|
||||
|
||||
public int available() {
|
||||
return (myHeader.getUncompressedSize() - myCurrentPosition);
|
||||
return myHeader.getUncompressedSize() - myCurrentPosition;
|
||||
}
|
||||
|
||||
private void ensure16BitsInBuffer() throws IOException {
|
||||
|
@ -75,17 +96,6 @@ public class DeflatingDecompressor extends Decompressor {
|
|||
return result;
|
||||
}
|
||||
|
||||
public DeflatingDecompressor(MyBufferedInputStream is, LocalFileHeader header) {
|
||||
super();
|
||||
myHeader = header;
|
||||
myStream = is;
|
||||
myBitsInBuffer = 0;
|
||||
myOutputBuffer = new CircularBuffer();
|
||||
myTotalLength = header.getCompressedSize();
|
||||
myBytesRead = 0;
|
||||
myState = ST_HEADER;
|
||||
}
|
||||
|
||||
private static final int MAX_LEN = CircularBuffer.DICTIONARY_LENGTH / 2;
|
||||
|
||||
public int read(byte b[], int off, int len) throws IOException, WrongZipFormatException {
|
||||
|
@ -255,8 +265,8 @@ public class DeflatingDecompressor extends Decompressor {
|
|||
break;
|
||||
case 1:
|
||||
myState = ST_FIXED_CODES;
|
||||
myHuffmanCodes = CodeBuilder.buildFixedHuffmanCodes().buildTable();
|
||||
myDistanceCodes = CodeBuilder.buildFixedDistanceCodes().buildTable();
|
||||
CodeBuilder.buildFixedHuffmanCodes(myHuffmanCodes);
|
||||
CodeBuilder.buildFixedDistanceCodes(myDistanceCodes);
|
||||
break;
|
||||
case 2:
|
||||
myState = ST_DYNAMIC_CODES;
|
||||
|
@ -288,12 +298,12 @@ public class DeflatingDecompressor extends Decompressor {
|
|||
readIntegerByBit(3));
|
||||
}
|
||||
|
||||
final int[] distHuffmanCodes = headerReadingCoder.buildTable();
|
||||
headerReadingCoder.buildTable(myAuxCodes);
|
||||
|
||||
CodeBuilder usualCodeBuilder = new CodeBuilder(288);
|
||||
int previousNumber = 0;
|
||||
for (int i = 0; i < (numberOfLiteralCodes + 257); i++) {
|
||||
int currentHuffmanCode = readHuffmanCode(distHuffmanCodes);
|
||||
int currentHuffmanCode = readHuffmanCode(myAuxCodes);
|
||||
//headersFound++;
|
||||
if (currentHuffmanCode <= 15) {
|
||||
usualCodeBuilder.addCodeLength(i, currentHuffmanCode);
|
||||
|
@ -326,13 +336,13 @@ public class DeflatingDecompressor extends Decompressor {
|
|||
}
|
||||
}
|
||||
// we can build huffman codes for charset
|
||||
myHuffmanCodes = usualCodeBuilder.buildTable();
|
||||
usualCodeBuilder.buildTable(myHuffmanCodes);
|
||||
|
||||
// building distance codes
|
||||
CodeBuilder distanceCodeBuilder = new CodeBuilder(32);
|
||||
previousNumber = 0;
|
||||
for (int i = 0; i < (numberOfDistanceCodes + 1); i++) {
|
||||
int currentHuffmanCode = readHuffmanCode(distHuffmanCodes);
|
||||
int currentHuffmanCode = readHuffmanCode(myAuxCodes);
|
||||
//headersFound++;
|
||||
if (currentHuffmanCode <= 15) {
|
||||
distanceCodeBuilder.addCodeLength(i, currentHuffmanCode);
|
||||
|
@ -364,6 +374,6 @@ public class DeflatingDecompressor extends Decompressor {
|
|||
i += (repeatNumber - 1);
|
||||
}
|
||||
}
|
||||
myDistanceCodes = distanceCodeBuilder.buildTable();
|
||||
distanceCodeBuilder.buildTable(myDistanceCodes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,12 +59,10 @@ public class LocalFileHeader {
|
|||
}
|
||||
|
||||
void setSizes(int compressedSize, int uncompressedSize) {
|
||||
if (mySizeIsKnown) {
|
||||
throw new RuntimeException(
|
||||
"Was attempt to change file sizes with use of setSizes");
|
||||
if (!mySizeIsKnown) {
|
||||
myCompressedSize = compressedSize;
|
||||
myUncompressedSize = uncompressedSize;
|
||||
mySizeIsKnown = true;
|
||||
}
|
||||
myCompressedSize = compressedSize;
|
||||
myUncompressedSize = uncompressedSize;
|
||||
mySizeIsKnown = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ final class MyBufferedInputStream extends InputStream {
|
|||
int myPositionInBuffer;
|
||||
private int myCurrentPosition;
|
||||
|
||||
public MyBufferedInputStream(String s, int arraySize) throws IOException {
|
||||
myFileName = s;
|
||||
myFileInputStream = new FileInputStream(s);
|
||||
myBuffer = new byte[arraySize];
|
||||
public MyBufferedInputStream(String fileName, int bufferSize) throws IOException {
|
||||
myFileName = fileName;
|
||||
myFileInputStream = new FileInputStream(fileName);
|
||||
myBuffer = new byte[bufferSize];
|
||||
myBytesReady = 0;
|
||||
myPositionInBuffer = 0;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ final class MyBufferedInputStream extends InputStream {
|
|||
}
|
||||
}
|
||||
myBytesReady--;
|
||||
return (myBuffer[myPositionInBuffer++] & 255);
|
||||
return myBuffer[myPositionInBuffer++] & 255;
|
||||
}
|
||||
|
||||
int read2Bytes() throws IOException {
|
||||
|
@ -113,5 +113,4 @@ final class MyBufferedInputStream extends InputStream {
|
|||
myFileInputStream.close();
|
||||
myBytesReady = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package org.amse.ys.zip;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Collection;
|
||||
import java.util.Queue;
|
||||
import java.util.LinkedList;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class ZipFile {
|
||||
private final String myFileName;
|
||||
private final ArrayList<LocalFileHeader> myFileHeaders = new ArrayList<LocalFileHeader>();
|
||||
private final TreeMap<String,LocalFileHeader> myFileHeaders = new TreeMap<String,LocalFileHeader>();
|
||||
private final MyBufferedInputStream myBaseStream;
|
||||
|
||||
private boolean myAllFilesAreRead;
|
||||
|
@ -17,13 +18,13 @@ public class ZipFile {
|
|||
myBaseStream = new MyBufferedInputStream(myFileName);
|
||||
}
|
||||
|
||||
public List<LocalFileHeader> headers() {
|
||||
public Collection<LocalFileHeader> headers() {
|
||||
try {
|
||||
readAllHeaders();
|
||||
} catch (IOException e) {
|
||||
} catch (WrongZipFormatException e) {
|
||||
}
|
||||
return Collections.unmodifiableList(myFileHeaders);
|
||||
return myFileHeaders.values();
|
||||
}
|
||||
|
||||
private boolean readFileHeader(String fileToFind) throws IOException {
|
||||
|
@ -39,20 +40,16 @@ public class ZipFile {
|
|||
|
||||
final String fileName = myBaseStream.readString(fileNameSize);
|
||||
myBaseStream.skip(extraField);
|
||||
myFileHeaders.add(new LocalFileHeader(version2extract, generalFlag,
|
||||
LocalFileHeader header = new LocalFileHeader(version2extract, generalFlag,
|
||||
compressionMethod, compressedSize, uncompressedSize,
|
||||
myBaseStream.offset(), fileName));
|
||||
if (fileName.equals(fileToFind)) {
|
||||
return true;
|
||||
}
|
||||
if ((generalFlag & 8) == 0) {
|
||||
myBaseStream.offset(), fileName);
|
||||
myFileHeaders.put(fileName, header);
|
||||
if (header.sizeIsKnown()) {
|
||||
myBaseStream.skip(compressedSize);
|
||||
} else {
|
||||
System.out
|
||||
.println("Warning: flag 3 is set! Trying to find header.");
|
||||
findAndReadDescriptor();
|
||||
findAndReadDescriptor(header);
|
||||
}
|
||||
return false;
|
||||
return fileName.equals(fileToFind);
|
||||
}
|
||||
|
||||
private void readAllHeaders() throws IOException, WrongZipFormatException {
|
||||
|
@ -61,6 +58,9 @@ public class ZipFile {
|
|||
}
|
||||
myAllFilesAreRead = true;
|
||||
|
||||
myBaseStream.reset();
|
||||
myFileHeaders.clear();
|
||||
|
||||
while (true) {
|
||||
int header = myBaseStream.read4Bytes();
|
||||
if (header != LocalFileHeader.FILE_HEADER_SIGNATURE) {
|
||||
|
@ -80,8 +80,7 @@ public class ZipFile {
|
|||
/**
|
||||
* Finds descriptor of the last header and installs sizes of files
|
||||
*/
|
||||
private void findAndReadDescriptor() throws IOException {
|
||||
byte[] tempArray = new byte[12];
|
||||
private void findAndReadDescriptor(LocalFileHeader header) throws IOException {
|
||||
while (true) {
|
||||
int signature = 0;
|
||||
do {
|
||||
|
@ -90,23 +89,13 @@ public class ZipFile {
|
|||
throw new IOException(
|
||||
"readFileHeaders. Unexpected end of file when looking for DataDescriptor");
|
||||
}
|
||||
signature = ((signature << 8) & (0x0ffffffff))
|
||||
+ (byte) nextByte;
|
||||
signature = ((signature << 8) & (0x0FFFFFFFF)) + (byte) nextByte;
|
||||
} while (signature != LocalFileHeader.DATA_DESCRIPTOR_SIGNATURE);
|
||||
myBaseStream.read(tempArray);
|
||||
int compressedSize =
|
||||
((tempArray[7] & 0xff) << 24) +
|
||||
((tempArray[6] & 0xff) << 16) +
|
||||
((tempArray[5] & 0xff) << 8) +
|
||||
(tempArray[4] & 0xff);
|
||||
int uncompressedSize =
|
||||
((tempArray[11] & 0xff) << 24) +
|
||||
((tempArray[10] & 0xff) << 16) +
|
||||
((tempArray[9] & 0xff) << 8) +
|
||||
(tempArray[8] & 0xff);
|
||||
LocalFileHeader lastHeader = myFileHeaders.get(myFileHeaders.size() - 1);
|
||||
if ((myBaseStream.offset() - lastHeader.OffsetOfLocalData - 16) == compressedSize) {
|
||||
lastHeader.setSizes(compressedSize, uncompressedSize);
|
||||
myBaseStream.skip(4);
|
||||
int compressedSize = myBaseStream.read4Bytes();
|
||||
int uncompressedSize = myBaseStream.read4Bytes();
|
||||
if ((myBaseStream.offset() - header.OffsetOfLocalData - 16) == compressedSize) {
|
||||
header.setSizes(compressedSize, uncompressedSize);
|
||||
break;
|
||||
} else {
|
||||
myBaseStream.backSkip(12);
|
||||
|
@ -115,30 +104,36 @@ public class ZipFile {
|
|||
}
|
||||
}
|
||||
|
||||
private final Queue<MyBufferedInputStream> myStoredStreams = new LinkedList<MyBufferedInputStream>();
|
||||
|
||||
synchronized void storeBaseStream(MyBufferedInputStream baseStream) {
|
||||
myStoredStreams.add(baseStream);
|
||||
}
|
||||
|
||||
synchronized private ZipInputStream createZipInputStream(LocalFileHeader header) throws IOException, WrongZipFormatException {
|
||||
MyBufferedInputStream baseStream =
|
||||
myStoredStreams.isEmpty() ?
|
||||
new MyBufferedInputStream(myFileName) :
|
||||
myStoredStreams.poll();
|
||||
return new ZipInputStream(this, baseStream, header);
|
||||
}
|
||||
|
||||
public InputStream getInputStream(String entryName) throws IOException {
|
||||
if (!myFileHeaders.isEmpty()) {
|
||||
// trying to find in already ready array
|
||||
int i;
|
||||
final int listSize = myFileHeaders.size();
|
||||
LocalFileHeader header = null;
|
||||
for (i = 0; i < listSize; i++) {
|
||||
header = myFileHeaders.get(i);
|
||||
if (header.FileName.equals(entryName)) {
|
||||
try {
|
||||
return new ZipInputStream(myFileName, header);
|
||||
} catch (WrongZipFormatException e) {
|
||||
return null;
|
||||
}
|
||||
LocalFileHeader header = myFileHeaders.get(entryName);
|
||||
if (header != null) {
|
||||
try {
|
||||
return createZipInputStream(header);
|
||||
} catch (WrongZipFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (myAllFilesAreRead) {
|
||||
return null;
|
||||
}
|
||||
if (header.sizeIsKnown()) {
|
||||
myBaseStream.setPosition(header.OffsetOfLocalData + header.getCompressedSize());
|
||||
} else {
|
||||
findAndReadDescriptor();
|
||||
}
|
||||
}
|
||||
// ready to read fileheader
|
||||
do {
|
||||
|
@ -153,13 +148,12 @@ public class ZipFile {
|
|||
}
|
||||
}
|
||||
} while (!readFileHeader(entryName));
|
||||
LocalFileHeader header = myFileHeaders.get(myFileHeaders.size() - 1);
|
||||
if (header.FileName.equals(entryName)) {
|
||||
try {
|
||||
return new ZipInputStream(myFileName, header);
|
||||
} catch (WrongZipFormatException e) {
|
||||
return null;
|
||||
}
|
||||
LocalFileHeader header = myFileHeaders.get(entryName);
|
||||
if (header != null) {
|
||||
try {
|
||||
return createZipInputStream(header);
|
||||
} catch (WrongZipFormatException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -5,17 +5,17 @@ import java.util.List;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
public class ZipInputStream extends InputStream {
|
||||
class ZipInputStream extends InputStream {
|
||||
private final ZipFile myParent;
|
||||
private final MyBufferedInputStream myBaseStream;
|
||||
private final LocalFileHeader myHeader;
|
||||
private final Decompressor myDecompressor;
|
||||
private boolean myIsClosed;
|
||||
|
||||
public ZipInputStream(String fileName, LocalFileHeader header) throws IOException, WrongZipFormatException {
|
||||
if (!header.sizeIsKnown()) {
|
||||
throw new RuntimeException("Reading of files with flag 3 is not implemented yet");
|
||||
}
|
||||
myBaseStream = new MyBufferedInputStream(fileName);
|
||||
myBaseStream.setPosition(header.OffsetOfLocalData);
|
||||
public ZipInputStream(ZipFile parent, MyBufferedInputStream baseStream, LocalFileHeader header) throws IOException, WrongZipFormatException {
|
||||
myParent = parent;
|
||||
myBaseStream = baseStream;
|
||||
baseStream.setPosition(header.OffsetOfLocalData);
|
||||
myHeader = header;
|
||||
myDecompressor = Decompressor.init(myBaseStream, header);
|
||||
}
|
||||
|
@ -50,6 +50,10 @@ public class ZipInputStream extends InputStream {
|
|||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
myBaseStream.close();
|
||||
if (!myIsClosed) {
|
||||
myIsClosed = true;
|
||||
myParent.storeBaseStream(myBaseStream);
|
||||
Decompressor.storeDecompressor(myDecompressor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,7 @@ public class OEBPlugin extends FormatPlugin {
|
|||
|
||||
public boolean acceptsFile(ZLFile file) {
|
||||
final String extension = file.getExtension().intern();
|
||||
return (extension == "opf") ||
|
||||
(extension == "oebzip") ||
|
||||
(extension == "epub");
|
||||
return (extension == "opf") || (extension == "oebzip") || (extension == "epub");
|
||||
}
|
||||
|
||||
private String getOpfFileName(String oebFileName) {
|
||||
|
|
|
@ -37,79 +37,81 @@ public class XHTMLReader extends ZLXMLReaderAdapter {
|
|||
}
|
||||
|
||||
public static void fillTagTable() {
|
||||
if (ourTagActions.isEmpty()) {
|
||||
//addAction("html", new XHTMLTagAction());
|
||||
addAction("body", new XHTMLTagBodyAction());
|
||||
//addAction("title", new XHTMLTagAction());
|
||||
//addAction("meta", new XHTMLTagAction());
|
||||
//addAction("script", new XHTMLTagAction());
|
||||
|
||||
//addAction("font", new XHTMLTagAction());
|
||||
//addAction("style", new XHTMLTagAction());
|
||||
|
||||
addAction("p", new XHTMLTagParagraphAction());
|
||||
addAction("h1", new XHTMLTagParagraphWithControlAction(FBTextKind.H1));
|
||||
addAction("h2", new XHTMLTagParagraphWithControlAction(FBTextKind.H2));
|
||||
addAction("h3", new XHTMLTagParagraphWithControlAction(FBTextKind.H3));
|
||||
addAction("h4", new XHTMLTagParagraphWithControlAction(FBTextKind.H4));
|
||||
addAction("h5", new XHTMLTagParagraphWithControlAction(FBTextKind.H5));
|
||||
addAction("h6", new XHTMLTagParagraphWithControlAction(FBTextKind.H6));
|
||||
|
||||
//addAction("ol", new XHTMLTagAction());
|
||||
//addAction("ul", new XHTMLTagAction());
|
||||
//addAction("dl", new XHTMLTagAction());
|
||||
addAction("li", new XHTMLTagItemAction());
|
||||
|
||||
addAction("strong", new XHTMLTagControlAction(FBTextKind.STRONG));
|
||||
addAction("b", new XHTMLTagControlAction(FBTextKind.BOLD));
|
||||
addAction("em", new XHTMLTagControlAction(FBTextKind.EMPHASIS));
|
||||
addAction("i", new XHTMLTagControlAction(FBTextKind.ITALIC));
|
||||
final XHTMLTagAction codeControlAction = new XHTMLTagControlAction(FBTextKind.CODE);
|
||||
addAction("code", codeControlAction);
|
||||
addAction("tt", codeControlAction);
|
||||
addAction("kbd", codeControlAction);
|
||||
addAction("var", codeControlAction);
|
||||
addAction("samp", codeControlAction);
|
||||
addAction("cite", new XHTMLTagControlAction(FBTextKind.CITE));
|
||||
addAction("sub", new XHTMLTagControlAction(FBTextKind.SUB));
|
||||
addAction("sup", new XHTMLTagControlAction(FBTextKind.SUP));
|
||||
addAction("dd", new XHTMLTagControlAction(FBTextKind.DEFINITION_DESCRIPTION));
|
||||
addAction("dfn", new XHTMLTagControlAction(FBTextKind.DEFINITION));
|
||||
addAction("strike", new XHTMLTagControlAction(FBTextKind.STRIKETHROUGH));
|
||||
|
||||
addAction("a", new XHTMLTagHyperlinkAction());
|
||||
|
||||
addAction("img", new XHTMLTagImageAction("src"));
|
||||
addAction("object", new XHTMLTagImageAction("data"));
|
||||
|
||||
//addAction("area", new XHTMLTagAction());
|
||||
//addAction("map", new XHTMLTagAction());
|
||||
|
||||
//addAction("base", new XHTMLTagAction());
|
||||
//addAction("blockquote", new XHTMLTagAction());
|
||||
addAction("br", new XHTMLTagRestartParagraphAction());
|
||||
//addAction("center", new XHTMLTagAction());
|
||||
addAction("div", new XHTMLTagParagraphAction());
|
||||
//addAction("dt", new XHTMLTagAction());
|
||||
//addAction("head", new XHTMLTagAction());
|
||||
//addAction("hr", new XHTMLTagAction());
|
||||
//addAction("link", new XHTMLTagAction());
|
||||
//addAction("param", new XHTMLTagAction());
|
||||
//addAction("q", new XHTMLTagAction());
|
||||
//addAction("s", new XHTMLTagAction());
|
||||
|
||||
addAction("pre", new XHTMLTagPreAction());
|
||||
//addAction("big", new XHTMLTagAction());
|
||||
//addAction("small", new XHTMLTagAction());
|
||||
//addAction("u", new XHTMLTagAction());
|
||||
|
||||
//addAction("table", new XHTMLTagAction());
|
||||
addAction("td", new XHTMLTagParagraphAction());
|
||||
addAction("th", new XHTMLTagParagraphAction());
|
||||
//addAction("tr", new XHTMLTagAction());
|
||||
//addAction("caption", new XHTMLTagAction());
|
||||
//addAction("span", new XHTMLTagAction());
|
||||
if (!ourTagActions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//addAction("html", new XHTMLTagAction());
|
||||
addAction("body", new XHTMLTagBodyAction());
|
||||
//addAction("title", new XHTMLTagAction());
|
||||
//addAction("meta", new XHTMLTagAction());
|
||||
//addAction("script", new XHTMLTagAction());
|
||||
|
||||
//addAction("font", new XHTMLTagAction());
|
||||
//addAction("style", new XHTMLTagAction());
|
||||
|
||||
addAction("p", new XHTMLTagParagraphAction());
|
||||
addAction("h1", new XHTMLTagParagraphWithControlAction(FBTextKind.H1));
|
||||
addAction("h2", new XHTMLTagParagraphWithControlAction(FBTextKind.H2));
|
||||
addAction("h3", new XHTMLTagParagraphWithControlAction(FBTextKind.H3));
|
||||
addAction("h4", new XHTMLTagParagraphWithControlAction(FBTextKind.H4));
|
||||
addAction("h5", new XHTMLTagParagraphWithControlAction(FBTextKind.H5));
|
||||
addAction("h6", new XHTMLTagParagraphWithControlAction(FBTextKind.H6));
|
||||
|
||||
//addAction("ol", new XHTMLTagAction());
|
||||
//addAction("ul", new XHTMLTagAction());
|
||||
//addAction("dl", new XHTMLTagAction());
|
||||
addAction("li", new XHTMLTagItemAction());
|
||||
|
||||
addAction("strong", new XHTMLTagControlAction(FBTextKind.STRONG));
|
||||
addAction("b", new XHTMLTagControlAction(FBTextKind.BOLD));
|
||||
addAction("em", new XHTMLTagControlAction(FBTextKind.EMPHASIS));
|
||||
addAction("i", new XHTMLTagControlAction(FBTextKind.ITALIC));
|
||||
final XHTMLTagAction codeControlAction = new XHTMLTagControlAction(FBTextKind.CODE);
|
||||
addAction("code", codeControlAction);
|
||||
addAction("tt", codeControlAction);
|
||||
addAction("kbd", codeControlAction);
|
||||
addAction("var", codeControlAction);
|
||||
addAction("samp", codeControlAction);
|
||||
addAction("cite", new XHTMLTagControlAction(FBTextKind.CITE));
|
||||
addAction("sub", new XHTMLTagControlAction(FBTextKind.SUB));
|
||||
addAction("sup", new XHTMLTagControlAction(FBTextKind.SUP));
|
||||
addAction("dd", new XHTMLTagControlAction(FBTextKind.DEFINITION_DESCRIPTION));
|
||||
addAction("dfn", new XHTMLTagControlAction(FBTextKind.DEFINITION));
|
||||
addAction("strike", new XHTMLTagControlAction(FBTextKind.STRIKETHROUGH));
|
||||
|
||||
addAction("a", new XHTMLTagHyperlinkAction());
|
||||
|
||||
addAction("img", new XHTMLTagImageAction("src"));
|
||||
addAction("object", new XHTMLTagImageAction("data"));
|
||||
|
||||
//addAction("area", new XHTMLTagAction());
|
||||
//addAction("map", new XHTMLTagAction());
|
||||
|
||||
//addAction("base", new XHTMLTagAction());
|
||||
//addAction("blockquote", new XHTMLTagAction());
|
||||
addAction("br", new XHTMLTagRestartParagraphAction());
|
||||
//addAction("center", new XHTMLTagAction());
|
||||
addAction("div", new XHTMLTagParagraphAction());
|
||||
//addAction("dt", new XHTMLTagAction());
|
||||
//addAction("head", new XHTMLTagAction());
|
||||
//addAction("hr", new XHTMLTagAction());
|
||||
//addAction("link", new XHTMLTagAction());
|
||||
//addAction("param", new XHTMLTagAction());
|
||||
//addAction("q", new XHTMLTagAction());
|
||||
//addAction("s", new XHTMLTagAction());
|
||||
|
||||
addAction("pre", new XHTMLTagPreAction());
|
||||
//addAction("big", new XHTMLTagAction());
|
||||
//addAction("small", new XHTMLTagAction());
|
||||
//addAction("u", new XHTMLTagAction());
|
||||
|
||||
//addAction("table", new XHTMLTagAction());
|
||||
addAction("td", new XHTMLTagParagraphAction());
|
||||
addAction("th", new XHTMLTagParagraphAction());
|
||||
//addAction("tr", new XHTMLTagAction());
|
||||
//addAction("caption", new XHTMLTagAction());
|
||||
//addAction("span", new XHTMLTagAction());
|
||||
}
|
||||
|
||||
private final BookReader myModelReader;
|
||||
|
|
|
@ -45,6 +45,7 @@ public class ZLFile {
|
|||
private ZLFileInfo myInfo;
|
||||
|
||||
private static final HashMap ourForcedFiles = new HashMap();
|
||||
private static HashMap<String,ZipFile> ourZipFileMap = new HashMap<String,ZipFile>();
|
||||
|
||||
public boolean removeFile(String path) {
|
||||
File file = new File(path);
|
||||
|
@ -196,8 +197,6 @@ public class ZLFile {
|
|||
return path;
|
||||
}
|
||||
|
||||
//private static HashMap<String,ZipFile> ourZipFileMap = new HashMap<String,ZipFile>();
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (isDirectory()) {
|
||||
return null;
|
||||
|
@ -213,10 +212,13 @@ public class ZLFile {
|
|||
if (base != null) {
|
||||
if (0 != (baseFile.myArchiveType & ArchiveType.ZIP)) {
|
||||
final String baseFileName = myPath.substring(0, index);
|
||||
ZipFile zf = null;//ourZipFileMap.get(baseFileName);
|
||||
if (zf == null) {
|
||||
zf = new ZipFile(baseFileName);
|
||||
//ourZipFileMap.put(baseFileName, zf);
|
||||
ZipFile zf;
|
||||
synchronized (ourZipFileMap) {
|
||||
zf = ourZipFileMap.get(baseFileName);
|
||||
if (zf == null) {
|
||||
zf = new ZipFile(baseFileName);
|
||||
ourZipFileMap.put(baseFileName, zf);
|
||||
}
|
||||
}
|
||||
/*
|
||||
ZipEntry entry = zf.getEntry(myPath.substring(index+1));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue