| // Copyright 2015 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.android.ziputils; |
| |
| import static java.nio.ByteOrder.LITTLE_ENDIAN; |
| |
| import com.google.errorprone.annotations.CanIgnoreReturnValue; |
| import java.nio.ByteBuffer; |
| |
| /** |
| * Provides a view of a data descriptor record, for a zip file entry. |
| */ |
| public class DataDescriptor extends View<DataDescriptor> { |
| private boolean hasMarker; |
| |
| /** |
| * Returns a {@code DataDescriptor} view of the given buffer. The buffer is assumed to contain a |
| * valid "data descriptor" record beginning at the buffers current position. |
| * |
| * @param buffer containing the data of a data descriptor record. |
| * @return a {@code DataDescriptor} of the data at the current position of the given byte |
| * buffer. |
| */ |
| public static DataDescriptor viewOf(ByteBuffer buffer) { |
| DataDescriptor view = new DataDescriptor(buffer.slice()); |
| int size = view.getSize(); |
| view.buffer.position(0).limit(size); |
| buffer.position(buffer.position() + size); |
| return view; |
| } |
| |
| private DataDescriptor(ByteBuffer buffer) { |
| super(buffer); |
| hasMarker = buffer.getInt(0) == SIGNATURE; |
| } |
| |
| /** |
| * Creates a {@code DataDescriptor} with a heap allocated buffer. |
| * |
| * @return a {@code DataDescriptor} with a heap allocated buffer. |
| */ |
| public static DataDescriptor allocate() { |
| ByteBuffer buffer = ByteBuffer.allocate(SIZE).order(LITTLE_ENDIAN); |
| return new DataDescriptor(buffer).init(); |
| } |
| |
| /** |
| * Creates a {@code DataDescriptor} view over a writable buffer. The given buffers position is |
| * advanced by the number of bytes consumed by the view. |
| * |
| * @param buffer buffer to hold data for the "data descriptor" record. |
| * @return a {@code DataDescriptor} with a heap allocated buffer. |
| */ |
| public static DataDescriptor view(ByteBuffer buffer) { |
| DataDescriptor view = new DataDescriptor(buffer.slice()).init(); |
| buffer.position(buffer.position() + SIZE); |
| return view; |
| } |
| |
| /** |
| * Copies this {@code DataDescriptor} into a writable buffer. The copy is made at the |
| * buffer's current position, and the position is advanced, by the size of the copy. |
| * |
| * @param buffer buffer to hold data for the copy. |
| * @return a {@code DataDescriptor} backed by the given buffer. |
| */ |
| public DataDescriptor copy(ByteBuffer buffer) { |
| int size = getSize(); |
| DataDescriptor view = new DataDescriptor(buffer.slice()); |
| this.buffer.rewind(); |
| view.buffer.put(this.buffer).flip(); |
| buffer.position(buffer.position() + size); |
| this.buffer.rewind(); |
| return view; |
| } |
| |
| @CanIgnoreReturnValue |
| private DataDescriptor init() { |
| buffer.putInt(0, SIGNATURE); |
| hasMarker = true; |
| buffer.limit(SIZE); |
| return this; |
| } |
| |
| /** |
| * Data descriptor signature. |
| */ |
| public static final int SIGNATURE = 0x08074b50; // 134695760L |
| |
| /** |
| * Data descriptor size (including optional signature). |
| */ |
| public static final int SIZE = 16; |
| |
| /** |
| * For accessing the data descriptor signature, with the {@link |
| * View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)} and {@link |
| * View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, long)} methods. |
| */ |
| public static final IntFieldId<DataDescriptor> EXTSIG = new IntFieldId<>(0); |
| |
| /** |
| * For accessing the "crc" data descriptor field, with the {@link |
| * View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)} and {@link |
| * View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, long)} methods. |
| */ |
| public static final IntFieldId<DataDescriptor> EXTCRC = new IntFieldId<>(4); |
| |
| /** |
| * For accessing the "compressed size" data descriptor field, with the {@link |
| * View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)} and {@link |
| * View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, long)} methods. |
| */ |
| public static final IntFieldId<DataDescriptor> EXTSIZ = new IntFieldId<>(8); |
| |
| /** |
| * For accessing the "uncompressed size" data descriptor field, with the {@link |
| * View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)} and {@link |
| * View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, long)} methods. |
| */ |
| public static final IntFieldId<DataDescriptor> EXTLEN = new IntFieldId<>(12); |
| |
| /** |
| * Overrides the generic field getter, to handle optionality of signature. |
| * |
| * @see View#get(com.google.devtools.build.android.ziputils.View.IntFieldId). |
| */ |
| @Override |
| public long get(IntFieldId<? extends DataDescriptor> item) { |
| int address = hasMarker ? item.address() : (item.address() - 4); |
| return address < 0 ? -1 : buffer.getInt(address); |
| } |
| |
| /** |
| * Returns whether this data descriptor has the optional signature. |
| * @return {@code true} if this data descriptor has a signature, {@code false} otherwise. |
| */ |
| public final boolean hasMarker() { |
| return hasMarker; |
| } |
| |
| /** |
| * Returns the size of this data descriptor. |
| * @return 12, or 16, depending on whether or not this data descriptor has a signature. |
| */ |
| public final int getSize() { |
| return hasMarker ? SIZE : SIZE - 4; |
| } |
| } |