blob: ee7fbca022c939e4b48f0a142dce2d17fcc1fe80 [file] [log] [blame]
// 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 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;
}
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, int)}
* 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, int)}
* 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, int)}
* 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, int)}
* 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 @SuppressWarnings("unchecked") // safe by specification (FieldId.type()).
public int 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;
}
}