250 lines
6.9 KiB
Java
250 lines
6.9 KiB
Java
/*
|
|
* Copyright 2012 dorkbox, llc
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package dorkbox.cabParser.structure;
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.nio.charset.Charset;
|
|
import java.util.Date;
|
|
|
|
import dorkbox.cabParser.CabException;
|
|
import dorkbox.cabParser.CorruptCabException;
|
|
import dorkbox.bytes.LittleEndian;
|
|
|
|
public final class CabFileEntry {
|
|
public static final Charset US_ASCII = Charset.forName("US-ASCII");
|
|
|
|
/** file is read-only (in HEX) */
|
|
static final int READONLY = 0x01;
|
|
|
|
/** file is hidden (in HEX) */
|
|
static final int HIDDEN = 0x02;
|
|
|
|
/** file is a system file (in HEX) */
|
|
static final int SYSTEM = 0x04;
|
|
|
|
/** file modified since last backup (in HEX) */
|
|
static final int ARCHIVE = 0x20;
|
|
|
|
/** szName[] contains UTF (in HEX) */
|
|
static final int NAME_IS_UTF = 0x80;
|
|
|
|
/** uncompressed size of this file in bytes , 4bytes */
|
|
public long cbFile;
|
|
/** uncompressed offset of this file in the folder , 4bytes */
|
|
public long offFolderStart;
|
|
/** index into the CFFOLDER area , 2bytes */
|
|
public int iFolder;
|
|
/** time/date stamp for this file , 2bytes */
|
|
public Date date = new Date();
|
|
/** attribute flags for this file , 2bytes */
|
|
public int attribs;
|
|
|
|
/** name of this file , 1*n bytes */
|
|
public String szName;
|
|
|
|
private Object objectOrSomething;
|
|
|
|
public void read(InputStream input) throws IOException, CabException {
|
|
byte[] arrayOfByte = new byte[256];
|
|
|
|
this.cbFile = LittleEndian.UInt_.from(input).longValue();
|
|
this.offFolderStart = LittleEndian.UInt_.from(input).longValue();
|
|
this.iFolder = LittleEndian.UShort_.from(input).intValue();
|
|
|
|
int timeA = LittleEndian.UShort_.from(input).intValue();
|
|
int timeB = LittleEndian.UShort_.from(input).intValue();
|
|
this.date = getDate(timeA, timeB);
|
|
|
|
this.attribs = LittleEndian.UShort_.from(input).intValue();
|
|
|
|
int i = 0;
|
|
|
|
for (i = 0; i < arrayOfByte.length; i++) {
|
|
int m = input.read();
|
|
if (m == -1) {
|
|
throw new CorruptCabException("EOF reading cffile");
|
|
}
|
|
arrayOfByte[i] = (byte) m;
|
|
if (m == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= arrayOfByte.length) {
|
|
throw new CorruptCabException("cffile filename not null terminated");
|
|
}
|
|
|
|
if ((this.attribs & NAME_IS_UTF) == NAME_IS_UTF) {
|
|
this.szName = readUtfString(arrayOfByte);
|
|
|
|
if (this.szName == null) {
|
|
throw new CorruptCabException("invalid utf8 code");
|
|
}
|
|
} else {
|
|
this.szName = new String(arrayOfByte, 0, i, US_ASCII).trim();
|
|
}
|
|
}
|
|
|
|
public boolean isReadOnly() {
|
|
return (this.attribs & READONLY) != 0;
|
|
}
|
|
|
|
public void setReadOnly(boolean bool) {
|
|
if (bool) {
|
|
this.attribs |= 1;
|
|
return;
|
|
}
|
|
|
|
this.attribs &= -2;
|
|
}
|
|
|
|
public boolean isHidden() {
|
|
return (this.attribs & HIDDEN) != 0;
|
|
}
|
|
|
|
public void setHidden(boolean bool) {
|
|
if (bool) {
|
|
this.attribs |= 2;
|
|
return;
|
|
}
|
|
|
|
this.attribs &= -3;
|
|
}
|
|
|
|
public boolean isSystem() {
|
|
return (this.attribs & SYSTEM) != 0;
|
|
}
|
|
|
|
public void setSystem(boolean bool) {
|
|
if (bool) {
|
|
this.attribs |= 4;
|
|
return;
|
|
}
|
|
this.attribs &= -5;
|
|
}
|
|
|
|
public boolean isArchive() {
|
|
return (this.attribs & ARCHIVE) != 0;
|
|
}
|
|
|
|
public void setArchive(boolean bool) {
|
|
if (bool) {
|
|
this.attribs |= 32;
|
|
return;
|
|
}
|
|
this.attribs &= -33;
|
|
}
|
|
|
|
public String getName() {
|
|
return this.szName;
|
|
}
|
|
|
|
public long getSize() {
|
|
return this.cbFile;
|
|
}
|
|
|
|
public void setName(String name) {
|
|
this.szName = name;
|
|
}
|
|
|
|
public void setSize(long size) {
|
|
this.cbFile = (int) size;
|
|
}
|
|
|
|
public Date getDate() {
|
|
return this.date;
|
|
}
|
|
|
|
public void setDate(Date paramDate) {
|
|
this.date = paramDate;
|
|
}
|
|
|
|
@SuppressWarnings("deprecation")
|
|
private Date getDate(int dateInfo, int timeInfo) {
|
|
int i = dateInfo & 0x1F;
|
|
int j = (dateInfo >>> 5) - 1 & 0xF;
|
|
int k = (dateInfo >>> 9) + 80;
|
|
int m = (timeInfo & 0x1F) << 1;
|
|
int n = timeInfo >>> 5 & 0x3F;
|
|
int i1 = timeInfo >>> 11 & 0x1F;
|
|
return new Date(k, j, i, i1, n, m);
|
|
}
|
|
|
|
public Object getApplicationData() {
|
|
return this.objectOrSomething;
|
|
}
|
|
|
|
public void setApplicationData(Object obj) {
|
|
this.objectOrSomething = obj;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return this.szName;
|
|
}
|
|
|
|
private static String readUtfString(byte[] stringBytes) {
|
|
int j = 0;
|
|
int stringSize = 0;
|
|
int k = 0;
|
|
|
|
// count the size of the string
|
|
for (stringSize = 0; stringBytes[stringSize] != 0; stringSize++) {}
|
|
|
|
char[] stringChars = new char[stringSize];
|
|
for (k = 0; stringBytes[j] != 0; k++) {
|
|
int m = (char) (stringBytes[j++] & 0xFF);
|
|
|
|
if (m < 128) {
|
|
stringChars[k] = (char) m;
|
|
} else {
|
|
if (m < 192) {
|
|
return null;
|
|
}
|
|
|
|
if (m < 224) {
|
|
stringChars[k] = (char) ((m & 0x1F) << 6);
|
|
m = (char) (stringBytes[j++] & 0xFF);
|
|
if (m < 128 || m > 191) {
|
|
return null;
|
|
}
|
|
stringChars[k] = (char) (stringChars[k] | (char) (m & 0x3F));
|
|
}
|
|
else if (m < 240) {
|
|
stringChars[k] = (char) ((m & 0xF) << 12);
|
|
m = (char) (stringBytes[j++] & 0xFF);
|
|
if (m < 128 || m > 191) {
|
|
return null;
|
|
}
|
|
|
|
stringChars[k] = (char) (stringChars[k] | (char) ((m & 0x3F) << 6));
|
|
m = (char) (stringBytes[j++] & 0xFF);
|
|
if (m < 128 || m > 191) {
|
|
return null;
|
|
}
|
|
stringChars[k] = (char) (stringChars[k] | (char) (m & 0x3F));
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
return new String(stringChars, 0, k);
|
|
}
|
|
}
|
|
|