2015-03-31 19:10:03 +02:00
/ *
* Copyright ( C ) 2010 Ken Ellinwood
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
package kellinwood.zipio ;
2018-04-19 16:18:24 +02:00
import kellinwood.logging.LoggerInterface ;
import kellinwood.logging.LoggerManager ;
2015-03-31 19:10:03 +02:00
import java.io.ByteArrayInputStream ;
import java.io.ByteArrayOutputStream ;
2018-04-19 16:18:24 +02:00
import java.io.File ;
2015-03-31 19:10:03 +02:00
import java.io.IOException ;
import java.io.InputStream ;
import java.io.OutputStream ;
import java.io.SequenceInputStream ;
import java.util.Date ;
2018-06-01 17:17:21 +02:00
import java.util.Locale ;
2015-03-31 19:10:03 +02:00
import java.util.zip.CRC32 ;
import java.util.zip.Inflater ;
import java.util.zip.InflaterInputStream ;
public class ZioEntry implements Cloneable {
private ZipInput zipInput ;
// public int signature = 0x02014b50;
private short versionMadeBy ;
private short versionRequired ;
private short generalPurposeBits ;
private short compression ;
private short modificationTime ;
private short modificationDate ;
private int crc32 ;
private int compressedSize ;
private int size ;
private String filename ;
private byte [ ] extraData ;
private short numAlignBytes = 0 ;
private String fileComment ;
private short diskNumberStart ;
private short internalAttributes ;
private int externalAttributes ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
private int localHeaderOffset ;
private long dataPosition = - 1 ;
private byte [ ] data = null ;
private ZioEntryOutputStream entryOut = null ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
private static byte [ ] alignBytes = new byte [ 4 ] ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
private static LoggerInterface log ;
2018-04-19 16:18:24 +02:00
public ZioEntry ( ZipInput input ) {
2015-03-31 19:10:03 +02:00
zipInput = input ;
}
public static LoggerInterface getLogger ( ) {
2018-04-19 16:18:24 +02:00
if ( log = = null ) log = LoggerManager . getLogger ( ZioEntry . class . getName ( ) ) ;
2015-03-31 19:10:03 +02:00
return log ;
}
2018-04-19 16:18:24 +02:00
public ZioEntry ( String name ) {
2015-03-31 19:10:03 +02:00
filename = name ;
fileComment = " " ;
compression = 8 ;
extraData = new byte [ 0 ] ;
2018-04-19 16:18:24 +02:00
setTime ( System . currentTimeMillis ( ) ) ;
2015-03-31 19:10:03 +02:00
}
2018-04-19 16:18:24 +02:00
public ZioEntry ( String name , String sourceDataFile )
throws IOException {
zipInput = new ZipInput ( sourceDataFile ) ;
2015-03-31 19:10:03 +02:00
filename = name ;
fileComment = " " ;
this . compression = 0 ;
2018-04-19 16:18:24 +02:00
this . size = ( int ) zipInput . getFileLength ( ) ;
2015-03-31 19:10:03 +02:00
this . compressedSize = this . size ;
2018-04-19 16:18:24 +02:00
if ( getLogger ( ) . isDebugEnabled ( ) )
2018-06-01 17:17:21 +02:00
getLogger ( ) . debug ( String . format ( Locale . ENGLISH , " Computing CRC for %s, size=%d " , sourceDataFile , size ) ) ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
// compute CRC
CRC32 crc = new CRC32 ( ) ;
byte [ ] buffer = new byte [ 8096 ] ;
int numRead = 0 ;
while ( numRead ! = size ) {
2018-04-19 16:18:24 +02:00
int count = zipInput . read ( buffer , 0 , Math . min ( buffer . length , ( this . size - numRead ) ) ) ;
2015-03-31 19:10:03 +02:00
if ( count > 0 ) {
2018-04-19 16:18:24 +02:00
crc . update ( buffer , 0 , count ) ;
2015-03-31 19:10:03 +02:00
numRead + = count ;
}
}
2018-04-19 16:18:24 +02:00
this . crc32 = ( int ) crc . getValue ( ) ;
2015-03-31 19:10:03 +02:00
zipInput . seek ( 0 ) ;
this . dataPosition = 0 ;
extraData = new byte [ 0 ] ;
2018-04-19 16:18:24 +02:00
setTime ( new File ( sourceDataFile ) . lastModified ( ) ) ;
2015-03-31 19:10:03 +02:00
}
2018-04-19 16:18:24 +02:00
public ZioEntry ( String name , String sourceDataFile , short compression , int crc32 , int compressedSize , int size )
throws IOException {
zipInput = new ZipInput ( sourceDataFile ) ;
2015-03-31 19:10:03 +02:00
filename = name ;
fileComment = " " ;
this . compression = compression ;
this . crc32 = crc32 ;
this . compressedSize = compressedSize ;
this . size = size ;
this . dataPosition = 0 ;
extraData = new byte [ 0 ] ;
2018-04-19 16:18:24 +02:00
setTime ( new File ( sourceDataFile ) . lastModified ( ) ) ;
2015-03-31 19:10:03 +02:00
}
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
// Return a copy with a new name
2018-04-19 16:18:24 +02:00
public ZioEntry getClonedEntry ( String newName ) {
2015-03-31 19:10:03 +02:00
ZioEntry clone ;
try {
2018-04-19 16:18:24 +02:00
clone = ( ZioEntry ) this . clone ( ) ;
} catch ( CloneNotSupportedException e ) {
2015-03-31 19:10:03 +02:00
throw new IllegalStateException ( " clone() failed! " ) ;
}
clone . setName ( newName ) ;
return clone ;
}
2018-04-19 16:18:24 +02:00
public void readLocalHeader ( ) throws IOException {
2015-03-31 19:10:03 +02:00
ZipInput input = zipInput ;
int tmp ;
boolean debug = getLogger ( ) . isDebugEnabled ( ) ;
2018-04-19 16:18:24 +02:00
input . seek ( localHeaderOffset ) ;
2015-03-31 19:10:03 +02:00
2018-04-19 16:18:24 +02:00
if ( debug ) getLogger ( ) . debug ( String . format ( " FILE POSITION: 0x%08x " , input . getFilePointer ( ) ) ) ;
2015-03-31 19:10:03 +02:00
// 0 4 Local file header signature = 0x04034b50
int signature = input . readInt ( ) ;
if ( signature ! = 0x04034b50 ) {
2018-04-19 16:18:24 +02:00
throw new IllegalStateException ( String . format ( " Local header not found at pos=0x%08x, file=%s " , input . getFilePointer ( ) , filename ) ) ;
2015-03-31 19:10:03 +02:00
}
// This method is usually called just before the data read, so
// its only purpose currently is to position the file pointer
// for the data read. The entry's attributes might also have
// been changed since the central dir entry was read (e.g.,
// filename), so throw away the values here.
int tmpInt ;
short tmpShort ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
// 4 2 Version needed to extract (minimum)
2018-04-19 16:18:24 +02:00
/* versionRequired */
tmpShort = input . readShort ( ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( String . format ( " Version required: 0x%04x " , tmpShort /*versionRequired*/ ) ) ;
// 6 2 General purpose bit flag
2018-04-19 16:18:24 +02:00
/* generalPurposeBits */
tmpShort = input . readShort ( ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( String . format ( " General purpose bits: 0x%04x " , tmpShort /* generalPurposeBits */ ) ) ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
// 8 2 Compression method
2018-04-19 16:18:24 +02:00
/* compression */
tmpShort = input . readShort ( ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( String . format ( " Compression: 0x%04x " , tmpShort /* compression */ ) ) ;
// 10 2 File last modification time
2018-04-19 16:18:24 +02:00
/* modificationTime */
tmpShort = input . readShort ( ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( String . format ( " Modification time: 0x%04x " , tmpShort /* modificationTime */ ) ) ;
// 12 2 File last modification date
2018-04-19 16:18:24 +02:00
/* modificationDate */
tmpShort = input . readShort ( ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( String . format ( " Modification date: 0x%04x " , tmpShort /* modificationDate */ ) ) ;
// 14 4 CRC-32
2018-04-19 16:18:24 +02:00
/* crc32 */
tmpInt = input . readInt ( ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( String . format ( " CRC-32: 0x%04x " , tmpInt /*crc32*/ ) ) ;
// 18 4 Compressed size
2018-04-19 16:18:24 +02:00
/* compressedSize*/
tmpInt = input . readInt ( ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( String . format ( " Compressed size: 0x%04x " , tmpInt /*compressedSize*/ ) ) ;
// 22 4 Uncompressed size
2018-04-19 16:18:24 +02:00
/* size */
tmpInt = input . readInt ( ) ;
if ( debug ) log . debug ( String . format ( " Size: 0x%04x " , tmpInt /*size*/ ) ) ;
2015-03-31 19:10:03 +02:00
// 26 2 File name length (n)
short fileNameLen = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " File name length: 0x%04x " , fileNameLen ) ) ;
// 28 2 Extra field length (m)
short extraLen = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Extra length: 0x%04x " , extraLen ) ) ;
// 30 n File name
String filename = input . readString ( fileNameLen ) ;
if ( debug ) log . debug ( " Filename: " + filename ) ;
// Extra data
2018-04-19 16:18:24 +02:00
byte [ ] extra = input . readBytes ( extraLen ) ;
2015-03-31 19:10:03 +02:00
// Record the file position of this entry's data.
dataPosition = input . getFilePointer ( ) ;
2018-04-19 16:18:24 +02:00
if ( debug ) log . debug ( String . format ( " Data position: 0x%08x " , dataPosition ) ) ;
2015-03-31 19:10:03 +02:00
}
2018-04-19 16:18:24 +02:00
public void writeLocalEntry ( ZipOutput output ) throws IOException {
2015-03-31 19:10:03 +02:00
if ( data = = null & & dataPosition < 0 & & zipInput ! = null ) {
readLocalHeader ( ) ;
}
2018-04-19 16:18:24 +02:00
localHeaderOffset = ( int ) output . getFilePointer ( ) ;
2015-03-31 19:10:03 +02:00
boolean debug = getLogger ( ) . isDebugEnabled ( ) ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
if ( debug ) {
2018-04-19 16:18:24 +02:00
getLogger ( ) . debug ( String . format ( " Writing local header at 0x%08x - %s " , localHeaderOffset , filename ) ) ;
2015-03-31 19:10:03 +02:00
}
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
if ( entryOut ! = null ) {
entryOut . close ( ) ;
size = entryOut . getSize ( ) ;
2018-04-19 16:18:24 +02:00
data = ( ( ByteArrayOutputStream ) entryOut . getWrappedStream ( ) ) . toByteArray ( ) ;
2015-03-31 19:10:03 +02:00
compressedSize = data . length ;
crc32 = entryOut . getCRC ( ) ;
}
2018-04-19 16:18:24 +02:00
output . writeInt ( 0x04034b50 ) ;
output . writeShort ( versionRequired ) ;
output . writeShort ( generalPurposeBits ) ;
output . writeShort ( compression ) ;
output . writeShort ( modificationTime ) ;
output . writeShort ( modificationDate ) ;
output . writeInt ( crc32 ) ;
output . writeInt ( compressedSize ) ;
output . writeInt ( size ) ;
output . writeShort ( ( short ) filename . length ( ) ) ;
2015-03-31 19:10:03 +02:00
numAlignBytes = 0 ;
// Zipalign if the file is uncompressed, i.e., "Stored", and file size is not zero.
if ( compression = = 0 ) {
long dataPos = output . getFilePointer ( ) + // current position
2018-04-19 16:18:24 +02:00
2 + // plus size of extra data length
filename . length ( ) + // plus filename
extraData . length ; // plus extra data
2015-03-31 19:10:03 +02:00
2018-04-19 16:18:24 +02:00
short dataPosMod4 = ( short ) ( dataPos % 4 ) ;
2015-03-31 19:10:03 +02:00
if ( dataPosMod4 > 0 ) {
2018-04-19 16:18:24 +02:00
numAlignBytes = ( short ) ( 4 - dataPosMod4 ) ;
2015-03-31 19:10:03 +02:00
}
}
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
// 28 2 Extra field length (m)
2018-04-19 16:18:24 +02:00
output . writeShort ( ( short ) ( extraData . length + numAlignBytes ) ) ;
2015-03-31 19:10:03 +02:00
// 30 n File name
2018-04-19 16:18:24 +02:00
output . writeString ( filename ) ;
2015-03-31 19:10:03 +02:00
// Extra data
2018-04-19 16:18:24 +02:00
output . writeBytes ( extraData ) ;
2015-03-31 19:10:03 +02:00
// Zipalign bytes
if ( numAlignBytes > 0 ) {
2018-04-19 16:18:24 +02:00
output . writeBytes ( alignBytes , 0 , numAlignBytes ) ;
2015-03-31 19:10:03 +02:00
}
2018-06-01 17:17:21 +02:00
if ( debug ) getLogger ( ) . debug ( String . format ( Locale . ENGLISH , " Data position 0x%08x " , output . getFilePointer ( ) ) ) ;
2015-03-31 19:10:03 +02:00
if ( data ! = null ) {
2018-04-19 16:18:24 +02:00
output . writeBytes ( data ) ;
2018-06-01 17:17:21 +02:00
if ( debug ) getLogger ( ) . debug ( String . format ( Locale . ENGLISH , " Wrote %d bytes " , data . length ) ) ;
2018-04-19 16:18:24 +02:00
} else {
2015-03-31 19:10:03 +02:00
if ( debug ) getLogger ( ) . debug ( String . format ( " Seeking to position 0x%08x " , dataPosition ) ) ;
2018-04-19 16:18:24 +02:00
zipInput . seek ( dataPosition ) ;
int bufferSize = Math . min ( compressedSize , 8096 ) ;
2015-03-31 19:10:03 +02:00
byte [ ] buffer = new byte [ bufferSize ] ;
long totalCount = 0 ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
while ( totalCount ! = compressedSize ) {
2018-04-19 16:18:24 +02:00
int numRead = zipInput . in . read ( buffer , 0 , ( int ) Math . min ( compressedSize - totalCount , bufferSize ) ) ;
2015-03-31 19:10:03 +02:00
if ( numRead > 0 ) {
output . writeBytes ( buffer , 0 , numRead ) ;
2018-06-01 17:17:21 +02:00
if ( debug ) getLogger ( ) . debug ( String . format ( Locale . ENGLISH , " Wrote %d bytes " , numRead ) ) ;
2015-03-31 19:10:03 +02:00
totalCount + = numRead ;
2018-04-19 16:18:24 +02:00
} else
2018-06-01 17:17:21 +02:00
throw new IllegalStateException ( String . format ( Locale . ENGLISH , " EOF reached while copying %s with %d bytes left to go " , filename , compressedSize - totalCount ) ) ;
2015-03-31 19:10:03 +02:00
}
}
2018-04-19 16:18:24 +02:00
}
public static ZioEntry read ( ZipInput input ) throws IOException {
2015-03-31 19:10:03 +02:00
// 0 4 Central directory header signature = 0x02014b50
int signature = input . readInt ( ) ;
if ( signature ! = 0x02014b50 ) {
// back up to the signature
2018-04-19 16:18:24 +02:00
input . seek ( input . getFilePointer ( ) - 4 ) ;
2015-03-31 19:10:03 +02:00
return null ;
}
2018-04-19 16:18:24 +02:00
ZioEntry entry = new ZioEntry ( input ) ;
2015-03-31 19:10:03 +02:00
2018-04-19 16:18:24 +02:00
entry . doRead ( input ) ;
2015-03-31 19:10:03 +02:00
return entry ;
}
2018-04-19 16:18:24 +02:00
private void doRead ( ZipInput input ) throws IOException {
2015-03-31 19:10:03 +02:00
boolean debug = getLogger ( ) . isDebugEnabled ( ) ;
// 4 2 Version needed to extract (minimum)
versionMadeBy = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Version made by: 0x%04x " , versionMadeBy ) ) ;
// 4 2 Version required
versionRequired = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Version required: 0x%04x " , versionRequired ) ) ;
// 6 2 General purpose bit flag
generalPurposeBits = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " General purpose bits: 0x%04x " , generalPurposeBits ) ) ;
// Bits 1, 2, 3, and 11 are allowed to be set (first bit is bit zero). Any others are a problem.
if ( ( generalPurposeBits & 0xF7F1 ) ! = 0x0000 ) {
2018-04-19 16:18:24 +02:00
throw new IllegalStateException ( " Can't handle general purpose bits == " + String . format ( " 0x%04x " , generalPurposeBits ) ) ;
2015-03-31 19:10:03 +02:00
}
// 8 2 Compression method
compression = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Compression: 0x%04x " , compression ) ) ;
// 10 2 File last modification time
modificationTime = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Modification time: 0x%04x " , modificationTime ) ) ;
// 12 2 File last modification date
modificationDate = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Modification date: 0x%04x " , modificationDate ) ) ;
// 14 4 CRC-32
crc32 = input . readInt ( ) ;
if ( debug ) log . debug ( String . format ( " CRC-32: 0x%04x " , crc32 ) ) ;
// 18 4 Compressed size
compressedSize = input . readInt ( ) ;
if ( debug ) log . debug ( String . format ( " Compressed size: 0x%04x " , compressedSize ) ) ;
// 22 4 Uncompressed size
size = input . readInt ( ) ;
if ( debug ) log . debug ( String . format ( " Size: 0x%04x " , size ) ) ;
// 26 2 File name length (n)
short fileNameLen = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " File name length: 0x%04x " , fileNameLen ) ) ;
// 28 2 Extra field length (m)
short extraLen = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Extra length: 0x%04x " , extraLen ) ) ;
short fileCommentLen = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " File comment length: 0x%04x " , fileCommentLen ) ) ;
diskNumberStart = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Disk number start: 0x%04x " , diskNumberStart ) ) ;
internalAttributes = input . readShort ( ) ;
if ( debug ) log . debug ( String . format ( " Internal attributes: 0x%04x " , internalAttributes ) ) ;
externalAttributes = input . readInt ( ) ;
if ( debug ) log . debug ( String . format ( " External attributes: 0x%08x " , externalAttributes ) ) ;
localHeaderOffset = input . readInt ( ) ;
if ( debug ) log . debug ( String . format ( " Local header offset: 0x%08x " , localHeaderOffset ) ) ;
// 30 n File name
filename = input . readString ( fileNameLen ) ;
if ( debug ) log . debug ( " Filename: " + filename ) ;
2018-04-19 16:18:24 +02:00
extraData = input . readBytes ( extraLen ) ;
2015-03-31 19:10:03 +02:00
2018-04-19 16:18:24 +02:00
fileComment = input . readString ( fileCommentLen ) ;
2015-03-31 19:10:03 +02:00
if ( debug ) log . debug ( " File comment: " + fileComment ) ;
2018-04-19 16:18:24 +02:00
generalPurposeBits = ( short ) ( generalPurposeBits & 0x0800 ) ; // Don't write a data descriptor, preserve UTF-8 encoded filename bit
2015-03-31 19:10:03 +02:00
// Don't write zero-length entries with compression.
if ( size = = 0 ) {
compressedSize = 0 ;
compression = 0 ;
crc32 = 0 ;
}
}
2018-04-19 16:18:24 +02:00
/ * *
* Returns the entry ' s data .
* /
public byte [ ] getData ( ) throws IOException {
2015-03-31 19:10:03 +02:00
if ( data ! = null ) return data ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
byte [ ] tmpdata = new byte [ size ] ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
InputStream din = getInputStream ( ) ;
int count = 0 ;
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
while ( count ! = size ) {
2018-04-19 16:18:24 +02:00
int numRead = din . read ( tmpdata , count , size - count ) ;
if ( numRead < 0 )
2018-06-01 17:17:21 +02:00
throw new IllegalStateException ( String . format ( Locale . ENGLISH , " Read failed, expecting %d bytes, got %d instead " , size , count ) ) ;
2015-03-31 19:10:03 +02:00
count + = numRead ;
}
return tmpdata ;
}
// Returns an input stream for reading the entry's data.
public InputStream getInputStream ( ) throws IOException {
return getInputStream ( null ) ;
}
// Returns an input stream for reading the entry's data.
public InputStream getInputStream ( OutputStream monitorStream ) throws IOException {
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
if ( entryOut ! = null ) {
entryOut . close ( ) ;
size = entryOut . getSize ( ) ;
2018-04-19 16:18:24 +02:00
data = ( ( ByteArrayOutputStream ) entryOut . getWrappedStream ( ) ) . toByteArray ( ) ;
2015-03-31 19:10:03 +02:00
compressedSize = data . length ;
crc32 = entryOut . getCRC ( ) ;
entryOut = null ;
2018-04-19 16:18:24 +02:00
InputStream rawis = new ByteArrayInputStream ( data ) ;
2015-03-31 19:10:03 +02:00
if ( compression = = 0 ) return rawis ;
else {
// Hacky, inflate using a sequence of input streams that returns 1 byte more than the actual length of the data.
// This extra dummy byte is required by InflaterInputStream when the data doesn't have the header and crc fields (as it is in zip files).
2018-04-19 16:18:24 +02:00
return new InflaterInputStream ( new SequenceInputStream ( rawis , new ByteArrayInputStream ( new byte [ 1 ] ) ) , new Inflater ( true ) ) ;
2015-03-31 19:10:03 +02:00
}
}
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
ZioEntryInputStream dataStream ;
dataStream = new ZioEntryInputStream ( this ) ;
2018-04-19 16:18:24 +02:00
if ( monitorStream ! = null ) dataStream . setMonitorStream ( monitorStream ) ;
if ( compression ! = 0 ) {
2015-03-31 19:10:03 +02:00
// Note: When using nowrap=true with Inflater it is also necessary to provide
// an extra "dummy" byte as input. This is required by the ZLIB native library
// in order to support certain optimizations.
dataStream . setReturnDummyByte ( true ) ;
2018-04-19 16:18:24 +02:00
return new InflaterInputStream ( dataStream , new Inflater ( true ) ) ;
} else return dataStream ;
2015-03-31 19:10:03 +02:00
}
// Returns an output stream for writing an entry's data.
2018-04-19 16:18:24 +02:00
public OutputStream getOutputStream ( ) {
entryOut = new ZioEntryOutputStream ( compression , new ByteArrayOutputStream ( ) ) ;
2015-03-31 19:10:03 +02:00
return entryOut ;
}
2018-04-19 16:18:24 +02:00
public void write ( ZipOutput output ) throws IOException {
2015-03-31 19:10:03 +02:00
boolean debug = getLogger ( ) . isDebugEnabled ( ) ;
2018-04-19 16:18:24 +02:00
output . writeInt ( 0x02014b50 ) ;
output . writeShort ( versionMadeBy ) ;
output . writeShort ( versionRequired ) ;
output . writeShort ( generalPurposeBits ) ;
output . writeShort ( compression ) ;
output . writeShort ( modificationTime ) ;
output . writeShort ( modificationDate ) ;
output . writeInt ( crc32 ) ;
output . writeInt ( compressedSize ) ;
output . writeInt ( size ) ;
output . writeShort ( ( short ) filename . length ( ) ) ;
output . writeShort ( ( short ) ( extraData . length + numAlignBytes ) ) ;
output . writeShort ( ( short ) fileComment . length ( ) ) ;
output . writeShort ( diskNumberStart ) ;
output . writeShort ( internalAttributes ) ;
output . writeInt ( externalAttributes ) ;
output . writeInt ( localHeaderOffset ) ;
output . writeString ( filename ) ;
output . writeBytes ( extraData ) ;
if ( numAlignBytes > 0 ) output . writeBytes ( alignBytes , 0 , numAlignBytes ) ;
output . writeString ( fileComment ) ;
2015-03-31 19:10:03 +02:00
}
/ *
* Returns timetamp in Java format
* /
public long getTime ( ) {
2018-04-19 16:18:24 +02:00
int year = ( int ) ( ( ( modificationDate > > 9 ) & 0x007f ) + 80 ) ;
int month = ( int ) ( ( ( modificationDate > > 5 ) & 0x000f ) - 1 ) ;
int day = ( int ) ( modificationDate & 0x001f ) ;
int hour = ( int ) ( ( modificationTime > > 11 ) & 0x001f ) ;
int minute = ( int ) ( ( modificationTime > > 5 ) & 0x003f ) ;
int seconds = ( int ) ( ( modificationTime < < 1 ) & 0x003e ) ;
Date d = new Date ( year , month , day , hour , minute , seconds ) ;
2015-03-31 19:10:03 +02:00
return d . getTime ( ) ;
}
/ *
* Set the file timestamp ( using a Java time value ) .
* /
public void setTime ( long time ) {
Date d = new Date ( time ) ;
long dtime ;
int year = d . getYear ( ) + 1900 ;
if ( year < 1980 ) {
dtime = ( 1 < < 21 ) | ( 1 < < 16 ) ;
2018-04-19 16:18:24 +02:00
} else {
2015-03-31 19:10:03 +02:00
dtime = ( year - 1980 ) < < 25 | ( d . getMonth ( ) + 1 ) < < 21 |
2018-04-19 16:18:24 +02:00
d . getDate ( ) < < 16 | d . getHours ( ) < < 11 | d . getMinutes ( ) < < 5 |
d . getSeconds ( ) > > 1 ;
2015-03-31 19:10:03 +02:00
}
2018-04-19 16:18:24 +02:00
modificationDate = ( short ) ( dtime > > 16 ) ;
modificationTime = ( short ) ( dtime & 0xFFFF ) ;
2015-03-31 19:10:03 +02:00
}
public boolean isDirectory ( ) {
return filename . endsWith ( " / " ) ;
}
2018-04-19 16:18:24 +02:00
2015-03-31 19:10:03 +02:00
public String getName ( ) {
return filename ;
}
2018-04-19 16:18:24 +02:00
public void setName ( String filename ) {
2015-03-31 19:10:03 +02:00
this . filename = filename ;
}
2018-04-19 16:18:24 +02:00
/ * *
* Use 0 ( STORED ) , or 8 ( DEFLATE ) .
* /
public void setCompression ( int compression ) {
this . compression = ( short ) compression ;
2015-03-31 19:10:03 +02:00
}
public short getVersionMadeBy ( ) {
return versionMadeBy ;
}
public short getVersionRequired ( ) {
return versionRequired ;
}
public short getGeneralPurposeBits ( ) {
return generalPurposeBits ;
}
public short getCompression ( ) {
return compression ;
}
public int getCrc32 ( ) {
return crc32 ;
}
public int getCompressedSize ( ) {
return compressedSize ;
}
public int getSize ( ) {
return size ;
}
public byte [ ] getExtraData ( ) {
return extraData ;
}
public String getFileComment ( ) {
return fileComment ;
}
public short getDiskNumberStart ( ) {
return diskNumberStart ;
}
public short getInternalAttributes ( ) {
return internalAttributes ;
}
public int getExternalAttributes ( ) {
return externalAttributes ;
}
public int getLocalHeaderOffset ( ) {
return localHeaderOffset ;
}
public long getDataPosition ( ) {
return dataPosition ;
}
public ZioEntryOutputStream getEntryOut ( ) {
return entryOut ;
}
public ZipInput getZipInput ( ) {
return zipInput ;
}
}