BinaryTree.java

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

  19. package org.apache.commons.compress.archivers.zip;

  20. import java.io.EOFException;
  21. import java.io.IOException;
  22. import java.io.InputStream;

  23. import org.apache.commons.compress.utils.IOUtils;
  24. import org.apache.commons.lang3.ArrayFill;

  25. /**
  26.  * Binary tree of positive values.
  27.  *
  28.  * @since 1.7
  29.  */
  30. final class BinaryTree {

  31.     /** Value in the array indicating an undefined node */
  32.     private static final int UNDEFINED = -1;

  33.     /** Value in the array indicating a non leaf node */
  34.     private static final int NODE = -2;

  35.     /**
  36.      * Decodes the packed binary tree from the specified stream.
  37.      */
  38.     static BinaryTree decode(final InputStream inputStream, final int totalNumberOfValues) throws IOException {
  39.         if (totalNumberOfValues < 0) {
  40.             throw new IllegalArgumentException("totalNumberOfValues must be bigger than 0, is " + totalNumberOfValues);
  41.         }
  42.         // the first byte contains the size of the structure minus one
  43.         final int size = inputStream.read() + 1;
  44.         if (size == 0) {
  45.             throw new IOException("Cannot read the size of the encoded tree, unexpected end of stream");
  46.         }

  47.         final byte[] encodedTree = IOUtils.readRange(inputStream, size);
  48.         if (encodedTree.length != size) {
  49.             throw new EOFException();
  50.         }

  51.         /* The maximum bit length for a value (16 or lower) */
  52.         int maxLength = 0;

  53.         final int[] originalBitLengths = new int[totalNumberOfValues];
  54.         int pos = 0;
  55.         for (final byte b : encodedTree) {
  56.             // each byte encodes the number of values (upper 4 bits) for a bit length (lower 4 bits)
  57.             final int numberOfValues = ((b & 0xF0) >> 4) + 1;
  58.             if (pos + numberOfValues > totalNumberOfValues) {
  59.                 throw new IOException("Number of values exceeds given total number of values");
  60.             }
  61.             final int bitLength = (b & 0x0F) + 1;

  62.             for (int j = 0; j < numberOfValues; j++) {
  63.                 originalBitLengths[pos++] = bitLength;
  64.             }

  65.             maxLength = Math.max(maxLength, bitLength);
  66.         }

  67.         final int oBitLengths = originalBitLengths.length;
  68.         // sort the array of bit lengths and memorize the permutation used to restore the order of the codes
  69.         final int[] permutation = new int[oBitLengths];
  70.         for (int k = 0; k < permutation.length; k++) {
  71.             permutation[k] = k;
  72.         }

  73.         int c = 0;
  74.         final int[] sortedBitLengths = new int[oBitLengths];
  75.         for (int k = 0; k < oBitLengths; k++) {
  76.             // iterate over the values
  77.             for (int l = 0; l < oBitLengths; l++) {
  78.                 // look for the value in the original array
  79.                 if (originalBitLengths[l] == k) {
  80.                     // put the value at the current position in the sorted array...
  81.                     sortedBitLengths[c] = k;

  82.                     // ...and memorize the permutation
  83.                     permutation[c] = l;

  84.                     c++;
  85.                 }
  86.             }
  87.         }

  88.         // decode the values of the tree
  89.         int code = 0;
  90.         int codeIncrement = 0;
  91.         int lastBitLength = 0;

  92.         final int[] codes = new int[totalNumberOfValues];

  93.         for (int i = totalNumberOfValues - 1; i >= 0; i--) {
  94.             code += codeIncrement;
  95.             if (sortedBitLengths[i] != lastBitLength) {
  96.                 lastBitLength = sortedBitLengths[i];
  97.                 codeIncrement = 1 << 16 - lastBitLength;
  98.             }
  99.             codes[permutation[i]] = code;
  100.         }

  101.         // build the tree
  102.         final BinaryTree tree = new BinaryTree(maxLength);

  103.         for (int k = 0; k < codes.length; k++) {
  104.             final int bitLength = originalBitLengths[k];
  105.             if (bitLength > 0) {
  106.                 tree.addLeaf(0, Integer.reverse(codes[k] << 16), bitLength, k);
  107.             }
  108.         }

  109.         return tree;
  110.     }

  111.     /**
  112.      * The array representing the binary tree. The root is at index 0, the left children are at 2*i+1 and the right children at 2*i+2.
  113.      */
  114.     private final int[] tree;

  115.     BinaryTree(final int depth) {
  116.         if (depth < 0 || depth > 30) {
  117.             throw new IllegalArgumentException("depth must be bigger than 0 and not bigger than 30" + " but is " + depth);
  118.         }
  119.         tree = ArrayFill.fill(new int[(int) ((1L << depth + 1) - 1)], UNDEFINED);
  120.     }

  121.     /**
  122.      * Adds a leaf to the tree.
  123.      *
  124.      * @param node  the index of the node where the path is appended
  125.      * @param path  the path to the leaf (bits are parsed from the right to the left)
  126.      * @param depth the number of nodes in the path
  127.      * @param value the value of the leaf (must be positive)
  128.      */
  129.     public void addLeaf(final int node, final int path, final int depth, final int value) {
  130.         if (depth == 0) {
  131.             // end of the path reached, add the value to the current node
  132.             if (tree[node] != UNDEFINED) {
  133.                 throw new IllegalArgumentException("Tree value at index " + node + " has already been assigned (" + tree[node] + ")");
  134.             }
  135.             tree[node] = value;
  136.         } else {
  137.             // mark the current node as a non leaf node
  138.             tree[node] = NODE;

  139.             // move down the path recursively
  140.             final int nextChild = 2 * node + 1 + (path & 1);
  141.             addLeaf(nextChild, path >>> 1, depth - 1, value);
  142.         }
  143.     }

  144.     /**
  145.      * Reads a value from the specified bit stream.
  146.      *
  147.      * @param stream
  148.      * @return the value decoded, or -1 if the end of the stream is reached
  149.      * @throws IOException on error.
  150.      */
  151.     public int read(final BitStream stream) throws IOException {
  152.         int currentIndex = 0;

  153.         while (true) {
  154.             final int bit = stream.nextBit();
  155.             if (bit == -1) {
  156.                 return -1;
  157.             }

  158.             final int childIndex = 2 * currentIndex + 1 + bit;
  159.             final int value = tree[childIndex];
  160.             if (value == NODE) {
  161.                 // consume the next bit
  162.                 currentIndex = childIndex;
  163.             } else if (value != UNDEFINED) {
  164.                 return value;
  165.             } else {
  166.                 throw new IOException("The child " + bit + " of node at index " + currentIndex + " is not defined");
  167.             }
  168.         }
  169.     }
  170. }