Example #1
0
  /**
   * @param compressed_size or use null if not known
   * @param uncompressed_size or use null if not known
   * @return uncompressed ByteArrayOutputStream
   * @throws IOException
   * @throws DataFormatException
   */
  private ByteArrayOutputStream unCompress(Integer compressed_size, Integer uncompressed_size)
      throws IOException, DataFormatException {
    byte[] uncompressed_data = null;
    byte[] input_data = null;
    ByteArrayOutputStream ret = new ByteArrayOutputStream();
    Inflater decompresser = new Inflater(false);
    long first_seek = fileChannel.position();
    Boolean uncompressing = true;
    while (uncompressing) {
      if (decompresser.needsInput()) {
        input_data = new byte[(compressed_size != null) ? compressed_size.intValue() : 1024];
        fileChannel.read(ByteBuffer.wrap(input_data));
        decompresser.setInput(input_data, 0, input_data.length);
      }
      uncompressed_data =
          new byte
              [(uncompressed_size != null)
                  ? uncompressed_size.intValue()
                  : (input_data.length * 4)];
      decompresser.inflate(uncompressed_data);
      int op = (int) (decompresser.getBytesWritten() - (long) ret.size());
      if (op > 0) ret.write(uncompressed_data, 0, op);

      if (decompresser.finished()) uncompressing = false;
    }
    fileChannel.position(
        (first_seek + decompresser.getBytesRead())); // move file pointer to start of next stream
    decompresser.end();
    return ret;
  }
  /**
   * {@inheritDoc}
   *
   * <p>If the decoding did not produce any output, for example because it consumed gzip header or
   * trailer bytes, it returns a buffer with zero capacity.
   *
   * <p>This method never returns null.
   *
   * <p>The given {@code buffer}'s position will be modified to reflect the bytes consumed during
   * the decoding.
   *
   * <p>The decoding may be finished without consuming the buffer completely if the buffer contains
   * gzip bytes plus other bytes (either plain or gzipped).
   */
  @Override
  public ByteBuffer decode(ByteBuffer buffer) {
    try {
      while (buffer.hasRemaining()) {
        byte currByte = buffer.get();
        switch (state) {
          case INITIAL:
            {
              buffer.position(buffer.position() - 1);
              state = State.ID;
              break;
            }
          case ID:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 2) {
                if (value != 0x8B1F) throw new ZipException("Invalid gzip bytes");
                state = State.CM;
              }
              break;
            }
          case CM:
            {
              if ((currByte & 0xFF) != 0x08)
                throw new ZipException("Invalid gzip compression method");
              state = State.FLG;
              break;
            }
          case FLG:
            {
              flags = currByte;
              state = State.MTIME;
              size = 0;
              value = 0;
              break;
            }
          case MTIME:
            {
              // Skip the 4 MTIME bytes
              ++size;
              if (size == 4) state = State.XFL;
              break;
            }
          case XFL:
            {
              // Skip XFL
              state = State.OS;
              break;
            }
          case OS:
            {
              // Skip OS
              state = State.FLAGS;
              break;
            }
          case FLAGS:
            {
              buffer.position(buffer.position() - 1);
              if ((flags & 0x04) == 0x04) {
                state = State.EXTRA_LENGTH;
                size = 0;
                value = 0;
              } else if ((flags & 0x08) == 0x08) state = State.NAME;
              else if ((flags & 0x10) == 0x10) state = State.COMMENT;
              else if ((flags & 0x2) == 0x2) {
                state = State.HCRC;
                size = 0;
                value = 0;
              } else state = State.DATA;
              break;
            }
          case EXTRA_LENGTH:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 2) state = State.EXTRA;
              break;
            }
          case EXTRA:
            {
              // Skip EXTRA bytes
              --value;
              if (value == 0) {
                // Clear the EXTRA flag and loop on the flags
                flags &= ~0x04;
                state = State.FLAGS;
              }
              break;
            }
          case NAME:
            {
              // Skip NAME bytes
              if (currByte == 0) {
                // Clear the NAME flag and loop on the flags
                flags &= ~0x08;
                state = State.FLAGS;
              }
              break;
            }
          case COMMENT:
            {
              // Skip COMMENT bytes
              if (currByte == 0) {
                // Clear the COMMENT flag and loop on the flags
                flags &= ~0x10;
                state = State.FLAGS;
              }
              break;
            }
          case HCRC:
            {
              // Skip HCRC
              ++size;
              if (size == 2) {
                // Clear the HCRC flag and loop on the flags
                flags &= ~0x02;
                state = State.FLAGS;
              }
              break;
            }
          case DATA:
            {
              buffer.position(buffer.position() - 1);
              while (true) {
                int decoded = inflate(bytes);
                if (decoded == 0) {
                  if (inflater.needsInput()) {
                    if (buffer.hasRemaining()) {
                      byte[] input = new byte[buffer.remaining()];
                      buffer.get(input);
                      inflater.setInput(input);
                    } else {
                      if (output != null) {
                        ByteBuffer result = ByteBuffer.wrap(output);
                        output = null;
                        return result;
                      }
                      break;
                    }
                  } else if (inflater.finished()) {
                    int remaining = inflater.getRemaining();
                    buffer.position(buffer.limit() - remaining);
                    state = State.CRC;
                    size = 0;
                    value = 0;
                    break;
                  } else {
                    throw new ZipException("Invalid inflater state");
                  }
                } else {
                  if (output == null) {
                    // Save the inflated bytes and loop to see if we have finished
                    output = Arrays.copyOf(bytes, decoded);
                  } else {
                    // Accumulate inflated bytes and loop to see if we have finished
                    byte[] newOutput = Arrays.copyOf(output, output.length + decoded);
                    System.arraycopy(bytes, 0, newOutput, output.length, decoded);
                    output = newOutput;
                  }
                }
              }
              break;
            }
          case CRC:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 4) {
                // From RFC 1952, compliant decoders need not to verify the CRC
                state = State.ISIZE;
                size = 0;
                value = 0;
              }
              break;
            }
          case ISIZE:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 4) {
                if (value != inflater.getBytesWritten())
                  throw new ZipException("Invalid input size");

                ByteBuffer result =
                    output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output);
                reset();
                return result;
              }
              break;
            }
          default:
            throw new ZipException();
        }
      }
      return BufferUtil.EMPTY_BUFFER;
    } catch (ZipException x) {
      throw new RuntimeException(x);
    }
  }