Folder.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.commons.compress.archivers.sevenz;

  18. import java.io.IOException;
  19. import java.util.Collections;
  20. import java.util.LinkedList;

  21. /**
  22.  * The unit of solid compression.
  23.  */
  24. final class Folder {

  25.     static final Folder[] EMPTY_FOLDER_ARRAY = {};

  26.     /** List of coders used in this folder, e.g. one for compression, one for encryption. */
  27.     Coder[] coders;

  28.     /**
  29.      * Total number of input streams across all coders. This field is currently unused but technically part of the 7z API.
  30.      */
  31.     long totalInputStreams;

  32.     /** Total number of output streams across all coders. */
  33.     long totalOutputStreams;

  34.     /** Mapping between input and output streams. */
  35.     BindPair[] bindPairs;

  36.     /** Indices of input streams, one per input stream not listed in bindPairs. */
  37.     long[] packedStreams;

  38.     /** Unpack sizes, per each output stream. */
  39.     long[] unpackSizes;

  40.     /** Whether the folder has a CRC. */
  41.     boolean hasCrc;

  42.     /** The CRC, if present. */
  43.     long crc;

  44.     /**
  45.      * The number of unpack substreams, product of the number of output streams and the number of non-empty files in this folder.
  46.      */
  47.     int numUnpackSubStreams;

  48.     int findBindPairForInStream(final int index) {
  49.         if (bindPairs != null) {
  50.             for (int i = 0; i < bindPairs.length; i++) {
  51.                 if (bindPairs[i].inIndex == index) {
  52.                     return i;
  53.                 }
  54.             }
  55.         }
  56.         return -1;
  57.     }

  58.     int findBindPairForOutStream(final int index) {
  59.         if (bindPairs != null) {
  60.             for (int i = 0; i < bindPairs.length; i++) {
  61.                 if (bindPairs[i].outIndex == index) {
  62.                     return i;
  63.                 }
  64.             }
  65.         }
  66.         return -1;
  67.     }

  68.     /**
  69.      * Sorts Coders using bind pairs.
  70.      * <p>
  71.      * The first coder reads from the packed stream (we currently only support single input stream decoders), the second reads from the output of the first and
  72.      * so on.
  73.      * </p>
  74.      */
  75.     Iterable<Coder> getOrderedCoders() throws IOException {
  76.         if (packedStreams == null || coders == null || packedStreams.length == 0 || coders.length == 0) {
  77.             return Collections.emptyList();
  78.         }
  79.         final LinkedList<Coder> list = new LinkedList<>();
  80.         int current = (int) packedStreams[0]; // more that 2^31 coders?
  81.         while (current >= 0 && current < coders.length) {
  82.             if (list.contains(coders[current])) {
  83.                 throw new IOException("folder uses the same coder more than once in coder chain");
  84.             }
  85.             list.addLast(coders[current]);
  86.             final int pair = findBindPairForOutStream(current);
  87.             current = pair != -1 ? (int) bindPairs[pair].inIndex : -1;
  88.         }
  89.         return list;
  90.     }

  91.     long getUnpackSize() {
  92.         if (totalOutputStreams == 0) {
  93.             return 0;
  94.         }
  95.         for (int i = (int) totalOutputStreams - 1; i >= 0; i--) {
  96.             if (findBindPairForOutStream(i) < 0) {
  97.                 return unpackSizes[i];
  98.             }
  99.         }
  100.         return 0;
  101.     }

  102.     long getUnpackSizeForCoder(final Coder coder) {
  103.         if (coders != null) {
  104.             for (int i = 0; i < coders.length; i++) {
  105.                 if (coders[i] == coder) {
  106.                     return unpackSizes[i];
  107.                 }
  108.             }
  109.         }
  110.         return 0;
  111.     }

  112.     @Override
  113.     public String toString() {
  114.         return "Folder with " + coders.length + " coders, " + totalInputStreams + " input streams, " + totalOutputStreams + " output streams, "
  115.                 + bindPairs.length + " bind pairs, " + packedStreams.length + " packed streams, " + unpackSizes.length + " unpack sizes, "
  116.                 + (hasCrc ? "with CRC " + crc : "without CRC") + " and " + numUnpackSubStreams + " unpack streams";
  117.     }
  118. }