View Javadoc
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  
19  import java.io.IOException;
20  import java.util.Collections;
21  import java.util.LinkedList;
22  
23  /**
24   * The unit of solid compression.
25   */
26  final class Folder {
27  
28      static final Folder[] EMPTY_FOLDER_ARRAY = {};
29  
30      /** List of coders used in this folder, e.g. one for compression, one for encryption. */
31      Coder[] coders;
32  
33      /**
34       * Total number of input streams across all coders. This field is currently unused but technically part of the 7z API.
35       */
36      long totalInputStreams;
37  
38      /** Total number of output streams across all coders. */
39      long totalOutputStreams;
40  
41      /** Mapping between input and output streams. */
42      BindPair[] bindPairs;
43  
44      /** Indices of input streams, one per input stream not listed in bindPairs. */
45      long[] packedStreams;
46  
47      /** Unpack sizes, per each output stream. */
48      long[] unpackSizes;
49  
50      /** Whether the folder has a CRC. */
51      boolean hasCrc;
52  
53      /** The CRC, if present. */
54      long crc;
55  
56      /**
57       * The number of unpack substreams, product of the number of output streams and the number of non-empty files in this folder.
58       */
59      int numUnpackSubStreams;
60  
61      int findBindPairForInStream(final int index) {
62          if (bindPairs != null) {
63              for (int i = 0; i < bindPairs.length; i++) {
64                  if (bindPairs[i].inIndex == index) {
65                      return i;
66                  }
67              }
68          }
69          return -1;
70      }
71  
72      int findBindPairForOutStream(final int index) {
73          if (bindPairs != null) {
74              for (int i = 0; i < bindPairs.length; i++) {
75                  if (bindPairs[i].outIndex == index) {
76                      return i;
77                  }
78              }
79          }
80          return -1;
81      }
82  
83      /**
84       * Sorts Coders using bind pairs.
85       * <p>
86       * 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
87       * so on.
88       * </p>
89       */
90      Iterable<Coder> getOrderedCoders() throws IOException {
91          if (packedStreams == null || coders == null || packedStreams.length == 0 || coders.length == 0) {
92              return Collections.emptyList();
93          }
94          final LinkedList<Coder> list = new LinkedList<>();
95          int current = (int) packedStreams[0]; // more that 2^31 coders?
96          while (current >= 0 && current < coders.length) {
97              if (list.contains(coders[current])) {
98                  throw new IOException("folder uses the same coder more than once in coder chain");
99              }
100             list.addLast(coders[current]);
101             final int pair = findBindPairForOutStream(current);
102             current = pair != -1 ? (int) bindPairs[pair].inIndex : -1;
103         }
104         return list;
105     }
106 
107     long getUnpackSize() {
108         if (totalOutputStreams == 0) {
109             return 0;
110         }
111         for (int i = (int) totalOutputStreams - 1; i >= 0; i--) {
112             if (findBindPairForOutStream(i) < 0) {
113                 return unpackSizes[i];
114             }
115         }
116         return 0;
117     }
118 
119     long getUnpackSizeForCoder(final Coder coder) {
120         if (coders != null) {
121             for (int i = 0; i < coders.length; i++) {
122                 if (coders[i] == coder) {
123                     return unpackSizes[i];
124                 }
125             }
126         }
127         return 0;
128     }
129 
130     @Override
131     public String toString() {
132         return "Folder with " + coders.length + " coders, " + totalInputStreams + " input streams, " + totalOutputStreams + " output streams, "
133                 + bindPairs.length + " bind pairs, " + packedStreams.length + " packed streams, " + unpackSizes.length + " unpack sizes, "
134                 + (hasCrc ? "with CRC " + crc : "without CRC") + " and " + numUnpackSubStreams + " unpack streams";
135     }
136 }