// Copyright 2014 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.zip; import java.util.Arrays; /** * A holder class for extra data in a ZIP entry. */ public final class ExtraData { static final int ID_OFFSET = 0; static final int LENGTH_OFFSET = 2; static final int FIXED_DATA_SIZE = 4; private final int index; private final byte[] buffer; /** * Creates a new {@link ExtraData} record with the specified id and data. * * @param id the ID tag for this extra data record * @param data the data payload for this extra data record */ public ExtraData(short id, byte[] data) { if (data.length > 0xffff) { throw new IllegalArgumentException(String.format("Data is too long. Is %d; max %d", data.length, 0xffff)); } index = 0; buffer = new byte[FIXED_DATA_SIZE + data.length]; ZipUtil.shortToLittleEndian(buffer, ID_OFFSET, id); ZipUtil.shortToLittleEndian(buffer, LENGTH_OFFSET, (short) data.length); System.arraycopy(data, 0, buffer, FIXED_DATA_SIZE, data.length); } /** * Creates a new {@link ExtraData} record using the buffer as the backing data store. * * <p><em>NOTE:</em> does not perform any defensive copying. Any modification to the buffer will * alter the extra data record and can make it invalid. * * @param buffer the array containing the extra data record * @param index the index where the extra data record is located * @throws IllegalArgumentException if buffer does not contain a well formed extra data record * at index */ ExtraData(byte[] buffer, int index) { if (index >= buffer.length) { throw new IllegalArgumentException("index past end of buffer"); } if (buffer.length - index < FIXED_DATA_SIZE) { throw new IllegalArgumentException("incomplete extra data entry in buffer"); } int length = ZipUtil.getUnsignedShort(buffer, index + LENGTH_OFFSET); if (buffer.length - index - FIXED_DATA_SIZE < length) { throw new IllegalArgumentException("incomplete extra data entry in buffer"); } this.buffer = buffer; this.index = index; } /** Returns the Id of the extra data record. */ public short getId() { return ZipUtil.get16(buffer, index + ID_OFFSET); } /** Returns the total length of the extra data record in bytes. */ public int getLength() { return getDataLength() + FIXED_DATA_SIZE; } /** Returns the length of the data payload of the extra data record in bytes. */ public int getDataLength() { return ZipUtil.getUnsignedShort(buffer, index + LENGTH_OFFSET); } /** Returns a byte array copy of the data payload. */ public byte[] getData() { return Arrays.copyOfRange(buffer, index + FIXED_DATA_SIZE, index + getLength()); } /** Returns a byte array copy of the entire record. */ public byte[] getBytes() { return Arrays.copyOfRange(buffer, index, index + getLength()); } /** Returns the byte at index from the entire record. */ byte getByte(int index) { return buffer[this.index + index]; } }