You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
5.8 KiB

/*
* 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.EOFException;
import java.io.IOException;
import java.io.InputStream;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CabStreamSaver;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.util.bytes.LittleEndian;
public final class CabHeader implements CabConstants {
/** reserved , 4 bytes */
public long reserved1;
/** size of this cabinet file in bytes , 4 bytes */
public long cbCabinet;
/** reserved, 4 bytes */
public long reserved2;
/** offset of the first CFFILE entry , 4 bytes */
public long coffFiles;
/** reserved, 4 bytes*/
public long reserved3;
/** cabinet file format version, minor/major , 1 bytes*2 */
public int version;
/** number of CFFOLDER entries in this cabinet , 2 bytes */
public int cFolders;
/** number of CFFILE entries in this cabinet , 2 bytes */
public int cFiles;
/** cabinet file option indicators , 2 bytes */
public int flags;
/** must be the same for all cabinets in a set , 2 bytes */
public int setID;
/** number of this cabinet file in a set , 2 bytes */
public int iCabinet;
/** (optional) size of per-cabinet reserved area , 2 bytes */
public int cbCFHeader = 0;
/** (optional) size of per-folder reserved area , 1 bytes */
public int cbCFFolder = 0;
/** (optional) size of per-datablock reserved area , 1 bytes */
public int cbCFData = 0;
/** (optional) per-cabinet reserved area , 1*n bytes */
//final short abReserve[];
/** (optional) name of previous cabinet file , 1*n bytes */
//final String szCabinetPrev;
/** (optional) name of previous disk , 1*n bytes */
//final String szDiskPrev;
/** (optional) name of next cabinet file , 1*n bytes */
//final String szCabinetNext;
/** (optional) name of next disk , 1*n bytes */
//final String szDiskNext;
private CabStreamSaver decoder;
public CabHeader(CabStreamSaver paramCabDecoderInterface) {
this.decoder = paramCabDecoderInterface;
}
public void read(InputStream input) throws IOException, CabException {
int i = input.read();
int j = input.read();
int k = input.read();
int m = input.read();
// Contains the characters "M", "S", "C", and "F" (bytes 0x4D, 0x53, 0x43, 0x46). This field is used to ensure that the file is a cabinet (.cab) file.
if (i != 77 || j != 83 || k != 67 || m != 70) {
throw new CorruptCabException("Missing header signature");
}
this.reserved1 = LittleEndian.UInt_.from(input).longValue(); // must be 0
this.cbCabinet = LittleEndian.UInt_.from(input).longValue(); // Specifies the total size of the cabinet file, in bytes.
this.reserved2 = LittleEndian.UInt_.from(input).longValue(); // must be 0
this.coffFiles = LittleEndian.UInt_.from(input).longValue(); // Specifies the absolute file offset, in bytes, of the first CFFILE field entry.
this.reserved3 = LittleEndian.UInt_.from(input).longValue(); // must be 0
// Currently, versionMajor = 1 and versionMinor = 3
this.version = LittleEndian.UShort_.from(input).intValue();
this.cFolders = LittleEndian.UShort_.from(input).intValue();
this.cFiles = LittleEndian.UShort_.from(input).intValue();
this.flags = LittleEndian.UShort_.from(input).intValue();
this.setID = LittleEndian.UShort_.from(input).intValue();
this.iCabinet = LittleEndian.UShort_.from(input).intValue();
if ((this.flags & FLAG_RESERVE_PRESENT) == FLAG_RESERVE_PRESENT) {
this.cbCFHeader = LittleEndian.UShort_.from(input).intValue();
this.cbCFFolder = input.read();
this.cbCFData = input.read();
}
if ((this.flags & FLAG_PREV_CABINET) == FLAG_PREV_CABINET ||
(this.flags & FLAG_NEXT_CABINET) == FLAG_NEXT_CABINET) {
throw new CabException("Spanned cabinets not supported");
}
// not supported
// if (prevCabinet()) {
// szCabinetPrev = bytes.readString(false);
// szDiskPrev = bytes.readString(false);
// } else {
// szCabinetPrev = null;
// szDiskPrev = null;
// }
//
// if (nextCabinet()) {
// szCabinetNext = bytes.readString(false);
// szDiskNext = bytes.readString(false);
// } else {
// szCabinetNext = null;
// szDiskNext = null;
// }
if (this.cbCFHeader != 0) {
if (this.decoder.saveReservedAreaData(null, this.cbCFHeader) == true) {
byte[] data = new byte[this.cbCFHeader];
if (this.cbCFHeader != 0) {
int readTotal = 0;
while (readTotal < this.cbCFHeader) {
int read = input.read(data, readTotal, this.cbCFHeader - readTotal);
if (read < 0) {
throw new EOFException();
}
readTotal += read;
}
}
this.decoder.saveReservedAreaData(data, this.cbCFHeader);
return;
}
input.skip(this.cbCFHeader);
}
}
}