blob: 466dc07715593b7f577035c93fdbb93255a1d18e [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 static java.nio.charset.StandardCharsets.UTF_8;
import java.nio.ByteBuffer;
/**
* Provides a view of a zip files "end of central directory" record.
*/
public class EndOfCentralDirectory extends View<EndOfCentralDirectory> {
/**
* Returns a {@code EndOfCentralDirectory} of the given buffer.
*
* @param buffer containing the data of a "end of central directory" record.
* @return a {@code EndOfCentralDirectory} of the data at the current position of the given
* byte buffer.
*/
public static EndOfCentralDirectory viewOf(ByteBuffer buffer) {
EndOfCentralDirectory view = new EndOfCentralDirectory(buffer.slice());
view.buffer.position(0).limit(view.getSize());
buffer.position(buffer.position() + view.buffer.remaining());
return view;
}
private EndOfCentralDirectory(ByteBuffer buffer) {
super(buffer);
}
/**
* Creates a {@code EndOfCentralDirectory} with a heap allocated buffer.
*
* @param comment zip file comment, or {@code null}.
* @return a {@code EndOfCentralDirectory} with a heap allocated buffer.
*/
public static EndOfCentralDirectory allocate(String comment) {
byte[] commentData = comment != null ? comment.getBytes(UTF_8) : EMPTY;
int size = SIZE + commentData.length;
ByteBuffer buffer = ByteBuffer.allocate(size).order(LITTLE_ENDIAN);
return new EndOfCentralDirectory(buffer).init(commentData);
}
/**
* Creates a {@code EndOfCentralDirectory} over a writable buffer.
*
* @param buffer buffer to hold data for the "end of central directory" record.
* @param comment zip file global comment, or {@code null}.
* @return a {@code EndOfCentralDirectory} with a heap allocated buffer.
*/
public static EndOfCentralDirectory view(ByteBuffer buffer, String comment) {
byte[] commentData = comment != null ? comment.getBytes(UTF_8) : EMPTY;
int size = SIZE + commentData.length;
EndOfCentralDirectory view = new EndOfCentralDirectory(buffer.slice()).init(commentData);
buffer.position(buffer.position() + size);
return view;
}
/**
* Copies this {@code EndOfCentralDirectory} over a writable buffer.
*
* @param buffer writable byte buffer to hold the data of the copy.
*/
public EndOfCentralDirectory copy(ByteBuffer buffer) {
EndOfCentralDirectory view = new EndOfCentralDirectory(buffer.slice());
this.buffer.rewind();
view.buffer.put(this.buffer).flip();
this.buffer.rewind();
buffer.position(buffer.position() + this.buffer.remaining());
return view;
}
private EndOfCentralDirectory init(byte[] comment) {
buffer.putInt(0, SIGNATURE);
set(ENDCOM, (short) comment.length);
if (comment.length > 0) {
buffer.position(SIZE);
buffer.put(comment);
}
buffer.position(0).limit(SIZE + comment.length);
return this;
}
/**
* Signature of end of directory record.
*/
public static final int SIGNATURE = 0x06054b50; //101010256L
/**
* Size of end of directory record, not including variable data.
* Also the offset of the file comment, if any.
*/
public static final int SIZE = 22;
/**
* For accessing the end of central directory 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<EndOfCentralDirectory> ENDSIG = new IntFieldId<>(0);
/**
* For accessing the "this disk number" end of central directory field, with the
* {@link View#get(com.google.devtools.build.android.ziputils.View.ShortFieldId)}
* and {@link View#set(com.google.devtools.build.android.ziputils.View.ShortFieldId, short)}
* methods.
*/
public static final ShortFieldId<EndOfCentralDirectory> ENDDSK = new ShortFieldId<>(4);
/**
* For accessing the "central directory start disk" end of central directory field, with the
* {@link View#get(com.google.devtools.build.android.ziputils.View.ShortFieldId)}
* and {@link View#set(com.google.devtools.build.android.ziputils.View.ShortFieldId, short)}
* methods.
*/
public static final ShortFieldId<EndOfCentralDirectory> ENDDCD = new ShortFieldId<>(6);
/**
* For accessing the "central directory local records" end of central directory field, with the
* {@link View#get(com.google.devtools.build.android.ziputils.View.ShortFieldId)}
* and {@link View#set(com.google.devtools.build.android.ziputils.View.ShortFieldId, short)}
* methods.
*/
public static final ShortFieldId<EndOfCentralDirectory> ENDSUB = new ShortFieldId<>(8);
/**
* For accessing the "central directory total records" end of central directory field, with the
* {@link View#get(com.google.devtools.build.android.ziputils.View.ShortFieldId)}
* and {@link View#set(com.google.devtools.build.android.ziputils.View.ShortFieldId, short)}
* methods.
*/
public static final ShortFieldId<EndOfCentralDirectory> ENDTOT = new ShortFieldId<>(10);
/**
* For accessing the "central directory size" end of central directory 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<EndOfCentralDirectory> ENDSIZ = new IntFieldId<>(12);
/**
* For accessing the "central directory offset" end of central directory 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<EndOfCentralDirectory> ENDOFF = new IntFieldId<>(16);
/**
* For accessing the "file comment length" end of central directory field, with the
* {@link View#get(com.google.devtools.build.android.ziputils.View.ShortFieldId)}
* and {@link View#set(com.google.devtools.build.android.ziputils.View.ShortFieldId, short)}
* methods.
*/
public static final ShortFieldId<EndOfCentralDirectory> ENDCOM = new ShortFieldId<>(20);
/**
* Returns the file comment.
* @return the file comment, or an empty string.
*/
public final String getComment() {
return getString(SIZE, get(ENDCOM));
}
/**
* Returns the total size of the end of directory record, including file comment, if any.
* @return the total size of the end of directory record.
*/
public int getSize() {
return SIZE + get(ENDCOM);
}
}