unrar/Archive.java

/*
* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
* Original author: Edmund Wagner
* Creation date: 22.05.2007
*
* Source: $HeadURL$
* Last changed: $LastChangedDate$
*
* the unrar licence applies to all junrar source and binary distributions
* you are not allowed to use this source to re-create the RAR compression
* algorithm
*
* Here some html entities which can be used for escaping javadoc tags:
* "&": "&" or "&"
* "<": "<" or "<"
* ">": ">" or ">"
* "@": "@"
*/
package de.innosystec.unrar;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.exception.RarException.RarExceptionType;
import de.innosystec.unrar.io.IReadOnlyAccess;
import de.innosystec.unrar.io.ReadOnlyAccessFile;
import de.innosystec.unrar.rarfile.AVHeader;
import de.innosystec.unrar.rarfile.BaseBlock;
import de.innosystec.unrar.rarfile.BlockHeader;
import de.innosystec.unrar.rarfile.CommentHeader;
import de.innosystec.unrar.rarfile.EAHeader;
import de.innosystec.unrar.rarfile.EndArcHeader;
import de.innosystec.unrar.rarfile.FileHeader;
import de.innosystec.unrar.rarfile.MacInfoHeader;
import de.innosystec.unrar.rarfile.MainHeader;
import de.innosystec.unrar.rarfile.MarkHeader;
import de.innosystec.unrar.rarfile.ProtectHeader;
import de.innosystec.unrar.rarfile.SignHeader;
import de.innosystec.unrar.rarfile.SubBlockHeader;
import de.innosystec.unrar.rarfile.UnixOwnersHeader;
import de.innosystec.unrar.rarfile.UnrarHeadertype;
import de.innosystec.unrar.unpack.ComprDataIO;
import de.innosystec.unrar.unpack.Unpack;

/**
* DOCUMENT ME
*
* @author $LastChangedBy$
* @version $LastChangedRevision$
*/
public class Archive implements Closeable {

private static Logger logger = Logger.getLogger(Archive.class.getName());

private File file;

private IReadOnlyAccess rof;

private final UnrarCallback unrarCallback;

private final ComprDataIO dataIO;

private final List<BaseBlock> headers = new ArrayList<BaseBlock>();

private MarkHeader markHead = null;

private MainHeader newMhd = null;

private EndArcHeader endHeader = null;

private Unpack unpack;

/** Archive data CRC. */
private long arcDataCRC = 0xffffffff;

private int currentHeaderIndex;

private boolean encrypted = false;

private int sfxSize = 0;

/** Size of packed data in current file. */
private long totalPackedSize = 0L;

/** Number of bytes of compressed data read from current file. */
private long totalPackedRead = 0L;

public Archive(File file) throws RarException, IOException {
this(file, null);
}

/**
* create a new archive object using the given file
* @param file the file to extract
* @throws RarException
*/
public Archive(File file, UnrarCallback unrarCallback)
throws RarException, IOException {
setFile(file);
this.unrarCallback = unrarCallback;
dataIO = new ComprDataIO(this);
}

public File getFile() {
return file;
}

void setFile(File file) throws IOException {
this.file = file;
totalPackedSize = 0L;
totalPackedRead = 0L;
close();
rof = new ReadOnlyAccessFile(file);
try {
readHeaders();
}
catch (Exception e) {
logger.log(Level.WARNING,
"exception in archive constructor maybe file is encrypted " +
"or currupt", e);
//ignore exceptions to allow exraction of working files in
//corrupt archive
}
// Calculate size of packed data
for (BaseBlock block : headers) {
if (block.getHeaderType() == UnrarHeadertype.FileHeader) {
totalPackedSize += ((FileHeader)block).getFullPackSize();
}
}
if (unrarCallback != null) {
unrarCallback.volumeProgressChanged(totalPackedRead,
totalPackedSize);
}
}

public void bytesReadRead(int count) {
if (count > 0) {
totalPackedRead += count;
if (unrarCallback != null) {
unrarCallback.volumeProgressChanged(totalPackedRead,
totalPackedSize);
}
}
}

public IReadOnlyAccess getRof() {
return rof;
}

/**
* @return returns all file headers of the archive
*/
public List<FileHeader> getFileHeaders(){
List<FileHeader> list = new ArrayList<FileHeader>();
for (BaseBlock block: headers) {
if(block.getHeaderType().equals(UnrarHeadertype.FileHeader)){
list.add((FileHeader)block);
}
}
return list;
}

public FileHeader nextFileHeader() {
int n = headers.size();
while (currentHeaderIndex < n) {
BaseBlock block = headers.get(currentHeaderIndex++);
if (block.getHeaderType() == UnrarHeadertype.FileHeader) {
return (FileHeader)block;
}
}
return null;
}

public UnrarCallback getUnrarCallback() {
return unrarCallback;
}

/**
*
* @return whether the archive is encrypted
*/
public boolean isEncrypted() {
if(newMhd!=null){
return newMhd.isEncrypted();
}else{
throw new NullPointerException("mainheader is null");
}
}

/**
* Read the headers of the archive
* @throws RarException
*/
private void readHeaders() throws IOException, RarException{
markHead = null;
newMhd = null;
endHeader = null;
headers.clear();
currentHeaderIndex = 0;
int toRead = 0;

long fileLength = this.file.length();

while(true){
int size = 0;
long newpos = 0;
byte[] baseBlockBuffer =new byte[BaseBlock.BaseBlockSize];

long position = rof.getPosition();

// Weird, but is trying to read beyond the end of the file
if (position >= fileLength) {
break;
}

// logger.info("\n--------reading header--------");
size = rof.readFully(baseBlockBuffer, BaseBlock.BaseBlockSize);
if (size == 0){
break;
}
BaseBlock block = new BaseBlock(baseBlockBuffer);

block.setPositionInFile(position);


switch(block.getHeaderType()) {

case MarkHeader:
markHead = new MarkHeader(block);
if (!markHead.isSignature()) {
throw new RarException(
RarException.RarExceptionType.badRarArchive);
}
headers.add(markHead);
// markHead.print();
break;

case MainHeader:
int mainHeaderSize = 0;
toRead = block.hasEncryptVersion() ?
MainHeader.mainHeaderSizeWithEnc :
MainHeader.mainHeaderSize;
byte[] mainbuff = new byte[toRead];
mainHeaderSize = rof.readFully(mainbuff, toRead);
MainHeader mainhead =new MainHeader(block,mainbuff);
headers.add(mainhead);
this.newMhd = mainhead;
if(newMhd.isEncrypted()){
throw new RarException(
RarExceptionType.rarEncryptedException);
}
// mainhead.print();
break;

case SignHeader:
int signHeaderSize = 0;
toRead = SignHeader.signHeaderSize;
byte[] signBuff = new byte[toRead];
signHeaderSize = rof.readFully(signBuff, toRead);
SignHeader signHead = new SignHeader(block,signBuff);
headers.add(signHead);
// logger.info("HeaderType: SignHeader");

break;

case AvHeader:
int avHeaderSize = 0;
toRead = AVHeader.avHeaderSize;
byte[] avBuff = new byte[toRead];
avHeaderSize = rof.readFully(avBuff, toRead);
AVHeader avHead = new AVHeader(block,avBuff);
headers.add(avHead);
// logger.info("headertype: AVHeader");
break;

case CommHeader:
int commHeaderSize = 0;
toRead = CommentHeader.commentHeaderSize;
byte[] commBuff = new byte[toRead];
commHeaderSize = rof.readFully(commBuff, toRead);
CommentHeader commHead = new CommentHeader(block,commBuff);
headers.add(commHead);
// logger.info("method: "+commHead.getUnpMethod()+"; 0x"+
// Integer.toHexString(commHead.getUnpMethod()));
newpos = commHead.getPositionInFile() +
commHead.getHeaderSize();
rof.setPosition(newpos);

break;
case EndArcHeader:

toRead = 0;
if (block.hasArchiveDataCRC()) {
toRead += EndArcHeader.endArcArchiveDataCrcSize;
}
if (block.hasVolumeNumber()) {
toRead += EndArcHeader.endArcVolumeNumberSize;
}
EndArcHeader endArcHead;
if(toRead > 0){
int endArcHeaderSize = 0;
byte[] endArchBuff = new byte[toRead];
endArcHeaderSize = rof.readFully(endArchBuff, toRead);
endArcHead = new EndArcHeader(block,endArchBuff);
// logger.info("HeaderType: endarch\ndatacrc:"+
// endArcHead.getArchiveDataCRC());
}else{
// logger.info("HeaderType: endarch - no Data");
endArcHead = new EndArcHeader(block,null);
}
headers.add(endArcHead);
this.endHeader = endArcHead;
// logger.info("\n--------end header--------");
return;

default:
byte[] blockHeaderBuffer =
new byte[BlockHeader.blockHeaderSize];
int bhsize = rof.readFully(blockHeaderBuffer,
BlockHeader.blockHeaderSize);
BlockHeader blockHead = new BlockHeader(block,
blockHeaderBuffer);

switch(blockHead.getHeaderType()) {
case NewSubHeader:
case FileHeader:
toRead = blockHead.getHeaderSize()-
BlockHeader.BaseBlockSize-
BlockHeader.blockHeaderSize;
byte[] fileHeaderBuffer = new byte[toRead];
int fhsize = rof.readFully(fileHeaderBuffer,
toRead);

FileHeader fh = new FileHeader(blockHead,
fileHeaderBuffer);
// if (DEBUG) {
// fh.print();
// }
headers.add(fh);
newpos = fh.getPositionInFile() +
fh.getHeaderSize() + fh.getFullPackSize();
rof.setPosition(newpos);
break;

case ProtectHeader:
toRead = blockHead.getHeaderSize()-
BlockHeader.BaseBlockSize-
BlockHeader.blockHeaderSize;
byte[] protectHeaderBuffer = new byte[toRead];
int phsize = rof.readFully(protectHeaderBuffer,
toRead);
ProtectHeader ph = new ProtectHeader(blockHead,
protectHeaderBuffer);

// logger.info("totalblocks"+ph.getTotalBlocks());
newpos = ph.getPositionInFile() +
ph.getHeaderSize();
rof.setPosition(newpos);
break;

case SubHeader:
{
byte[] subHeadbuffer = new byte[SubBlockHeader.SubBlockHeaderSize];
int subheadersize = rof.readFully(subHeadbuffer, SubBlockHeader.SubBlockHeaderSize);
SubBlockHeader subHead = new SubBlockHeader(blockHead,subHeadbuffer);
subHead.print();
switch (subHead.getSubType()) {
case MAC_HEAD:
{
byte[] macHeaderbuffer = new byte[MacInfoHeader.MacInfoHeaderSize];
int macheadersize = rof.readFully(macHeaderbuffer, MacInfoHeader.MacInfoHeaderSize);
MacInfoHeader macHeader = new MacInfoHeader(subHead,macHeaderbuffer);
macHeader.print();
headers.add(macHeader);

break;
}
//TODO implement other subheaders
case BEEA_HEAD:
break;
case EA_HEAD:
{
byte[] eaHeaderBuffer = new byte[EAHeader.EAHeaderSize];
int eaheadersize = rof.readFully(eaHeaderBuffer, EAHeader.EAHeaderSize);
EAHeader eaHeader = new EAHeader(subHead,eaHeaderBuffer);
eaHeader.print();
headers.add(eaHeader);

break;
}
case NTACL_HEAD:
break;
case STREAM_HEAD:
break;
case UO_HEAD:
toRead = subHead.getHeaderSize();
toRead -= BaseBlock.BaseBlockSize;
toRead -= BlockHeader.blockHeaderSize;
toRead -= SubBlockHeader.SubBlockHeaderSize;
byte[] uoHeaderBuffer = new byte[toRead];
int uoHeaderSize = rof.readFully(uoHeaderBuffer, toRead);
UnixOwnersHeader uoHeader = new UnixOwnersHeader(subHead,uoHeaderBuffer);
uoHeader.print();
headers.add(uoHeader);
break;
default:
break;
}

break;
}
default:
logger.warning("Unknown Header");
throw new RarException(
RarExceptionType.notRarArchive);

}
}
// logger.info("\n--------end header--------");
}
}

/**
* Extract the file specified by the given header and write it
* to the supplied output stream
*
* @param header the header to be extracted
* @param os the outputstream
* @throws RarException
*/
public void extractFile(FileHeader hd, OutputStream os)
throws RarException{
if (!headers.contains(hd)){
throw new RarException(RarExceptionType.headerNotInArchive);
}
try {
doExtractFile(hd, os);
}
catch (Exception e) {
if (e instanceof RarException){
throw (RarException)e;
} else{
throw new RarException(e);
}
}
}

private void doExtractFile(FileHeader hd, OutputStream os)
throws RarException, IOException {
dataIO.init(os);
dataIO.init(hd);
dataIO.setUnpFileCRC(this.isOldFormat()?0:0xffFFffFF);
if(unpack==null){
unpack = new Unpack(dataIO);
}
if(!hd.isSolid()){
unpack.init(null);
}
unpack.setDestSize(hd.getFullUnpackSize());
try {
unpack.doUnpack(hd.getUnpVersion(), hd.isSolid());
// Verify file CRC
hd = dataIO.getSubHeader();
long actualCRC = hd.isSplitAfter() ?
~dataIO.getPackedCRC() : ~dataIO.getUnpFileCRC();
int expectedCRC = hd.getFileCRC();
if(actualCRC != expectedCRC){
throw new RarException(RarExceptionType.crcError);
}
// if (!hd.isSplitAfter()) {
// // Verify file CRC
// if(~dataIO.getUnpFileCRC() != hd.getFileCRC()){
// throw new RarException(RarExceptionType.crcError);
// }
// }
}
catch (Exception e) {
unpack.cleanUp();
if (e instanceof RarException){
//throw new RarException((RarException)e);
throw (RarException)e;
}
else{
throw new RarException(e);
}
}
}

/**
* @return returns the main header of this archive
*/
public MainHeader getMainHeader() {
return newMhd;
}

/**
* @return whether the archive is old format
*/
public boolean isOldFormat() {
return markHead.isOldFormat();
}

/** Close the underlying compressed file. */
public void close() throws IOException {
if (rof != null) {
rof.close();
rof = null;
}
}
}

URL:[url]http://svn.atlassian.com/svn/public/atlassian/vendor/java-unrar/trunk/src/main/java/de/innosystec/unrar/Archive.java[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值