Package de.innosystec.unrar.unpack

Source Code of de.innosystec.unrar.unpack.Unpack

/*
* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
* Original author: Edmund Wagner
* Creation date: 31.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 "&"
* "<":  "&#060;" or "&lt;"
* ">":  "&#062;" or "&gt;"
* "@":  "&#064;"
*/
package de.innosystec.unrar.unpack;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.unpack.decode.Compress;
import de.innosystec.unrar.unpack.ppm.BlockTypes;
import de.innosystec.unrar.unpack.ppm.ModelPPM;
import de.innosystec.unrar.unpack.ppm.SubAllocator;
import de.innosystec.unrar.unpack.vm.BitInput;
import de.innosystec.unrar.unpack.vm.RarVM;
import de.innosystec.unrar.unpack.vm.VMPreparedProgram;

/**
* DOCUMENT ME
*
* @author $LastChangedBy$
* @version $LastChangedRevision$
*/
public final class Unpack extends Unpack20 {

    private final ModelPPM ppm = new ModelPPM();

    private int ppmEscChar;

    private RarVM rarVM = new RarVM();

    /* Filters code, one entry per filter */
    private List<UnpackFilter> filters = new ArrayList<UnpackFilter>();

    /* Filters stack, several entrances of same filter are possible */
    private List<UnpackFilter> prgStack = new ArrayList<UnpackFilter>();

    /*
     * lengths of preceding blocks, one length per filter. Used to reduce size
     * required to write block length if lengths are repeating
     */
    private List<Integer> oldFilterLengths = new ArrayList<Integer>();

    private int lastFilter;

    private boolean tablesRead;

    private byte[] unpOldTable = new byte[Compress.HUFF_TABLE_SIZE];

    private BlockTypes unpBlockType;

    private boolean externalWindow;

    private long writtenFileSize;

    private boolean fileExtracted;

    private boolean ppmError;

    private int prevLowDist;

    private int lowDistRepCount;

    public static int[] DBitLengthCounts = { 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
      2, 2, 2, 2, 2, 14, 0, 12 };

    public Unpack(ComprDataIO DataIO) {
  unpIO = DataIO;
  window = null;
  externalWindow = false;
  suspended = false;
  unpAllBuf = false;
  unpSomeRead = false;
    }

    public void init(byte[] window) {
  if (window == null) {
      this.window = new byte[Compress.MAXWINSIZE];
  } else {
      this.window = window;
      externalWindow = true;
  }
  inAddr = 0;
  unpInitData(false);
    }

    public void doUnpack(int method, boolean solid) throws IOException,
      RarException {
  if (unpIO.getSubHeader().getUnpMethod() == 0x30) {
      unstoreFile();
  }
  switch (method) {
  case 15: // rar 1.5 compression
      unpack15(solid);
      break;
  case 20: // rar 2.x compression
  case 26: // files larger than 2GB
      unpack20(solid);
      break;
  case 29: // rar 3.x compression
  case 36: // alternative hash
      unpack29(solid);
      break;
  }
    }

    private void unstoreFile() throws IOException, RarException {
  byte[] buffer = new byte[0x10000];
  while (true) {
      int code = unpIO.unpRead(buffer, 0, (int) Math.min(buffer.length,
        destUnpSize));
      if (code == 0 || code == -1)
    break;
      code = code < destUnpSize ? code : (int) destUnpSize;
      unpIO.unpWrite(buffer, 0, code);
      if (destUnpSize >= 0)
    destUnpSize -= code;
  }

    }

    private void unpack29(boolean solid) throws IOException, RarException {

  int[] DDecode = new int[Compress.DC];
  byte[] DBits = new byte[Compress.DC];

  int Bits;

  if (DDecode[1] == 0) {
      int Dist = 0, BitLength = 0, Slot = 0;
      for (int I = 0; I < DBitLengthCounts.length; I++, BitLength++) {
    int count = DBitLengthCounts[I];
    for (int J = 0; J < count; J++, Slot++, Dist += (1 << BitLength)) {
        DDecode[Slot] = Dist;
        DBits[Slot] = (byte) BitLength;
    }
      }
  }

  fileExtracted = true;

  if (!suspended) {
      unpInitData(solid);
      if (!unpReadBuf()) {
    return;
      }
      if ((!solid || !tablesRead) && !readTables()) {
    return;
      }
  }

  if (ppmError) {
      return;
  }

  while (true) {
      unpPtr &= Compress.MAXWINMASK;

      if (inAddr > readBorder) {
    if (!unpReadBuf()) {
        break;
    }
      }
      // System.out.println(((wrPtr - unpPtr) &
      // Compress.MAXWINMASK)+":"+wrPtr+":"+unpPtr);
      if (((wrPtr - unpPtr) & Compress.MAXWINMASK) < 260
        && wrPtr != unpPtr) {

    UnpWriteBuf();
    if (writtenFileSize > destUnpSize) {
        return;
    }
    if (suspended) {
        fileExtracted = false;
        return;
    }
      }
      if (unpBlockType == BlockTypes.BLOCK_PPM) {
    int Ch = ppm.decodeChar();
    if (Ch == -1) {
        ppmError = true;
        break;
    }
    if (Ch == ppmEscChar) {
        int NextCh = ppm.decodeChar();
        if (NextCh == 0) {
      if (!readTables()) {
          break;
      }
      continue;
        }
        if (NextCh == 2 || NextCh == -1) {
      break;
        }
        if (NextCh == 3) {
      if (!readVMCodePPM()) {
          break;
      }
      continue;
        }
        if (NextCh == 4) {
      int Distance = 0, Length = 0;
      boolean failed = false;
      for (int I = 0; I < 4 && !failed; I++) {
          int ch = ppm.decodeChar();
          if (ch == -1) {
        failed = true;
          } else {
        if (I == 3) {
            // Bug fixed
            Length = ch & 0xff;
        } else {
            // Bug fixed
            Distance = (Distance << 8) + (ch & 0xff);
        }
          }
      }
      if (failed) {
          break;
      }
      copyString(Length + 32, Distance + 2);
      continue;
        }
        if (NextCh == 5) {
      int Length = ppm.decodeChar();
      if (Length == -1) {
          break;
      }
      copyString(Length + 4, 1);
      continue;
        }
    }
    window[unpPtr++] = (byte) Ch;
    continue;
      }

      int Number = decodeNumber(LD);
      if (Number < 256) {
    window[unpPtr++] = (byte) Number;
    continue;
      }
      if (Number >= 271) {
    int Length = LDecode[Number -= 271] + 3;
    if ((Bits = LBits[Number]) > 0) {
        Length += getbits() >>> (16 - Bits);
        addbits(Bits);
    }

    int DistNumber = decodeNumber(DD);
    int Distance = DDecode[DistNumber] + 1;
    if ((Bits = DBits[DistNumber]) > 0) {
        if (DistNumber > 9) {
      if (Bits > 4) {
          Distance += ((getbits() >>> (20 - Bits)) << 4);
          addbits(Bits - 4);
      }
      if (lowDistRepCount > 0) {
          lowDistRepCount--;
          Distance += prevLowDist;
      } else {
          int LowDist = decodeNumber(LDD);
          if (LowDist == 16) {
        lowDistRepCount = Compress.LOW_DIST_REP_COUNT - 1;
        Distance += prevLowDist;
          } else {
        Distance += LowDist;
        prevLowDist = LowDist;
          }
      }
        } else {
      Distance += getbits() >>> (16 - Bits);
      addbits(Bits);
        }
    }

    if (Distance >= 0x2000) {
        Length++;
        if (Distance >= 0x40000L) {
      Length++;
        }
    }

    insertOldDist(Distance);
    insertLastMatch(Length, Distance);

    copyString(Length, Distance);
    continue;
      }
      if (Number == 256) {
    if (!readEndOfBlock()) {
        break;
    }
    continue;
      }
      if (Number == 257) {
    if (!readVMCode()) {
        break;
    }
    continue;
      }
      if (Number == 258) {
    if (lastLength != 0) {
        copyString(lastLength, lastDist);
    }
    continue;
      }
      if (Number < 263) {
    int DistNum = Number - 259;
    int Distance = oldDist[DistNum];
    for (int I = DistNum; I > 0; I--) {
        oldDist[I] = oldDist[I - 1];
    }
    oldDist[0] = Distance;

    int LengthNumber = decodeNumber(RD);
    int Length = LDecode[LengthNumber] + 2;
    if ((Bits = LBits[LengthNumber]) > 0) {
        Length += getbits() >>> (16 - Bits);
        addbits(Bits);
    }
    insertLastMatch(Length, Distance);
    copyString(Length, Distance);
    continue;
      }
      if (Number < 272) {
    int Distance = SDDecode[Number -= 263] + 1;
    if ((Bits = SDBits[Number]) > 0) {
        Distance += getbits() >>> (16 - Bits);
        addbits(Bits);
    }
    insertOldDist(Distance);
    insertLastMatch(2, Distance);
    copyString(2, Distance);
    continue;
      }
  }
  UnpWriteBuf();

    }

    private void UnpWriteBuf() throws IOException {
  int WrittenBorder = wrPtr;
  int WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK;
  for (int I = 0; I < prgStack.size(); I++) {
      UnpackFilter flt = prgStack.get(I);
      if (flt == null) {
    continue;
      }
      if (flt.isNextWindow()) {
    flt.setNextWindow(false);// ->NextWindow=false;
    continue;
      }
      int BlockStart = flt.getBlockStart();// ->BlockStart;
      int BlockLength = flt.getBlockLength();// ->BlockLength;
      if (((BlockStart - WrittenBorder) & Compress.MAXWINMASK) < WriteSize) {
    if (WrittenBorder != BlockStart) {
        UnpWriteArea(WrittenBorder, BlockStart);
        WrittenBorder = BlockStart;
        WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK;
    }
    if (BlockLength <= WriteSize) {
        int BlockEnd = (BlockStart + BlockLength)
          & Compress.MAXWINMASK;
        if (BlockStart < BlockEnd || BlockEnd == 0) {
      // VM.SetMemory(0,Window+BlockStart,BlockLength);
      rarVM.setMemory(0, window, BlockStart, BlockLength);
        } else {
      int FirstPartLength = Compress.MAXWINSIZE - BlockStart;
      // VM.SetMemory(0,Window+BlockStart,FirstPartLength);
      rarVM.setMemory(0, window, BlockStart, FirstPartLength);
      // VM.SetMemory(FirstPartLength,Window,BlockEnd);
      rarVM.setMemory(FirstPartLength, window, 0, BlockEnd);

        }

        VMPreparedProgram ParentPrg = filters.get(
          flt.getParentFilter()).getPrg();
        VMPreparedProgram Prg = flt.getPrg();

        if (ParentPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
      // copy global data from previous script execution if
      // any
      // Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
      // memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
      Prg.getGlobalData().setSize(
        ParentPrg.getGlobalData().size());
      for (int i = 0; i < ParentPrg.getGlobalData().size()
        - RarVM.VM_FIXEDGLOBALSIZE; i++) {
          Prg.getGlobalData().set(
            RarVM.VM_FIXEDGLOBALSIZE + i,
            ParentPrg.getGlobalData().get(
              RarVM.VM_FIXEDGLOBALSIZE + i));
      }
        }

        ExecuteCode(Prg);

        if (Prg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
      // save global data for next script execution
      if (ParentPrg.getGlobalData().size() < Prg
        .getGlobalData().size()) {
          ParentPrg.getGlobalData().setSize(
            Prg.getGlobalData().size());// ->GlobalData.Alloc(Prg->GlobalData.Size());
      }
      // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
      for (int i = 0; i < Prg.getGlobalData().size()
        - RarVM.VM_FIXEDGLOBALSIZE; i++) {
          ParentPrg.getGlobalData().set(
            RarVM.VM_FIXEDGLOBALSIZE + i,
            Prg.getGlobalData().get(
              RarVM.VM_FIXEDGLOBALSIZE + i));
      }
        } else {
      ParentPrg.getGlobalData().clear();
        }

        int FilteredDataOffset = Prg.getFilteredDataOffset();
        int FilteredDataSize = Prg.getFilteredDataSize();
        byte[] FilteredData = new byte[FilteredDataSize];

        for (int i = 0; i < FilteredDataSize; i++) {
      FilteredData[i] = rarVM.getMem()[FilteredDataOffset + i];// Prg.getGlobalData().get(FilteredDataOffset
                     // +
                     // i);
        }

        prgStack.set(I, null);
        while (I + 1 < prgStack.size()) {
      UnpackFilter NextFilter = prgStack.get(I + 1);
      if (NextFilter == null
        || NextFilter.getBlockStart() != BlockStart
        || NextFilter.getBlockLength() != FilteredDataSize
        || NextFilter.isNextWindow()) {
          break;
      }
      // apply several filters to same data block

      rarVM.setMemory(0, FilteredData, 0, FilteredDataSize);// .SetMemory(0,FilteredData,FilteredDataSize);

      VMPreparedProgram pPrg = filters.get(
        NextFilter.getParentFilter()).getPrg();
      VMPreparedProgram NextPrg = NextFilter.getPrg();

      if (pPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
          // copy global data from previous script execution
          // if any
          // NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
          NextPrg.getGlobalData().setSize(
            pPrg.getGlobalData().size());
          // memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
          for (int i = 0; i < pPrg.getGlobalData().size()
            - RarVM.VM_FIXEDGLOBALSIZE; i++) {
        NextPrg.getGlobalData().set(
          RarVM.VM_FIXEDGLOBALSIZE + i,
          pPrg.getGlobalData().get(
            RarVM.VM_FIXEDGLOBALSIZE + i));
          }
      }

      ExecuteCode(NextPrg);

      if (NextPrg.getGlobalData().size() > RarVM.VM_FIXEDGLOBALSIZE) {
          // save global data for next script execution
          if (pPrg.getGlobalData().size() < NextPrg
            .getGlobalData().size()) {
        pPrg.getGlobalData().setSize(
          NextPrg.getGlobalData().size());
          }
          // memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
          for (int i = 0; i < NextPrg.getGlobalData().size()
            - RarVM.VM_FIXEDGLOBALSIZE; i++) {
        pPrg.getGlobalData().set(
          RarVM.VM_FIXEDGLOBALSIZE + i,
          NextPrg.getGlobalData().get(
            RarVM.VM_FIXEDGLOBALSIZE + i));
          }
      } else {
          pPrg.getGlobalData().clear();
      }
      FilteredDataOffset = NextPrg.getFilteredDataOffset();
      FilteredDataSize = NextPrg.getFilteredDataSize();

      FilteredData = new byte[FilteredDataSize];
      for (int i = 0; i < FilteredDataSize; i++) {
          FilteredData[i] = NextPrg.getGlobalData().get(
            FilteredDataOffset + i);
      }

      I++;
      prgStack.set(I, null);
        }
        unpIO.unpWrite(FilteredData, 0, FilteredDataSize);
        unpSomeRead = true;
        writtenFileSize += FilteredDataSize;
        WrittenBorder = BlockEnd;
        WriteSize = (unpPtr - WrittenBorder) & Compress.MAXWINMASK;
    } else {
        for (int J = I; J < prgStack.size(); J++) {
      UnpackFilter filt = prgStack.get(J);
      if (filt != null && filt.isNextWindow()) {
          filt.setNextWindow(false);
      }
        }
        wrPtr = WrittenBorder;
        return;
    }
      }
  }

  UnpWriteArea(WrittenBorder, unpPtr);
  wrPtr = unpPtr;

    }

    private void UnpWriteArea(int startPtr, int endPtr) throws IOException {
  if (endPtr != startPtr) {
      unpSomeRead = true;
  }
  if (endPtr < startPtr) {
      UnpWriteData(window, startPtr, -startPtr & Compress.MAXWINMASK);
      UnpWriteData(window, 0, endPtr);
      unpAllBuf = true;
  } else {
      UnpWriteData(window, startPtr, endPtr - startPtr);
  }
    }

    private void UnpWriteData(byte[] data, int offset, int size)
      throws IOException {
  if (writtenFileSize >= destUnpSize) {
      return;
  }
  int writeSize = size;
  long leftToWrite = destUnpSize - writtenFileSize;
  if (writeSize > leftToWrite) {
      writeSize = (int) leftToWrite;
  }
  unpIO.unpWrite(data, offset, writeSize);

  writtenFileSize += size;

    }

    private void insertOldDist(int distance) {
  oldDist[3] = oldDist[2];
  oldDist[2] = oldDist[1];
  oldDist[1] = oldDist[0];
  oldDist[0] = distance;
    }

    private void insertLastMatch(int length, int distance) {
  lastDist = distance;
  lastLength = length;
    }

    private void copyString(int length, int distance) {
  // System.out.println("copyString(" + length + ", " + distance + ")");

  int destPtr = unpPtr - distance;
  // System.out.println(unpPtr+":"+distance);
  if (destPtr >= 0 && destPtr < Compress.MAXWINSIZE - 260
    && unpPtr < Compress.MAXWINSIZE - 260) {

      window[unpPtr++] = window[destPtr++];

      while (--length > 0)

    window[unpPtr++] = window[destPtr++];
  } else
      while (length-- != 0) {
    window[unpPtr] = window[destPtr++ & Compress.MAXWINMASK];
    unpPtr = (unpPtr + 1) & Compress.MAXWINMASK;
      }
    }

    protected void unpInitData(boolean solid) {
  if (!solid) {
      tablesRead = false;
      Arrays.fill(oldDist, 0); // memset(oldDist,0,sizeof(OldDist));

      oldDistPtr = 0;
      lastDist = 0;
      lastLength = 0;

      Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable));

      unpPtr = 0;
      wrPtr = 0;
      ppmEscChar = 2;

      initFilters();
  }
  InitBitInput();
  ppmError = false;
  writtenFileSize = 0;
  readTop = 0;
  readBorder = 0;
  unpInitData20(solid);
    }

    private void initFilters() {
  oldFilterLengths.clear();
  lastFilter = 0;

  filters.clear();

  prgStack.clear();
    }

    private boolean readEndOfBlock() throws IOException, RarException {
  int BitField = getbits();
  boolean NewTable, NewFile = false;
  if ((BitField & 0x8000) != 0) {
      NewTable = true;
      addbits(1);
  } else {
      NewFile = true;
      NewTable = (BitField & 0x4000) != 0 ? true : false;
      addbits(2);
  }
  tablesRead = !NewTable;
  return !(NewFile || NewTable && !readTables());
    }

    private boolean readTables() throws IOException, RarException {
  byte[] bitLength = new byte[Compress.BC];

  byte[] table = new byte[Compress.HUFF_TABLE_SIZE];
  if (inAddr > readTop - 25) {
      if (!unpReadBuf()) {
    return (false);
      }
  }
  faddbits((8 - inBit) & 7);
  long bitField = fgetbits() & 0xffFFffFF;
  if ((bitField & 0x8000) != 0) {
      unpBlockType = BlockTypes.BLOCK_PPM;
      return (ppm.decodeInit(this, ppmEscChar));
  }
  unpBlockType = BlockTypes.BLOCK_LZ;

  prevLowDist = 0;
  lowDistRepCount = 0;

  if ((bitField & 0x4000) == 0) {
      Arrays.fill(unpOldTable, (byte) 0);// memset(UnpOldTable,0,sizeof(UnpOldTable));
  }
  faddbits(2);

  for (int i = 0; i < Compress.BC; i++) {
      int length = (fgetbits() >>> 12) & 0xFF;
      faddbits(4);
      if (length == 15) {
    int zeroCount = (fgetbits() >>> 12) & 0xFF;
    faddbits(4);
    if (zeroCount == 0) {
        bitLength[i] = 15;
    } else {
        zeroCount += 2;
        while (zeroCount-- > 0 && i < bitLength.length) {
      bitLength[i++] = 0;
        }
        i--;
    }
      } else {
    bitLength[i] = (byte) length;
      }
  }

  makeDecodeTables(bitLength, 0, BD, Compress.BC);

  int TableSize = Compress.HUFF_TABLE_SIZE;

  for (int i = 0; i < TableSize;) {
      if (inAddr > readTop - 5) {
    if (!unpReadBuf()) {
        return (false);
    }
      }
      int Number = decodeNumber(BD);
      if (Number < 16) {
    table[i] = (byte) ((Number + unpOldTable[i]) & 0xf);
    i++;
      } else if (Number < 18) {
    int N;
    if (Number == 16) {
        N = (fgetbits() >>> 13) + 3;
        faddbits(3);
    } else {
        N = (fgetbits() >>> 9) + 11;
        faddbits(7);
    }
    while (N-- > 0 && i < TableSize) {
        table[i] = table[i - 1];
        i++;
    }
      } else {
    int N;
    if (Number == 18) {
        N = (fgetbits() >>> 13) + 3;
        faddbits(3);
    } else {
        N = (fgetbits() >>> 9) + 11;
        faddbits(7);
    }
    while (N-- > 0 && i < TableSize) {
        table[i++] = 0;
    }
      }
  }
  tablesRead = true;
  if (inAddr > readTop) {
      return (false);
  }
  makeDecodeTables(table, 0, LD, Compress.NC);
  makeDecodeTables(table, Compress.NC, DD, Compress.DC);
  makeDecodeTables(table, Compress.NC + Compress.DC, LDD, Compress.LDC);
  makeDecodeTables(table, Compress.NC + Compress.DC + Compress.LDC, RD,
    Compress.RC);

  // memcpy(unpOldTable,table,sizeof(unpOldTable));
  for (int i = 0; i < unpOldTable.length; i++) {
      unpOldTable[i] = table[i];
  }
  return (true);

    }

    private boolean readVMCode() throws IOException, RarException {
  int FirstByte = getbits() >> 8;
  addbits(8);
  int Length = (FirstByte & 7) + 1;
  if (Length == 7) {
      Length = (getbits() >> 8) + 7;
      addbits(8);
  } else if (Length == 8) {
      Length = getbits();
      addbits(16);
  }
  List<Byte> vmCode = new ArrayList<Byte>();
  for (int I = 0; I < Length; I++) {
      if (inAddr >= readTop - 1 && !unpReadBuf() && I < Length - 1) {
    return (false);
      }
      vmCode.add(Byte.valueOf((byte) (getbits() >> 8)));
      addbits(8);
  }
  return (addVMCode(FirstByte, vmCode, Length));
    }

    private boolean readVMCodePPM() throws IOException, RarException {
  int FirstByte = ppm.decodeChar();
  if ((int) FirstByte == -1) {
      return (false);
  }
  int Length = (FirstByte & 7) + 1;
  if (Length == 7) {
      int B1 = ppm.decodeChar();
      if (B1 == -1) {
    return (false);
      }
      Length = B1 + 7;
  } else if (Length == 8) {
      int B1 = ppm.decodeChar();
      if (B1 == -1) {
    return (false);
      }
      int B2 = ppm.decodeChar();
      if (B2 == -1) {
    return (false);
      }
      Length = B1 * 256 + B2;
  }
  List<Byte> vmCode = new ArrayList<Byte>();
  for (int I = 0; I < Length; I++) {
      int Ch = ppm.decodeChar();
      if (Ch == -1) {
    return (false);
      }
      vmCode.add(Byte.valueOf((byte) Ch));// VMCode[I]=Ch;
  }
  return (addVMCode(FirstByte, vmCode, Length));
    }

    private boolean addVMCode(int firstByte, List<Byte> vmCode, int length) {
  BitInput Inp = new BitInput();
  Inp.InitBitInput();
  // memcpy(Inp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize));
  for (int i = 0; i < Math.min(BitInput.MAX_SIZE, vmCode.size()); i++) {
      Inp.getInBuf()[i] = vmCode.get(i);
  }
  rarVM.init();

  int FiltPos;
  if ((firstByte & 0x80) != 0) {
      FiltPos = RarVM.ReadData(Inp);
      if (FiltPos == 0) {
    initFilters();
      } else {
    FiltPos--;
      }
  } else
      FiltPos = lastFilter; // use the same filter as last time

  if (FiltPos > filters.size() || FiltPos > oldFilterLengths.size()) {
      return (false);
  }
  lastFilter = FiltPos;
  boolean NewFilter = (FiltPos == filters.size());

  UnpackFilter StackFilter = new UnpackFilter(); // new filter for
  // PrgStack

  UnpackFilter Filter;
  if (NewFilter) // new filter code, never used before since VM reset
  {
      // too many different filters, corrupt archive
      if (FiltPos > 1024) {
    return (false);
      }

      // Filters[Filters.Size()-1]=Filter=new UnpackFilter;
      Filter = new UnpackFilter();
      filters.add(Filter);
      StackFilter.setParentFilter(filters.size() - 1);
      oldFilterLengths.add(0);
      Filter.setExecCount(0);
  } else // filter was used in the past
  {
      Filter = filters.get(FiltPos);
      StackFilter.setParentFilter(FiltPos);
      Filter.setExecCount(Filter.getExecCount() + 1);// ->ExecCount++;
  }

  prgStack.add(StackFilter);
  StackFilter.setExecCount(Filter.getExecCount());// ->ExecCount;

  int BlockStart = RarVM.ReadData(Inp);
  if ((firstByte & 0x40) != 0) {
      BlockStart += 258;
  }
  StackFilter.setBlockStart((BlockStart + unpPtr) & Compress.MAXWINMASK);
  if ((firstByte & 0x20) != 0) {
      StackFilter.setBlockLength(RarVM.ReadData(Inp));
  } else {
      StackFilter
        .setBlockLength(FiltPos < oldFilterLengths.size() ? oldFilterLengths
          .get(FiltPos)
          : 0);
  }
  StackFilter.setNextWindow((wrPtr != unpPtr)
    && ((wrPtr - unpPtr) & Compress.MAXWINMASK) <= BlockStart);

  // DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x
  // BlockStart=%08x",UnpPtr,WrPtr,BlockStart);

  oldFilterLengths.set(FiltPos, StackFilter.getBlockLength());

  // memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR));
  Arrays.fill(StackFilter.getPrg().getInitR(), 0);
  StackFilter.getPrg().getInitR()[3] = RarVM.VM_GLOBALMEMADDR;// StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR;
  StackFilter.getPrg().getInitR()[4] = StackFilter.getBlockLength();// StackFilter->Prg.InitR[4]=StackFilter->BlockLength;
  StackFilter.getPrg().getInitR()[5] = StackFilter.getExecCount();// StackFilter->Prg.InitR[5]=StackFilter->ExecCount;

  if ((firstByte & 0x10) != 0) // set registers to optional parameters
  // if any
  {
      int InitMask = Inp.fgetbits() >>> 9;
      Inp.faddbits(7);
      for (int I = 0; I < 7; I++) {
    if ((InitMask & (1 << I)) != 0) {
        // StackFilter->Prg.InitR[I]=RarVM::ReadData(Inp);
        StackFilter.getPrg().getInitR()[I] = RarVM.ReadData(Inp);
    }
      }
  }

  if (NewFilter) {
      int VMCodeSize = RarVM.ReadData(Inp);
      if (VMCodeSize >= 0x10000 || VMCodeSize == 0) {
    return (false);
      }
      byte[] VMCode = new byte[VMCodeSize];
      for (int I = 0; I < VMCodeSize; I++) {
    if (Inp.Overflow(3)) {
        return (false);
    }
    VMCode[I] = (byte) (Inp.fgetbits() >> 8);
    Inp.faddbits(8);
      }
      // VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg);
      rarVM.prepare(VMCode, VMCodeSize, Filter.getPrg());
  }
  StackFilter.getPrg().setAltCmd(Filter.getPrg().getCmd());// StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0];
  StackFilter.getPrg().setCmdCount(Filter.getPrg().getCmdCount());// StackFilter->Prg.CmdCount=Filter->Prg.CmdCount;

  int StaticDataSize = Filter.getPrg().getStaticData().size();
  if (StaticDataSize > 0 && StaticDataSize < RarVM.VM_GLOBALMEMSIZE) {
      // read statically defined data contained in DB commands
      // StackFilter->Prg.StaticData.Add(StaticDataSize);
      StackFilter.getPrg().setStaticData(Filter.getPrg().getStaticData());
      // memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize);
  }

  if (StackFilter.getPrg().getGlobalData().size() < RarVM.VM_FIXEDGLOBALSIZE) {
      // StackFilter->Prg.GlobalData.Reset();
      // StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE);
      StackFilter.getPrg().getGlobalData().clear();
      StackFilter.getPrg().getGlobalData().setSize(
        RarVM.VM_FIXEDGLOBALSIZE);
  }

  // byte *GlobalData=&StackFilter->Prg.GlobalData[0];
  Vector<Byte> globalData = StackFilter.getPrg().getGlobalData();
  for (int I = 0; I < 7; I++) {
      rarVM.setLowEndianValue(globalData, I * 4, StackFilter.getPrg()
        .getInitR()[I]);
  }

  // VM.SetLowEndianValue((uint
  // *)&GlobalData[0x1c],StackFilter->BlockLength);
  rarVM.setLowEndianValue(globalData, 0x1c, StackFilter.getBlockLength());
  // VM.SetLowEndianValue((uint *)&GlobalData[0x20],0);
  rarVM.setLowEndianValue(globalData, 0x20, 0);
  rarVM.setLowEndianValue(globalData, 0x24, 0);
  rarVM.setLowEndianValue(globalData, 0x28, 0);

  // VM.SetLowEndianValue((uint
  // *)&GlobalData[0x2c],StackFilter->ExecCount);
  rarVM.setLowEndianValue(globalData, 0x2c, StackFilter.getExecCount());
  // memset(&GlobalData[0x30],0,16);
  for (int i = 0; i < 16; i++) {
      globalData.set(0x30 + i, Byte.valueOf((byte) (0)));
  }
  if ((firstByte & 8) != 0) // put data block passed as parameter if any
  {
      if (Inp.Overflow(3)) {
    return (false);
      }
      int DataSize = RarVM.ReadData(Inp);
      if (DataSize > RarVM.VM_GLOBALMEMSIZE - RarVM.VM_FIXEDGLOBALSIZE) {
    return (false);
      }
      int CurSize = StackFilter.getPrg().getGlobalData().size();
      if (CurSize < DataSize + RarVM.VM_FIXEDGLOBALSIZE) {
    // StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize);
    StackFilter.getPrg().getGlobalData().setSize(
      DataSize + RarVM.VM_FIXEDGLOBALSIZE - CurSize);
      }
      int offset = RarVM.VM_FIXEDGLOBALSIZE;
      globalData = StackFilter.getPrg().getGlobalData();
      for (int I = 0; I < DataSize; I++) {
    if (Inp.Overflow(3)) {
        return (false);
    }
    globalData.set(offset + I, Byte
      .valueOf((byte) (Inp.fgetbits() >>> 8)));
    Inp.faddbits(8);
      }
  }
  return (true);
    }

    private void ExecuteCode(VMPreparedProgram Prg) {
  if (Prg.getGlobalData().size() > 0) {
      // Prg->InitR[6]=int64to32(WrittenFileSize);
      Prg.getInitR()[6] = (int) (writtenFileSize);
      // rarVM.SetLowEndianValue((uint
      // *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize));
      rarVM.setLowEndianValue(Prg.getGlobalData(), 0x24,
        (int) writtenFileSize);
      // rarVM.SetLowEndianValue((uint
      // *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32));
      rarVM.setLowEndianValue(Prg.getGlobalData(), 0x28,
        (int) (writtenFileSize >>> 32));
      rarVM.execute(Prg);
  }
    }

    // Duplicate method
    // private boolean ReadEndOfBlock() throws IOException, RarException
    // {
    // int BitField = getbits();
    // boolean NewTable, NewFile = false;
    // if ((BitField & 0x8000) != 0) {
    // NewTable = true;
    // addbits(1);
    // } else {
    // NewFile = true;
    // NewTable = (BitField & 0x4000) != 0;
    // addbits(2);
    // }
    // tablesRead = !NewTable;
    // return !(NewFile || NewTable && !readTables());
    // }

    public boolean isFileExtracted() {
  return fileExtracted;
    }

    public void setDestSize(long destSize) {
  this.destUnpSize = destSize;
  this.fileExtracted = false;
    }

    public void setSuspended(boolean suspended) {
  this.suspended = suspended;
    }

    public int getChar() throws IOException, RarException {
  if (inAddr > BitInput.MAX_SIZE - 30) {
      unpReadBuf();
  }
  return (inBuf[inAddr++] & 0xff);
    }

    public int getPpmEscChar() {
  return ppmEscChar;
    }

    public void setPpmEscChar(int ppmEscChar) {
  this.ppmEscChar = ppmEscChar;
    }

    public void cleanUp() {
  if (ppm != null) {
      SubAllocator allocator = ppm.getSubAlloc();
      if (allocator != null) {
    allocator.stopSubAllocator();
      }
  }
    }
}
TOP

Related Classes of de.innosystec.unrar.unpack.Unpack

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.