add ZipFileSystem
This commit is contained in:
parent
24c0af8162
commit
b05b148361
|
@ -31,7 +31,7 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation project(path: ':FCLauncher')
|
||||
implementation 'com.github.marschall:zipfilesystem-standalone:1.0.1'
|
||||
implementation project(path: ':ZipFileSystem')
|
||||
implementation 'org.nanohttpd:nanohttpd:2.3.1'
|
||||
implementation 'com.github.steveice10:opennbt:1.5'
|
||||
implementation 'org.tukaani:xz:1.9'
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
plugins {
|
||||
id 'com.android.library'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.github.marschall.ZipFileSystem'
|
||||
compileSdk 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk 26
|
||||
targetSdk 34
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
fordebug {
|
||||
initWith debug
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Utility class for zipfile name and comment decoding and encoding
|
||||
*
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
|
||||
final class ZipCoder {
|
||||
|
||||
String toString(byte[] ba, int length) {
|
||||
CharsetDecoder cd = decoder().reset();
|
||||
int len = (int)(length * cd.maxCharsPerByte());
|
||||
char[] ca = new char[len];
|
||||
if (len == 0)
|
||||
return new String(ca);
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
return new String(ca, 0, cb.position());
|
||||
}
|
||||
|
||||
String toString(byte[] ba) {
|
||||
return toString(ba, ba.length);
|
||||
}
|
||||
|
||||
byte[] getBytes(String s) {
|
||||
CharsetEncoder ce = encoder().reset();
|
||||
char[] ca = s.toCharArray();
|
||||
int len = (int)(ca.length * ce.maxBytesPerChar());
|
||||
byte[] ba = new byte[len];
|
||||
if (len == 0)
|
||||
return ba;
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
cr = ce.flush(bb);
|
||||
if (!cr.isUnderflow())
|
||||
throw new IllegalArgumentException(cr.toString());
|
||||
if (bb.position() == ba.length) // defensive copy?
|
||||
return ba;
|
||||
else
|
||||
return Arrays.copyOf(ba, bb.position());
|
||||
}
|
||||
|
||||
// assume invoked only if "this" is not utf8
|
||||
byte[] getBytesUTF8(String s) {
|
||||
if (isutf8)
|
||||
return getBytes(s);
|
||||
if (utf8 == null)
|
||||
utf8 = new ZipCoder(Charset.forName("UTF-8"));
|
||||
return utf8.getBytes(s);
|
||||
}
|
||||
|
||||
String toStringUTF8(byte[] ba, int len) {
|
||||
if (isutf8)
|
||||
return toString(ba, len);
|
||||
if (utf8 == null)
|
||||
utf8 = new ZipCoder(Charset.forName("UTF-8"));
|
||||
return utf8.toString(ba, len);
|
||||
}
|
||||
|
||||
boolean isUTF8() {
|
||||
return isutf8;
|
||||
}
|
||||
|
||||
private Charset cs;
|
||||
private boolean isutf8;
|
||||
private ZipCoder utf8;
|
||||
|
||||
private ZipCoder(Charset cs) {
|
||||
this.cs = cs;
|
||||
this.isutf8 = cs.name().equals("UTF-8");
|
||||
}
|
||||
|
||||
static ZipCoder get(Charset charset) {
|
||||
return new ZipCoder(charset);
|
||||
}
|
||||
|
||||
static ZipCoder get(String csn) {
|
||||
try {
|
||||
return new ZipCoder(Charset.forName(csn));
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
return new ZipCoder(Charset.defaultCharset());
|
||||
}
|
||||
|
||||
private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>();
|
||||
private final ThreadLocal<CharsetEncoder> encTL = new ThreadLocal<>();
|
||||
|
||||
private CharsetDecoder decoder() {
|
||||
CharsetDecoder dec = decTL.get();
|
||||
if (dec == null) {
|
||||
dec = cs.newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
decTL.set(dec);
|
||||
}
|
||||
return dec;
|
||||
}
|
||||
|
||||
private CharsetEncoder encoder() {
|
||||
CharsetEncoder enc = encTL.get();
|
||||
if (enc == null) {
|
||||
enc = cs.newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
encTL.set(enc);
|
||||
}
|
||||
return enc;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
|
||||
class ZipConstants {
|
||||
/*
|
||||
* Compression methods
|
||||
*/
|
||||
static final int METHOD_STORED = 0;
|
||||
static final int METHOD_DEFLATED = 8;
|
||||
static final int METHOD_DEFLATED64 = 9;
|
||||
static final int METHOD_BZIP2 = 12;
|
||||
static final int METHOD_LZMA = 14;
|
||||
static final int METHOD_LZ77 = 19;
|
||||
static final int METHOD_AES = 99;
|
||||
|
||||
/*
|
||||
* General purpose big flag
|
||||
*/
|
||||
static final int FLAG_ENCRYPTED = 0x01;
|
||||
static final int FLAG_DATADESCR = 0x08; // crc, size and csize in dd
|
||||
static final int FLAG_EFS = 0x800; // If this bit is set the filename and
|
||||
// comment fields for this file must be
|
||||
// encoded using UTF-8.
|
||||
/*
|
||||
* Header signatures
|
||||
*/
|
||||
static long LOCSIG = 0x04034b50L; // "PK\003\004"
|
||||
static long EXTSIG = 0x08074b50L; // "PK\007\008"
|
||||
static long CENSIG = 0x02014b50L; // "PK\001\002"
|
||||
static long ENDSIG = 0x06054b50L; // "PK\005\006"
|
||||
|
||||
/*
|
||||
* Header sizes in bytes (including signatures)
|
||||
*/
|
||||
static final int LOCHDR = 30; // LOC header size
|
||||
static final int EXTHDR = 16; // EXT header size
|
||||
static final int CENHDR = 46; // CEN header size
|
||||
static final int ENDHDR = 22; // END header size
|
||||
|
||||
/*
|
||||
* Local file (LOC) header field offsets
|
||||
*/
|
||||
static final int LOCVER = 4; // version needed to extract
|
||||
static final int LOCFLG = 6; // general purpose bit flag
|
||||
static final int LOCHOW = 8; // compression method
|
||||
static final int LOCTIM = 10; // modification time
|
||||
static final int LOCCRC = 14; // uncompressed file crc-32 value
|
||||
static final int LOCSIZ = 18; // compressed size
|
||||
static final int LOCLEN = 22; // uncompressed size
|
||||
static final int LOCNAM = 26; // filename length
|
||||
static final int LOCEXT = 28; // extra field length
|
||||
|
||||
/*
|
||||
* Extra local (EXT) header field offsets
|
||||
*/
|
||||
static final int EXTCRC = 4; // uncompressed file crc-32 value
|
||||
static final int EXTSIZ = 8; // compressed size
|
||||
static final int EXTLEN = 12; // uncompressed size
|
||||
|
||||
/*
|
||||
* Central directory (CEN) header field offsets
|
||||
*/
|
||||
static final int CENVEM = 4; // version made by
|
||||
static final int CENVER = 6; // version needed to extract
|
||||
static final int CENFLG = 8; // encrypt, decrypt flags
|
||||
static final int CENHOW = 10; // compression method
|
||||
static final int CENTIM = 12; // modification time
|
||||
static final int CENCRC = 16; // uncompressed file crc-32 value
|
||||
static final int CENSIZ = 20; // compressed size
|
||||
static final int CENLEN = 24; // uncompressed size
|
||||
static final int CENNAM = 28; // filename length
|
||||
static final int CENEXT = 30; // extra field length
|
||||
static final int CENCOM = 32; // comment length
|
||||
static final int CENDSK = 34; // disk number start
|
||||
static final int CENATT = 36; // internal file attributes
|
||||
static final int CENATX = 38; // external file attributes
|
||||
static final int CENOFF = 42; // LOC header offset
|
||||
|
||||
/*
|
||||
* End of central directory (END) header field offsets
|
||||
*/
|
||||
static final int ENDSUB = 8; // number of entries on this disk
|
||||
static final int ENDTOT = 10; // total number of entries
|
||||
static final int ENDSIZ = 12; // central directory size in bytes
|
||||
static final int ENDOFF = 16; // offset of first CEN header
|
||||
static final int ENDCOM = 20; // zip file comment length
|
||||
|
||||
/*
|
||||
* ZIP64 constants
|
||||
*/
|
||||
static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006"
|
||||
static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007"
|
||||
static final int ZIP64_ENDHDR = 56; // ZIP64 end header size
|
||||
static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size
|
||||
static final int ZIP64_EXTHDR = 24; // EXT header size
|
||||
static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID
|
||||
|
||||
static final int ZIP64_MINVAL32 = 0xFFFF;
|
||||
static final long ZIP64_MINVAL = 0xFFFFFFFFL;
|
||||
|
||||
/*
|
||||
* Zip64 End of central directory (END) header field offsets
|
||||
*/
|
||||
static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir
|
||||
static final int ZIP64_ENDVEM = 12; // version made by
|
||||
static final int ZIP64_ENDVER = 14; // version needed to extract
|
||||
static final int ZIP64_ENDNMD = 16; // number of this disk
|
||||
static final int ZIP64_ENDDSK = 20; // disk number of start
|
||||
static final int ZIP64_ENDTOD = 24; // total number of entries on this disk
|
||||
static final int ZIP64_ENDTOT = 32; // total number of entries
|
||||
static final int ZIP64_ENDSIZ = 40; // central directory size in bytes
|
||||
static final int ZIP64_ENDOFF = 48; // offset of first CEN header
|
||||
static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector
|
||||
|
||||
/*
|
||||
* Zip64 End of central directory locator field offsets
|
||||
*/
|
||||
static final int ZIP64_LOCDSK = 4; // disk number start
|
||||
static final int ZIP64_LOCOFF = 8; // offset of zip64 end
|
||||
static final int ZIP64_LOCTOT = 16; // total number of disks
|
||||
|
||||
/*
|
||||
* Zip64 Extra local (EXT) header field offsets
|
||||
*/
|
||||
static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value
|
||||
static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte
|
||||
static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte
|
||||
|
||||
/*
|
||||
* Extra field header ID
|
||||
*/
|
||||
static final int EXTID_ZIP64 = 0x0001; // ZIP64
|
||||
static final int EXTID_NTFS = 0x000a; // NTFS
|
||||
static final int EXTID_UNIX = 0x000d; // UNIX
|
||||
static final int EXTID_EFS = 0x0017; // Strong Encryption
|
||||
static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp
|
||||
|
||||
/*
|
||||
* fields access methods
|
||||
*/
|
||||
///////////////////////////////////////////////////////
|
||||
static final int CH(byte[] b, int n) {
|
||||
return toUnsignedInt(b[n]);
|
||||
}
|
||||
|
||||
static final int SH(byte[] b, int n) {
|
||||
return toUnsignedInt(b[n]) | (toUnsignedInt(b[n + 1]) << 8);
|
||||
}
|
||||
|
||||
private static int toUnsignedInt(byte x) {
|
||||
return ((int) x) & 0xff;
|
||||
}
|
||||
|
||||
static final long LG(byte[] b, int n) {
|
||||
return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
|
||||
}
|
||||
|
||||
static final long LL(byte[] b, int n) {
|
||||
return (LG(b, n)) | (LG(b, n + 4) << 32);
|
||||
}
|
||||
|
||||
static final long GETSIG(byte[] b) {
|
||||
return LG(b, 0);
|
||||
}
|
||||
|
||||
// local file (LOC) header fields
|
||||
static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
|
||||
static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
|
||||
static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
|
||||
static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
|
||||
static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
|
||||
static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
|
||||
static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
|
||||
static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
|
||||
static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
|
||||
static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
|
||||
|
||||
// extra local (EXT) header fields
|
||||
static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
|
||||
static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
|
||||
static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
|
||||
|
||||
// end of central directory header (END) fields
|
||||
static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
|
||||
static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
|
||||
static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
|
||||
static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
|
||||
static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
|
||||
static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
|
||||
|
||||
// zip64 end of central directory recoder fields
|
||||
static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
|
||||
static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
|
||||
static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
|
||||
static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
|
||||
static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
|
||||
|
||||
// central directory header (CEN) fields
|
||||
static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
|
||||
static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
|
||||
static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
|
||||
static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
|
||||
static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
|
||||
static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
|
||||
static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
|
||||
static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
|
||||
static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
|
||||
static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
|
||||
static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
|
||||
static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
|
||||
static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
|
||||
static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
|
||||
static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
|
||||
static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
|
||||
|
||||
/* The END header is followed by a variable length comment of size < 64k. */
|
||||
static final long END_MAXLEN = 0xFFFF + ENDHDR;
|
||||
static final int READBLOCKSZ = 128;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.ClosedDirectoryStreamException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
|
||||
public class ZipDirectoryStream implements DirectoryStream<Path> {
|
||||
|
||||
private final ZipFileSystem zipfs;
|
||||
private final byte[] path;
|
||||
private final DirectoryStream.Filter<? super Path> filter;
|
||||
private volatile boolean isClosed;
|
||||
private volatile Iterator<Path> itr;
|
||||
|
||||
ZipDirectoryStream(ZipPath zipPath,
|
||||
DirectoryStream.Filter<? super java.nio.file.Path> filter)
|
||||
throws IOException
|
||||
{
|
||||
this.zipfs = zipPath.getFileSystem();
|
||||
this.path = zipPath.getResolvedPath();
|
||||
this.filter = filter;
|
||||
// sanity check
|
||||
if (!zipfs.isDirectory(path))
|
||||
throw new NotDirectoryException(zipPath.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Iterator<Path> iterator() {
|
||||
if (isClosed)
|
||||
throw new ClosedDirectoryStreamException();
|
||||
if (itr != null)
|
||||
throw new IllegalStateException("Iterator has already been returned");
|
||||
|
||||
try {
|
||||
itr = zipfs.iteratorOf(path, filter);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return new Iterator<Path>() {
|
||||
private Path next;
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (isClosed)
|
||||
return false;
|
||||
return itr.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Path next() {
|
||||
if (isClosed)
|
||||
throw new NoSuchElementException();
|
||||
return itr.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
isClosed = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
|
||||
public class ZipFileAttributeView implements BasicFileAttributeView
|
||||
{
|
||||
private static enum AttrID {
|
||||
size,
|
||||
creationTime,
|
||||
lastAccessTime,
|
||||
lastModifiedTime,
|
||||
isDirectory,
|
||||
isRegularFile,
|
||||
isSymbolicLink,
|
||||
isOther,
|
||||
fileKey,
|
||||
compressedSize,
|
||||
crc,
|
||||
method
|
||||
};
|
||||
|
||||
private final ZipPath path;
|
||||
private final boolean isZipView;
|
||||
|
||||
private ZipFileAttributeView(ZipPath path, boolean isZipView) {
|
||||
this.path = path;
|
||||
this.isZipView = isZipView;
|
||||
}
|
||||
|
||||
static <V extends FileAttributeView> V get(ZipPath path, Class<V> type) {
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
if (type == BasicFileAttributeView.class)
|
||||
return (V)new ZipFileAttributeView(path, false);
|
||||
if (type == ZipFileAttributeView.class)
|
||||
return (V)new ZipFileAttributeView(path, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
static ZipFileAttributeView get(ZipPath path, String type) {
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
if (type.equals("basic"))
|
||||
return new ZipFileAttributeView(path, false);
|
||||
if (type.equals("zip"))
|
||||
return new ZipFileAttributeView(path, true);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return isZipView ? "zip" : "basic";
|
||||
}
|
||||
|
||||
public ZipFileAttributes readAttributes() throws IOException
|
||||
{
|
||||
return path.getAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimes(FileTime lastModifiedTime,
|
||||
FileTime lastAccessTime,
|
||||
FileTime createTime)
|
||||
throws IOException
|
||||
{
|
||||
path.setTimes(lastModifiedTime, lastAccessTime, createTime);
|
||||
}
|
||||
|
||||
void setAttribute(String attribute, Object value)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime)
|
||||
setTimes ((FileTime)value, null, null);
|
||||
if (AttrID.valueOf(attribute) == AttrID.lastAccessTime)
|
||||
setTimes (null, (FileTime)value, null);
|
||||
if (AttrID.valueOf(attribute) == AttrID.creationTime)
|
||||
setTimes (null, null, (FileTime)value);
|
||||
return;
|
||||
} catch (IllegalArgumentException x) {}
|
||||
throw new UnsupportedOperationException("'" + attribute +
|
||||
"' is unknown or read-only attribute");
|
||||
}
|
||||
|
||||
Map<String, Object> readAttributes(String attributes)
|
||||
throws IOException
|
||||
{
|
||||
ZipFileAttributes zfas = readAttributes();
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
if ("*".equals(attributes)) {
|
||||
for (AttrID id : AttrID.values()) {
|
||||
try {
|
||||
map.put(id.name(), attribute(id, zfas));
|
||||
} catch (IllegalArgumentException x) {}
|
||||
}
|
||||
} else {
|
||||
String[] as = attributes.split(",");
|
||||
for (String a : as) {
|
||||
try {
|
||||
map.put(a, attribute(AttrID.valueOf(a), zfas));
|
||||
} catch (IllegalArgumentException x) {}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
Object attribute(AttrID id, ZipFileAttributes zfas) {
|
||||
switch (id) {
|
||||
case size:
|
||||
return zfas.size();
|
||||
case creationTime:
|
||||
return zfas.creationTime();
|
||||
case lastAccessTime:
|
||||
return zfas.lastAccessTime();
|
||||
case lastModifiedTime:
|
||||
return zfas.lastModifiedTime();
|
||||
case isDirectory:
|
||||
return zfas.isDirectory();
|
||||
case isRegularFile:
|
||||
return zfas.isRegularFile();
|
||||
case isSymbolicLink:
|
||||
return zfas.isSymbolicLink();
|
||||
case isOther:
|
||||
return zfas.isOther();
|
||||
case fileKey:
|
||||
return zfas.fileKey();
|
||||
case compressedSize:
|
||||
if (isZipView)
|
||||
return zfas.compressedSize();
|
||||
break;
|
||||
case crc:
|
||||
if (isZipView)
|
||||
return zfas.crc();
|
||||
break;
|
||||
case method:
|
||||
if (isZipView)
|
||||
return zfas.method();
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
|
||||
*/
|
||||
|
||||
public class ZipFileAttributes implements BasicFileAttributes
|
||||
|
||||
{
|
||||
private final ZipFileSystem.Entry e;
|
||||
|
||||
ZipFileAttributes(ZipFileSystem.Entry e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
///////// basic attributes ///////////
|
||||
@Override
|
||||
public FileTime creationTime() {
|
||||
if (e.ctime != -1)
|
||||
return FileTime.fromMillis(e.ctime);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return e.isDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOther() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegularFile() {
|
||||
return !e.isDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastAccessTime() {
|
||||
if (e.atime != -1)
|
||||
return FileTime.fromMillis(e.atime);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
return FileTime.fromMillis(e.mtime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return e.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSymbolicLink() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fileKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
///////// zip entry attributes ///////////
|
||||
public long compressedSize() {
|
||||
return e.csize;
|
||||
}
|
||||
|
||||
public long crc() {
|
||||
return e.crc;
|
||||
}
|
||||
|
||||
public int method() {
|
||||
return e.method;
|
||||
}
|
||||
|
||||
public byte[] extra() {
|
||||
if (e.extra != null)
|
||||
return Arrays.copyOf(e.extra, e.extra.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] comment() {
|
||||
if (e.comment != null)
|
||||
return Arrays.copyOf(e.comment, e.comment.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
Formatter fm = new Formatter(sb);
|
||||
if (creationTime() != null)
|
||||
fm.format(" creationTime : %tc%n", creationTime().toMillis());
|
||||
else
|
||||
fm.format(" creationTime : null%n");
|
||||
|
||||
if (lastAccessTime() != null)
|
||||
fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis());
|
||||
else
|
||||
fm.format(" lastAccessTime : null%n");
|
||||
fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
|
||||
fm.format(" isRegularFile : %b%n", isRegularFile());
|
||||
fm.format(" isDirectory : %b%n", isDirectory());
|
||||
fm.format(" isSymbolicLink : %b%n", isSymbolicLink());
|
||||
fm.format(" isOther : %b%n", isOther());
|
||||
fm.format(" fileKey : %s%n", fileKey());
|
||||
fm.format(" size : %d%n", size());
|
||||
fm.format(" compressedSize : %d%n", compressedSize());
|
||||
fm.format(" crc : %x%n", crc());
|
||||
fm.format(" method : %d%n", method());
|
||||
fm.close();
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.attribute.FileStoreAttributeView;
|
||||
|
||||
/*
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
|
||||
public class ZipFileStore extends FileStore {
|
||||
|
||||
private final ZipFileSystem zfs;
|
||||
|
||||
ZipFileStore(ZipPath zpath) {
|
||||
this.zfs = zpath.getFileSystem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return zfs.toString() + "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "zipfs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return zfs.isReadOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
|
||||
return (type == BasicFileAttributeView.class ||
|
||||
type == ZipFileAttributeView.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileAttributeView(String name) {
|
||||
return name.equals("basic") || name.equals("zip");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
return (V)null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalSpace() throws IOException {
|
||||
return new ZipFileStoreAttributes(this).totalSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsableSpace() throws IOException {
|
||||
return new ZipFileStoreAttributes(this).usableSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnallocatedSpace() throws IOException {
|
||||
return new ZipFileStoreAttributes(this).unallocatedSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String attribute) throws IOException {
|
||||
if (attribute.equals("totalSpace"))
|
||||
return getTotalSpace();
|
||||
if (attribute.equals("usableSpace"))
|
||||
return getUsableSpace();
|
||||
if (attribute.equals("unallocatedSpace"))
|
||||
return getUnallocatedSpace();
|
||||
throw new UnsupportedOperationException("does not support the given attribute");
|
||||
}
|
||||
|
||||
private static class ZipFileStoreAttributes {
|
||||
final FileStore fstore;
|
||||
final long size;
|
||||
|
||||
public ZipFileStoreAttributes(ZipFileStore fileStore)
|
||||
throws IOException
|
||||
{
|
||||
Path path = FileSystems.getDefault().getPath(fileStore.name());
|
||||
this.size = Files.size(path);
|
||||
this.fstore = Files.getFileStore(path);
|
||||
}
|
||||
|
||||
public long totalSpace() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public long usableSpace() throws IOException {
|
||||
if (!fstore.isReadOnly())
|
||||
return fstore.getUsableSpace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long unallocatedSpace() throws IOException {
|
||||
if (!fstore.isReadOnly())
|
||||
return fstore.getUnallocatedSpace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.channels.AsynchronousFileChannel;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.AccessMode;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.DirectoryStream.Filter;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystemAlreadyExistsException;
|
||||
import java.nio.file.FileSystemNotFoundException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.ProviderMismatchException;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileAttributeView;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.zip.ZipError;
|
||||
|
||||
/*
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
|
||||
public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
|
||||
|
||||
private final Map<Path, ZipFileSystem> filesystems = new HashMap<>();
|
||||
|
||||
public ZipFileSystemProvider() {}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "zipfs";
|
||||
}
|
||||
|
||||
protected Path uriToPath(URI uri) {
|
||||
String scheme = uri.getScheme();
|
||||
if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
|
||||
throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
|
||||
}
|
||||
try {
|
||||
// only support legacy JAR URL syntax jar:{uri}!/{entry} for now
|
||||
String spec = uri.getRawSchemeSpecificPart();
|
||||
int sep = spec.indexOf("!/");
|
||||
if (sep != -1)
|
||||
spec = spec.substring(0, sep);
|
||||
return Paths.get(new URI(spec)).toAbsolutePath();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ensureFile(Path path) {
|
||||
try {
|
||||
BasicFileAttributes attrs =
|
||||
Files.readAttributes(path, BasicFileAttributes.class);
|
||||
if (!attrs.isRegularFile())
|
||||
throw new UnsupportedOperationException();
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem newFileSystem(URI uri, Map<String, ?> env)
|
||||
throws IOException
|
||||
{
|
||||
Path path = uriToPath(uri);
|
||||
synchronized(filesystems) {
|
||||
Path realPath = null;
|
||||
if (ensureFile(path)) {
|
||||
realPath = path.toRealPath();
|
||||
if (filesystems.containsKey(realPath))
|
||||
throw new FileSystemAlreadyExistsException();
|
||||
}
|
||||
ZipFileSystem zipfs = null;
|
||||
try {
|
||||
zipfs = new ZipFileSystem(this, path, env);
|
||||
} catch (ZipError ze) {
|
||||
String pname = path.toString();
|
||||
if (pname.endsWith(".zip") || pname.endsWith(".jar"))
|
||||
throw ze;
|
||||
// assume NOT a zip/jar file
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
filesystems.put(realPath, zipfs);
|
||||
return zipfs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem newFileSystem(Path path, Map<String, ?> env)
|
||||
throws IOException
|
||||
{
|
||||
if (path.getFileSystem() != FileSystems.getDefault()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
ensureFile(path);
|
||||
try {
|
||||
return new ZipFileSystem(this, path, env);
|
||||
} catch (ZipError ze) {
|
||||
String pname = path.toString();
|
||||
if (pname.endsWith(".zip") || pname.endsWith(".jar"))
|
||||
throw ze;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(URI uri) {
|
||||
|
||||
String spec = uri.getSchemeSpecificPart();
|
||||
int sep = spec.indexOf("!/");
|
||||
if (sep == -1)
|
||||
throw new IllegalArgumentException("URI: "
|
||||
+ uri
|
||||
+ " does not contain path info ex. jar:file:/c:/foo.zip!/BAR");
|
||||
return getFileSystem(uri).getPath(spec.substring(sep + 1));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FileSystem getFileSystem(URI uri) {
|
||||
synchronized (filesystems) {
|
||||
ZipFileSystem zipfs = null;
|
||||
try {
|
||||
zipfs = filesystems.get(uriToPath(uri).toRealPath());
|
||||
} catch (IOException x) {
|
||||
// ignore the ioe from toRealPath(), return FSNFE
|
||||
}
|
||||
if (zipfs == null)
|
||||
throw new FileSystemNotFoundException();
|
||||
return zipfs;
|
||||
}
|
||||
}
|
||||
|
||||
// Checks that the given file is a UnixPath
|
||||
static final ZipPath toZipPath(Path path) {
|
||||
if (path == null)
|
||||
throw new NullPointerException();
|
||||
if (!(path instanceof ZipPath))
|
||||
throw new ProviderMismatchException();
|
||||
return (ZipPath)path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Path path, AccessMode... modes) throws IOException {
|
||||
toZipPath(path).checkAccess(modes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(Path src, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(src).copy(toZipPath(target), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createDirectory(Path path, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(path).createDirectory(attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void delete(Path path) throws IOException {
|
||||
toZipPath(path).delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V extends FileAttributeView> V
|
||||
getFileAttributeView(Path path, Class<V> type, LinkOption... options)
|
||||
{
|
||||
return ZipFileAttributeView.get(toZipPath(path), type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileStore getFileStore(Path path) throws IOException {
|
||||
return toZipPath(path).getFileStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(Path path) {
|
||||
return toZipPath(path).isHidden();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameFile(Path path, Path other) throws IOException {
|
||||
return toZipPath(path).isSameFile(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Path src, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(src).move(toZipPath(target), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
ExecutorService exec,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeekableByteChannel newByteChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newByteChannel(options, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirectoryStream<Path> newDirectoryStream(
|
||||
Path path, Filter<? super Path> filter) throws IOException
|
||||
{
|
||||
return toZipPath(path).newDirectoryStream(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileChannel newFileChannel(Path path,
|
||||
Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newFileChannel(options, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream newInputStream(Path path, OpenOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newInputStream(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream newOutputStream(Path path, OpenOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).newOutputStream(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends BasicFileAttributes> A
|
||||
readAttributes(Path path, Class<A> type, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
if (type == BasicFileAttributes.class || type == ZipFileAttributes.class)
|
||||
return (A)toZipPath(path).getAttributes();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object>
|
||||
readAttributes(Path path, String attribute, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return toZipPath(path).readAttributes(attribute, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readSymbolicLink(Path link) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(Path path, String attribute,
|
||||
Object value, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
toZipPath(path).setAttribute(attribute, value, options);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
void removeFileSystem(Path zfpath, ZipFileSystem zfs) throws IOException {
|
||||
synchronized (filesystems) {
|
||||
zfpath = zfpath.toRealPath();
|
||||
if (filesystems.get(zfpath) == zfs)
|
||||
filesystems.remove(zfpath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,915 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
import static java.nio.file.StandardOpenOption.CREATE_NEW;
|
||||
import static java.nio.file.StandardOpenOption.READ;
|
||||
import static java.nio.file.StandardOpenOption.WRITE;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.nio.file.AccessDeniedException;
|
||||
import java.nio.file.AccessMode;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.DirectoryStream.Filter;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.ProviderMismatchException;
|
||||
import java.nio.file.ReadOnlyFileSystemException;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.nio.file.WatchKey;
|
||||
import java.nio.file.WatchService;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
|
||||
*/
|
||||
|
||||
public class ZipPath implements Path {
|
||||
|
||||
private final ZipFileSystem zfs;
|
||||
private final byte[] path;
|
||||
private volatile int[] offsets;
|
||||
private int hashcode = 0; // cached hashcode (created lazily)
|
||||
|
||||
ZipPath(ZipFileSystem zfs, byte[] path) {
|
||||
this(zfs, path, false);
|
||||
}
|
||||
|
||||
ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized)
|
||||
{
|
||||
this.zfs = zfs;
|
||||
if (normalized)
|
||||
this.path = path;
|
||||
else
|
||||
this.path = normalize(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath getRoot() {
|
||||
if (this.isAbsolute())
|
||||
return new ZipPath(zfs, new byte[]{path[0]});
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getFileName() {
|
||||
initOffsets();
|
||||
int count = offsets.length;
|
||||
if (count == 0)
|
||||
return null; // no elements so no name
|
||||
if (count == 1 && path[0] != '/')
|
||||
return this;
|
||||
int lastOffset = offsets[count-1];
|
||||
int len = path.length - lastOffset;
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, lastOffset, result, 0, len);
|
||||
return new ZipPath(zfs, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath getParent() {
|
||||
initOffsets();
|
||||
int count = offsets.length;
|
||||
if (count == 0) // no elements so no parent
|
||||
return null;
|
||||
int len = offsets[count-1] - 1;
|
||||
if (len <= 0) // parent is root only (may be null)
|
||||
return getRoot();
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, 0, result, 0, len);
|
||||
return new ZipPath(zfs, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNameCount() {
|
||||
initOffsets();
|
||||
return offsets.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath getName(int index) {
|
||||
initOffsets();
|
||||
if (index < 0 || index >= offsets.length)
|
||||
throw new IllegalArgumentException();
|
||||
int begin = offsets[index];
|
||||
int len;
|
||||
if (index == (offsets.length-1))
|
||||
len = path.length - begin;
|
||||
else
|
||||
len = offsets[index+1] - begin - 1;
|
||||
// construct result
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, begin, result, 0, len);
|
||||
return new ZipPath(zfs, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath subpath(int beginIndex, int endIndex) {
|
||||
initOffsets();
|
||||
if (beginIndex < 0 ||
|
||||
beginIndex >= offsets.length ||
|
||||
endIndex > offsets.length ||
|
||||
beginIndex >= endIndex)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
// starting offset and length
|
||||
int begin = offsets[beginIndex];
|
||||
int len;
|
||||
if (endIndex == offsets.length)
|
||||
len = path.length - begin;
|
||||
else
|
||||
len = offsets[endIndex] - begin - 1;
|
||||
// construct result
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(path, begin, result, 0, len);
|
||||
return new ZipPath(zfs, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath toRealPath(LinkOption... options) throws IOException {
|
||||
ZipPath realPath = new ZipPath(zfs, getResolvedPath()).toAbsolutePath();
|
||||
realPath.checkAccess();
|
||||
return realPath;
|
||||
}
|
||||
|
||||
boolean isHidden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath toAbsolutePath() {
|
||||
if (isAbsolute()) {
|
||||
return this;
|
||||
} else {
|
||||
//add / bofore the existing path
|
||||
byte[] defaultdir = zfs.getDefaultDir().path;
|
||||
int defaultlen = defaultdir.length;
|
||||
boolean endsWith = (defaultdir[defaultlen - 1] == '/');
|
||||
byte[] t = null;
|
||||
if (endsWith)
|
||||
t = new byte[defaultlen + path.length];
|
||||
else
|
||||
t = new byte[defaultlen + 1 + path.length];
|
||||
System.arraycopy(defaultdir, 0, t, 0, defaultlen);
|
||||
if (!endsWith)
|
||||
t[defaultlen++] = '/';
|
||||
System.arraycopy(path, 0, t, defaultlen, path.length);
|
||||
return new ZipPath(zfs, t, true); // normalized
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI toUri() {
|
||||
try {
|
||||
return new URI(zfs.provider().getScheme(),
|
||||
zfs.getZipFile().toUri() +
|
||||
"!" +
|
||||
zfs.getString(toAbsolutePath().path),
|
||||
null);
|
||||
} catch (Exception ex) {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean equalsNameAt(ZipPath other, int index) {
|
||||
int mbegin = offsets[index];
|
||||
int mlen = 0;
|
||||
if (index == (offsets.length-1))
|
||||
mlen = path.length - mbegin;
|
||||
else
|
||||
mlen = offsets[index + 1] - mbegin - 1;
|
||||
int obegin = other.offsets[index];
|
||||
int olen = 0;
|
||||
if (index == (other.offsets.length - 1))
|
||||
olen = other.path.length - obegin;
|
||||
else
|
||||
olen = other.offsets[index + 1] - obegin - 1;
|
||||
if (mlen != olen)
|
||||
return false;
|
||||
int n = 0;
|
||||
while(n < mlen) {
|
||||
if (path[mbegin + n] != other.path[obegin + n])
|
||||
return false;
|
||||
n++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path relativize(Path other) {
|
||||
final ZipPath o = checkPath(other);
|
||||
if (o.equals(this))
|
||||
return new ZipPath(getFileSystem(), new byte[0], true);
|
||||
if (/* this.getFileSystem() != o.getFileSystem() || */
|
||||
this.isAbsolute() != o.isAbsolute()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
int mc = this.getNameCount();
|
||||
int oc = o.getNameCount();
|
||||
int n = Math.min(mc, oc);
|
||||
int i = 0;
|
||||
while (i < n) {
|
||||
if (!equalsNameAt(o, i))
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
int dotdots = mc - i;
|
||||
int len = dotdots * 3 - 1;
|
||||
if (i < oc)
|
||||
len += (o.path.length - o.offsets[i] + 1);
|
||||
byte[] result = new byte[len];
|
||||
|
||||
int pos = 0;
|
||||
while (dotdots > 0) {
|
||||
result[pos++] = (byte)'.';
|
||||
result[pos++] = (byte)'.';
|
||||
if (pos < len) // no tailing slash at the end
|
||||
result[pos++] = (byte)'/';
|
||||
dotdots--;
|
||||
}
|
||||
if (i < oc)
|
||||
System.arraycopy(o.path, o.offsets[i],
|
||||
result, pos,
|
||||
o.path.length - o.offsets[i]);
|
||||
return new ZipPath(getFileSystem(), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipFileSystem getFileSystem() {
|
||||
return zfs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbsolute() {
|
||||
return (this.path.length > 0 && path[0] == '/');
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath resolve(Path other) {
|
||||
final ZipPath o = checkPath(other);
|
||||
if (o.isAbsolute())
|
||||
return o;
|
||||
byte[] resolved = null;
|
||||
if (this.path[path.length - 1] == '/') {
|
||||
resolved = new byte[path.length + o.path.length];
|
||||
System.arraycopy(path, 0, resolved, 0, path.length);
|
||||
System.arraycopy(o.path, 0, resolved, path.length, o.path.length);
|
||||
} else {
|
||||
resolved = new byte[path.length + 1 + o.path.length];
|
||||
System.arraycopy(path, 0, resolved, 0, path.length);
|
||||
resolved[path.length] = '/';
|
||||
System.arraycopy(o.path, 0, resolved, path.length + 1, o.path.length);
|
||||
}
|
||||
return new ZipPath(zfs, resolved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path resolveSibling(Path other) {
|
||||
if (other == null)
|
||||
throw new NullPointerException();
|
||||
Path parent = getParent();
|
||||
return (parent == null) ? other : parent.resolve(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startsWith(Path other) {
|
||||
final ZipPath o = checkPath(other);
|
||||
if (o.isAbsolute() != this.isAbsolute() ||
|
||||
o.path.length > this.path.length)
|
||||
return false;
|
||||
int olast = o.path.length;
|
||||
for (int i = 0; i < olast; i++) {
|
||||
if (o.path[i] != this.path[i])
|
||||
return false;
|
||||
}
|
||||
olast--;
|
||||
return o.path.length == this.path.length ||
|
||||
o.path[olast] == '/' ||
|
||||
this.path[olast + 1] == '/';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean endsWith(Path other) {
|
||||
final ZipPath o = checkPath(other);
|
||||
int olast = o.path.length - 1;
|
||||
if (olast > 0 && o.path[olast] == '/')
|
||||
olast--;
|
||||
int last = this.path.length - 1;
|
||||
if (last > 0 && this.path[last] == '/')
|
||||
last--;
|
||||
if (olast == -1) // o.path.length == 0
|
||||
return last == -1;
|
||||
if ((o.isAbsolute() &&(!this.isAbsolute() || olast != last)) ||
|
||||
(last < olast))
|
||||
return false;
|
||||
for (; olast >= 0; olast--, last--) {
|
||||
if (o.path[olast] != this.path[last])
|
||||
return false;
|
||||
}
|
||||
return o.path[olast + 1] == '/' ||
|
||||
last == -1 || this.path[last] == '/';
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath resolve(String other) {
|
||||
return resolve(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Path resolveSibling(String other) {
|
||||
return resolveSibling(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean startsWith(String other) {
|
||||
return startsWith(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean endsWith(String other) {
|
||||
return endsWith(getFileSystem().getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path normalize() {
|
||||
byte[] resolved = getResolved();
|
||||
if (resolved == path) // no change
|
||||
return this;
|
||||
return new ZipPath(zfs, resolved, true);
|
||||
}
|
||||
|
||||
private ZipPath checkPath(Path path) {
|
||||
if (path == null)
|
||||
throw new NullPointerException();
|
||||
if (!(path instanceof ZipPath))
|
||||
throw new ProviderMismatchException();
|
||||
return (ZipPath) path;
|
||||
}
|
||||
|
||||
// create offset list if not already created
|
||||
private void initOffsets() {
|
||||
if (offsets == null) {
|
||||
int count, index;
|
||||
// count names
|
||||
count = 0;
|
||||
index = 0;
|
||||
while (index < path.length) {
|
||||
byte c = path[index++];
|
||||
if (c != '/') {
|
||||
count++;
|
||||
while (index < path.length && path[index] != '/')
|
||||
index++;
|
||||
}
|
||||
}
|
||||
// populate offsets
|
||||
int[] result = new int[count];
|
||||
count = 0;
|
||||
index = 0;
|
||||
while (index < path.length) {
|
||||
byte c = path[index];
|
||||
if (c == '/') {
|
||||
index++;
|
||||
} else {
|
||||
result[count++] = index++;
|
||||
while (index < path.length && path[index] != '/')
|
||||
index++;
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
if (offsets == null)
|
||||
offsets = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resolved path for locating zip entry inside the zip file,
|
||||
// the result path does not contain ./ and .. components
|
||||
private volatile byte[] resolved = null;
|
||||
byte[] getResolvedPath() {
|
||||
byte[] r = resolved;
|
||||
if (r == null) {
|
||||
if (isAbsolute())
|
||||
r = getResolved();
|
||||
else
|
||||
r = toAbsolutePath().getResolvedPath();
|
||||
if (r[0] == '/')
|
||||
r = Arrays.copyOfRange(r, 1, r.length);
|
||||
resolved = r;
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
// removes redundant slashs, replace "\" to zip separator "/"
|
||||
// and check for invalid characters
|
||||
private byte[] normalize(byte[] path) {
|
||||
if (path.length == 0)
|
||||
return path;
|
||||
byte prevC = 0;
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
byte c = path[i];
|
||||
if (c == '\\')
|
||||
return normalize(path, i);
|
||||
if (c == (byte)'/' && prevC == '/')
|
||||
return normalize(path, i - 1);
|
||||
if (c == '\u0000')
|
||||
throw new InvalidPathException(zfs.getString(path),
|
||||
"Path: nul character not allowed");
|
||||
prevC = c;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private byte[] normalize(byte[] path, int off) {
|
||||
byte[] to = new byte[path.length];
|
||||
int n = 0;
|
||||
while (n < off) {
|
||||
to[n] = path[n];
|
||||
n++;
|
||||
}
|
||||
int m = n;
|
||||
byte prevC = 0;
|
||||
while (n < path.length) {
|
||||
byte c = path[n++];
|
||||
if (c == (byte)'\\')
|
||||
c = (byte)'/';
|
||||
if (c == (byte)'/' && prevC == (byte)'/')
|
||||
continue;
|
||||
if (c == '\u0000')
|
||||
throw new InvalidPathException(zfs.getString(path),
|
||||
"Path: nul character not allowed");
|
||||
to[m++] = c;
|
||||
prevC = c;
|
||||
}
|
||||
if (m > 1 && to[m - 1] == '/')
|
||||
m--;
|
||||
return (m == to.length)? to : Arrays.copyOf(to, m);
|
||||
}
|
||||
|
||||
// Remove DotSlash(./) and resolve DotDot (..) components
|
||||
private byte[] getResolved() {
|
||||
if (path.length == 0)
|
||||
return path;
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
byte c = path[i];
|
||||
if (c == (byte)'.')
|
||||
return resolve0();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// TBD: performance, avoid initOffsets
|
||||
private byte[] resolve0() {
|
||||
byte[] to = new byte[path.length];
|
||||
int nc = getNameCount();
|
||||
int[] lastM = new int[nc];
|
||||
int lastMOff = -1;
|
||||
int m = 0;
|
||||
for (int i = 0; i < nc; i++) {
|
||||
int n = offsets[i];
|
||||
int len = (i == offsets.length - 1)?
|
||||
(path.length - n):(offsets[i + 1] - n - 1);
|
||||
if (len == 1 && path[n] == (byte)'.') {
|
||||
if (m == 0 && path[0] == '/') // absolute path
|
||||
to[m++] = '/';
|
||||
continue;
|
||||
}
|
||||
if (len == 2 && path[n] == '.' && path[n + 1] == '.') {
|
||||
if (lastMOff >= 0) {
|
||||
m = lastM[lastMOff--]; // retreat
|
||||
continue;
|
||||
}
|
||||
if (path[0] == '/') { // "/../xyz" skip
|
||||
if (m == 0)
|
||||
to[m++] = '/';
|
||||
} else { // "../xyz" -> "../xyz"
|
||||
if (m != 0 && to[m-1] != '/')
|
||||
to[m++] = '/';
|
||||
while (len-- > 0)
|
||||
to[m++] = path[n++];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (m == 0 && path[0] == '/' || // absolute path
|
||||
m != 0 && to[m-1] != '/') { // not the first name
|
||||
to[m++] = '/';
|
||||
}
|
||||
lastM[++lastMOff] = m;
|
||||
while (len-- > 0)
|
||||
to[m++] = path[n++];
|
||||
}
|
||||
if (m > 1 && to[m - 1] == '/')
|
||||
m--;
|
||||
return (m == to.length)? to : Arrays.copyOf(to, m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return zfs.getString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = hashcode;
|
||||
if (h == 0)
|
||||
hashcode = h = Arrays.hashCode(path);
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj != null &&
|
||||
obj instanceof ZipPath &&
|
||||
this.zfs == ((ZipPath)obj).zfs &&
|
||||
compareTo((Path) obj) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Path other) {
|
||||
final ZipPath o = checkPath(other);
|
||||
int len1 = this.path.length;
|
||||
int len2 = o.path.length;
|
||||
|
||||
int n = Math.min(len1, len2);
|
||||
byte v1[] = this.path;
|
||||
byte v2[] = o.path;
|
||||
|
||||
int k = 0;
|
||||
while (k < n) {
|
||||
int c1 = v1[k] & 0xff;
|
||||
int c2 = v2[k] & 0xff;
|
||||
if (c1 != c2)
|
||||
return c1 - c2;
|
||||
k++;
|
||||
}
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
public WatchKey register(
|
||||
WatchService watcher,
|
||||
WatchEvent.Kind<?>[] events,
|
||||
WatchEvent.Modifier... modifiers) {
|
||||
if (watcher == null || events == null || modifiers == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) {
|
||||
return register(watcher, events, new WatchEvent.Modifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final File toFile() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Path> iterator() {
|
||||
return new Iterator<Path>() {
|
||||
private int i = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (i < getNameCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path next() {
|
||||
if (i < getNameCount()) {
|
||||
Path result = getName(i);
|
||||
i++;
|
||||
return result;
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new ReadOnlyFileSystemException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void createDirectory(FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
zfs.createDirectory(getResolvedPath(), attrs);
|
||||
}
|
||||
|
||||
InputStream newInputStream(OpenOption... options) throws IOException
|
||||
{
|
||||
if (options.length > 0) {
|
||||
for (OpenOption opt : options) {
|
||||
if (opt != READ)
|
||||
throw new UnsupportedOperationException("'" + opt + "' not allowed");
|
||||
}
|
||||
}
|
||||
return zfs.newInputStream(getResolvedPath());
|
||||
}
|
||||
|
||||
DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter)
|
||||
throws IOException
|
||||
{
|
||||
return new ZipDirectoryStream(this, filter);
|
||||
}
|
||||
|
||||
void delete() throws IOException {
|
||||
zfs.deleteFile(getResolvedPath(), true);
|
||||
}
|
||||
|
||||
void deleteIfExists() throws IOException {
|
||||
zfs.deleteFile(getResolvedPath(), false);
|
||||
}
|
||||
|
||||
ZipFileAttributes getAttributes() throws IOException
|
||||
{
|
||||
ZipFileAttributes zfas = zfs.getFileAttributes(getResolvedPath());
|
||||
if (zfas == null)
|
||||
throw new NoSuchFileException(toString());
|
||||
return zfas;
|
||||
}
|
||||
|
||||
void setAttribute(String attribute, Object value, LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
String type = null;
|
||||
String attr = null;
|
||||
int colonPos = attribute.indexOf(':');
|
||||
if (colonPos == -1) {
|
||||
type = "basic";
|
||||
attr = attribute;
|
||||
} else {
|
||||
type = attribute.substring(0, colonPos++);
|
||||
attr = attribute.substring(colonPos);
|
||||
}
|
||||
ZipFileAttributeView view = ZipFileAttributeView.get(this, type);
|
||||
if (view == null)
|
||||
throw new UnsupportedOperationException("view <" + view + "> is not supported");
|
||||
view.setAttribute(attr, value);
|
||||
}
|
||||
|
||||
void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
|
||||
throws IOException
|
||||
{
|
||||
zfs.setTimes(getResolvedPath(), mtime, atime, ctime);
|
||||
}
|
||||
|
||||
Map<String, Object> readAttributes(String attributes, LinkOption... options)
|
||||
throws IOException
|
||||
|
||||
{
|
||||
String view = null;
|
||||
String attrs = null;
|
||||
int colonPos = attributes.indexOf(':');
|
||||
if (colonPos == -1) {
|
||||
view = "basic";
|
||||
attrs = attributes;
|
||||
} else {
|
||||
view = attributes.substring(0, colonPos++);
|
||||
attrs = attributes.substring(colonPos);
|
||||
}
|
||||
ZipFileAttributeView zfv = ZipFileAttributeView.get(this, view);
|
||||
if (zfv == null) {
|
||||
throw new UnsupportedOperationException("view not supported");
|
||||
}
|
||||
return zfv.readAttributes(attrs);
|
||||
}
|
||||
|
||||
FileStore getFileStore() throws IOException {
|
||||
// each ZipFileSystem only has one root (as requested for now)
|
||||
if (exists())
|
||||
return zfs.getFileStore(this);
|
||||
throw new NoSuchFileException(zfs.getString(path));
|
||||
}
|
||||
|
||||
boolean isSameFile(Path other) throws IOException {
|
||||
if (this.equals(other))
|
||||
return true;
|
||||
if (other == null ||
|
||||
this.getFileSystem() != other.getFileSystem())
|
||||
return false;
|
||||
this.checkAccess();
|
||||
((ZipPath)other).checkAccess();
|
||||
return Arrays.equals(this.getResolvedPath(),
|
||||
((ZipPath)other).getResolvedPath());
|
||||
}
|
||||
|
||||
SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
return zfs.newByteChannel(getResolvedPath(), options, attrs);
|
||||
}
|
||||
|
||||
|
||||
FileChannel newFileChannel(Set<? extends OpenOption> options,
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
return zfs.newFileChannel(getResolvedPath(), options, attrs);
|
||||
}
|
||||
|
||||
void checkAccess(AccessMode... modes) throws IOException {
|
||||
boolean w = false;
|
||||
boolean x = false;
|
||||
for (AccessMode mode : modes) {
|
||||
switch (mode) {
|
||||
case READ:
|
||||
break;
|
||||
case WRITE:
|
||||
w = true;
|
||||
break;
|
||||
case EXECUTE:
|
||||
x = true;
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
ZipFileAttributes attrs = zfs.getFileAttributes(getResolvedPath());
|
||||
if (attrs == null && (path.length != 1 || path[0] != '/'))
|
||||
throw new NoSuchFileException(toString());
|
||||
if (w) {
|
||||
if (zfs.isReadOnly())
|
||||
throw new AccessDeniedException(toString());
|
||||
}
|
||||
if (x)
|
||||
throw new AccessDeniedException(toString());
|
||||
}
|
||||
|
||||
boolean exists() {
|
||||
if (path.length == 1 && path[0] == '/')
|
||||
return true;
|
||||
try {
|
||||
return zfs.exists(getResolvedPath());
|
||||
} catch (IOException x) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
OutputStream newOutputStream(OpenOption... options) throws IOException
|
||||
{
|
||||
if (options.length == 0)
|
||||
return zfs.newOutputStream(getResolvedPath(),
|
||||
CREATE_NEW, WRITE);
|
||||
return zfs.newOutputStream(getResolvedPath(), options);
|
||||
}
|
||||
|
||||
void move(ZipPath target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
if (Files.isSameFile(this.zfs.getZipFile(), target.zfs.getZipFile()))
|
||||
{
|
||||
zfs.copyFile(true,
|
||||
getResolvedPath(), target.getResolvedPath(),
|
||||
options);
|
||||
} else {
|
||||
copyToTarget(target, options);
|
||||
delete();
|
||||
}
|
||||
}
|
||||
|
||||
void copy(ZipPath target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
if (Files.isSameFile(this.zfs.getZipFile(), target.zfs.getZipFile()))
|
||||
zfs.copyFile(false,
|
||||
getResolvedPath(), target.getResolvedPath(),
|
||||
options);
|
||||
else
|
||||
copyToTarget(target, options);
|
||||
}
|
||||
|
||||
private void copyToTarget(ZipPath target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
boolean replaceExisting = false;
|
||||
boolean copyAttrs = false;
|
||||
for (CopyOption opt : options) {
|
||||
if (opt == REPLACE_EXISTING)
|
||||
replaceExisting = true;
|
||||
else if (opt == COPY_ATTRIBUTES)
|
||||
copyAttrs = true;
|
||||
}
|
||||
// attributes of source file
|
||||
ZipFileAttributes zfas = getAttributes();
|
||||
// check if target exists
|
||||
boolean exists;
|
||||
if (replaceExisting) {
|
||||
try {
|
||||
target.deleteIfExists();
|
||||
exists = false;
|
||||
} catch (DirectoryNotEmptyException x) {
|
||||
exists = true;
|
||||
}
|
||||
} else {
|
||||
exists = target.exists();
|
||||
}
|
||||
if (exists)
|
||||
throw new FileAlreadyExistsException(target.toString());
|
||||
|
||||
if (zfas.isDirectory()) {
|
||||
// create directory or file
|
||||
target.createDirectory();
|
||||
} else {
|
||||
InputStream is = zfs.newInputStream(getResolvedPath());
|
||||
try {
|
||||
OutputStream os = target.newOutputStream();
|
||||
try {
|
||||
byte[] buf = new byte[8192];
|
||||
int n = 0;
|
||||
while ((n = is.read(buf)) != -1) {
|
||||
os.write(buf, 0, n);
|
||||
}
|
||||
} finally {
|
||||
os.close();
|
||||
}
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
if (copyAttrs) {
|
||||
BasicFileAttributeView view =
|
||||
ZipFileAttributeView.get(target, BasicFileAttributeView.class);
|
||||
try {
|
||||
view.setTimes(zfas.lastModifiedTime(),
|
||||
zfas.lastAccessTime(),
|
||||
zfas.creationTime());
|
||||
} catch (IOException x) {
|
||||
// rollback?
|
||||
try {
|
||||
target.delete();
|
||||
} catch (IOException ignore) { }
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of Oracle nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This source code is provided to illustrate the usage of a given feature
|
||||
* or technique and has been deliberately simplified. Additional steps
|
||||
* required for a production-quality application, such as security checks,
|
||||
* input validation and proper error handling, might not be present in
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.marschall.com.sun.nio.zipfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xueming Shen
|
||||
*/
|
||||
|
||||
class ZipUtils {
|
||||
|
||||
/*
|
||||
* Writes a 16-bit short to the output stream in little-endian byte order.
|
||||
*/
|
||||
public static void writeShort(OutputStream os, int v) throws IOException {
|
||||
os.write(v & 0xff);
|
||||
os.write((v >>> 8) & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 32-bit int to the output stream in little-endian byte order.
|
||||
*/
|
||||
public static void writeInt(OutputStream os, long v) throws IOException {
|
||||
os.write((int)(v & 0xff));
|
||||
os.write((int)((v >>> 8) & 0xff));
|
||||
os.write((int)((v >>> 16) & 0xff));
|
||||
os.write((int)((v >>> 24) & 0xff));
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes a 64-bit int to the output stream in little-endian byte order.
|
||||
*/
|
||||
public static void writeLong(OutputStream os, long v) throws IOException {
|
||||
os.write((int)(v & 0xff));
|
||||
os.write((int)((v >>> 8) & 0xff));
|
||||
os.write((int)((v >>> 16) & 0xff));
|
||||
os.write((int)((v >>> 24) & 0xff));
|
||||
os.write((int)((v >>> 32) & 0xff));
|
||||
os.write((int)((v >>> 40) & 0xff));
|
||||
os.write((int)((v >>> 48) & 0xff));
|
||||
os.write((int)((v >>> 56) & 0xff));
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes an array of bytes to the output stream.
|
||||
*/
|
||||
public static void writeBytes(OutputStream os, byte[] b)
|
||||
throws IOException
|
||||
{
|
||||
os.write(b, 0, b.length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes an array of bytes to the output stream.
|
||||
*/
|
||||
public static void writeBytes(OutputStream os, byte[] b, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
os.write(b, off, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a slash at the end, if it does not have one yet
|
||||
*/
|
||||
public static byte[] toDirectoryPath(byte[] dir) {
|
||||
if (dir.length != 0 && dir[dir.length - 1] != '/') {
|
||||
dir = Arrays.copyOf(dir, dir.length + 1);
|
||||
dir[dir.length - 1] = '/';
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts DOS time to Java time (number of milliseconds since epoch).
|
||||
*/
|
||||
public static long dosToJavaTime(long dtime) {
|
||||
Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
|
||||
(int)(((dtime >> 21) & 0x0f) - 1),
|
||||
(int)((dtime >> 16) & 0x1f),
|
||||
(int)((dtime >> 11) & 0x1f),
|
||||
(int)((dtime >> 5) & 0x3f),
|
||||
(int)((dtime << 1) & 0x3e));
|
||||
return d.getTime();
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts Java time to DOS time.
|
||||
*/
|
||||
public static long javaToDosTime(long time) {
|
||||
Date d = new Date(time);
|
||||
int year = d.getYear() + 1900;
|
||||
if (year < 1980) {
|
||||
return (1 << 21) | (1 << 16);
|
||||
}
|
||||
return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
|
||||
d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
|
||||
d.getSeconds() >> 1;
|
||||
}
|
||||
|
||||
|
||||
// used to adjust values between Windows and java epoch
|
||||
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
|
||||
public static final long winToJavaTime(long wtime) {
|
||||
return TimeUnit.MILLISECONDS.convert(
|
||||
wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS);
|
||||
}
|
||||
|
||||
public static final long javaToWinTime(long time) {
|
||||
return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS)
|
||||
- WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
|
||||
}
|
||||
|
||||
public static final long unixToJavaTime(long utime) {
|
||||
return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public static final long javaToUnixTime(long time) {
|
||||
return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private static final String regexMetaChars = ".^$+{[]|()";
|
||||
private static final String globMetaChars = "\\*?[{";
|
||||
private static boolean isRegexMeta(char c) {
|
||||
return regexMetaChars.indexOf(c) != -1;
|
||||
}
|
||||
private static boolean isGlobMeta(char c) {
|
||||
return globMetaChars.indexOf(c) != -1;
|
||||
}
|
||||
private static char EOL = 0; //TBD
|
||||
private static char next(String glob, int i) {
|
||||
if (i < glob.length()) {
|
||||
return glob.charAt(i);
|
||||
}
|
||||
return EOL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a regex pattern from the given glob expression.
|
||||
*
|
||||
* @throws PatternSyntaxException
|
||||
*/
|
||||
public static String toRegexPattern(String globPattern) {
|
||||
boolean inGroup = false;
|
||||
StringBuilder regex = new StringBuilder("^");
|
||||
|
||||
int i = 0;
|
||||
while (i < globPattern.length()) {
|
||||
char c = globPattern.charAt(i++);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
// escape special characters
|
||||
if (i == globPattern.length()) {
|
||||
throw new PatternSyntaxException("No character to escape",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
char next = globPattern.charAt(i++);
|
||||
if (isGlobMeta(next) || isRegexMeta(next)) {
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(next);
|
||||
break;
|
||||
case '/':
|
||||
regex.append(c);
|
||||
break;
|
||||
case '[':
|
||||
// don't match name separator in class
|
||||
regex.append("[[^/]&&[");
|
||||
if (next(globPattern, i) == '^') {
|
||||
// escape the regex negation char if it appears
|
||||
regex.append("\\^");
|
||||
i++;
|
||||
} else {
|
||||
// negation
|
||||
if (next(globPattern, i) == '!') {
|
||||
regex.append('^');
|
||||
i++;
|
||||
}
|
||||
// hyphen allowed at start
|
||||
if (next(globPattern, i) == '-') {
|
||||
regex.append('-');
|
||||
i++;
|
||||
}
|
||||
}
|
||||
boolean hasRangeStart = false;
|
||||
char last = 0;
|
||||
while (i < globPattern.length()) {
|
||||
c = globPattern.charAt(i++);
|
||||
if (c == ']') {
|
||||
break;
|
||||
}
|
||||
if (c == '/') {
|
||||
throw new PatternSyntaxException("Explicit 'name separator' in class",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
// TBD: how to specify ']' in a class?
|
||||
if (c == '\\' || c == '[' ||
|
||||
c == '&' && next(globPattern, i) == '&') {
|
||||
// escape '\', '[' or "&&" for regex class
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(c);
|
||||
|
||||
if (c == '-') {
|
||||
if (!hasRangeStart) {
|
||||
throw new PatternSyntaxException("Invalid range",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
if ((c = next(globPattern, i++)) == EOL || c == ']') {
|
||||
break;
|
||||
}
|
||||
if (c < last) {
|
||||
throw new PatternSyntaxException("Invalid range",
|
||||
globPattern, i - 3);
|
||||
}
|
||||
regex.append(c);
|
||||
hasRangeStart = false;
|
||||
} else {
|
||||
hasRangeStart = true;
|
||||
last = c;
|
||||
}
|
||||
}
|
||||
if (c != ']') {
|
||||
throw new PatternSyntaxException("Missing ']", globPattern, i - 1);
|
||||
}
|
||||
regex.append("]]");
|
||||
break;
|
||||
case '{':
|
||||
if (inGroup) {
|
||||
throw new PatternSyntaxException("Cannot nest groups",
|
||||
globPattern, i - 1);
|
||||
}
|
||||
regex.append("(?:(?:");
|
||||
inGroup = true;
|
||||
break;
|
||||
case '}':
|
||||
if (inGroup) {
|
||||
regex.append("))");
|
||||
inGroup = false;
|
||||
} else {
|
||||
regex.append('}');
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (inGroup) {
|
||||
regex.append(")|(?:");
|
||||
} else {
|
||||
regex.append(',');
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
if (next(globPattern, i) == '*') {
|
||||
// crosses directory boundaries
|
||||
regex.append(".*");
|
||||
i++;
|
||||
} else {
|
||||
// within directory boundary
|
||||
regex.append("[^/]*");
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
regex.append("[^/]");
|
||||
break;
|
||||
default:
|
||||
if (isRegexMeta(c)) {
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(c);
|
||||
}
|
||||
}
|
||||
if (inGroup) {
|
||||
throw new PatternSyntaxException("Missing '}", globPattern, i - 1);
|
||||
}
|
||||
return regex.append('$').toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of Oracle nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,2 @@
|
|||
com.github.marschall.com.sun.nio.zipfs.ZipFileSystemProvider
|
||||
|
|
@ -21,3 +21,4 @@ include ':FCLCore'
|
|||
include ':FCLauncher'
|
||||
include ':FCLLibrary'
|
||||
include ':LWJGL'
|
||||
include ':ZipFileSystem'
|
||||
|
|
Loading…
Reference in New Issue