/*
* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
* Original author: Edmund Wagner
* Creation date: 26.06.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.io;
import gnu.crypto.cipher.Rijndael;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.Queue;
import de.innosystec.unrar.rarfile.FileHeader;
/**
* DOCUMENT ME
*
* @author $LastChangedBy$
* @version $LastChangedRevision$
*/
public class ReadOnlyAccessInputStream extends InputStream {
private IReadOnlyAccess file;
private long curPos;
protected final long startPos;
private final long endPos;
private FileHeader hd;
private Queue<Byte> data = new LinkedList<Byte>();
private Rijndael rin = new Rijndael();
private byte[] AESKey = new byte[16];
private byte[] AESInit = new byte[16];
public ReadOnlyAccessInputStream(IReadOnlyAccess file, FileHeader hd, long startPos,
long endPos) throws IOException {
super();
this.file = file;
this.hd = hd;
if(hd.isEncrypted()){
file.initAES(rin, hd.getSalt(), AESInit, AESKey);
}
this.startPos = startPos;
curPos = startPos;
this.endPos = endPos;
file.setPosition(curPos);
}
@Override
public int read() throws IOException {
if (curPos == endPos) {
return -1;
}
else {
int b = 0;
if(hd.isEncrypted()){
byte[] bx = new byte[1];
this.deRead(bx, 0, bx.length);
b = bx[0];
}else{
b = file.read();
}
//file.
curPos++;
return b;
}
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (len == 0) {
return 0;
}
if (curPos == endPos) {
return -1;
}
int bytesRead = 0;
if(hd.isEncrypted()){
//byte[] bx = new byte[(int)Math.min(len, endPos - curPos)];
bytesRead = this.deRead(b, off, (int)Math.min(len, endPos - curPos));
}else{
bytesRead = file.read(b, off,
(int)Math.min(len, endPos - curPos));
}
curPos += bytesRead;
return bytesRead;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
//
// public void close() throws IOException {
// file.close();
// }
private int deRead(byte[] b, int off, int len) throws IOException {
int cs = data.size();
int sizeToRead = len - cs;
if (sizeToRead > 0) {
int alignedSize = sizeToRead + ((~sizeToRead + 1) & 0xf);
for(int i=0;i<alignedSize/16;i++){
//long ax = System.currentTimeMillis();
byte[] tr = new byte[16];
file.readFully(tr, 0, 16);
/**
* decrypt & add to data list
*
*/
byte[] out = new byte[16];
this.rin.decryptBlock(tr, 0, out, 0);
for(int j=0;j<out.length;j++){
this.data.add((byte)(out[j]^AESInit[j%16])); //32:114, 33:101
}
for(int j=0;j<AESInit.length;j++){
AESInit[j] = tr[j];
}
//System.out.println(System.currentTimeMillis()-ax);
}
}
for (int i = 0; i < len; i++) {
b[off+i] = data.poll();
}
return len;
}
}