blob: 441eb712580d3fcc2227411295ff6b5d4c204c7e [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 com.google.devtools.build.android.ziputils.DataDescriptor.EXTLEN;
import static com.google.devtools.build.android.ziputils.DataDescriptor.EXTSIZ;
import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENFLG;
import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENLEN;
import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENOFF;
import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENSIZ;
import static com.google.devtools.build.android.ziputils.DirectoryEntry.CENTIM;
import static com.google.devtools.build.android.ziputils.LocalFileHeader.LOCFLG;
import static com.google.devtools.build.android.ziputils.LocalFileHeader.LOCLEN;
import static com.google.devtools.build.android.ziputils.LocalFileHeader.LOCSIZ;
import static com.google.devtools.build.android.ziputils.LocalFileHeader.LOCTIM;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* Zip file builder for testing, For now it only supports building
* valid zip files.
*/
class ZipFileBuilder {
private final List<FileInfo> input;
private static final Charset CHARSET = Charset.forName("UTF-8");
private static final byte[] EMPTY = {};
public ZipFileBuilder() {
input = new ArrayList<>();
}
public ZipFileBuilder add(String filename, String content) {
input.add(new FileInfo(filename, content.getBytes(Charset.defaultCharset())));
return this;
}
public ZipFileBuilder add(FileInfo fileInfo) {
input.add(fileInfo);
return this;
}
public void create(String filename) throws IOException {
ZipOut out = new ZipOut(FileSystem.fileSystem().getOutputChannel(filename, false), filename);
for (FileInfo info : input) {
int compressed = info.compressedSize();
int uncompressed = info.uncompressedSize();
int dirCompressed = info.dirCompressedSize();
int dirUncompressed = info.dirUncompressedSize();
short flags = info.flags();
DirectoryEntry entry = DirectoryEntry.allocate(info.name, info.extra, info.comment);
out.nextEntry(entry)
.set(CENOFF, out.fileOffset())
.set(CENFLG, flags)
.set(CENTIM, info.date)
.set(CENLEN, dirUncompressed)
.set(CENSIZ, dirCompressed);
LocalFileHeader header = LocalFileHeader.allocate(info.name, null)
.set(LOCFLG, flags)
.set(LOCTIM, info.date)
.set(LOCLEN, uncompressed)
.set(LOCSIZ, compressed);
out.write(header);
out.write(ByteBuffer.wrap(info.data));
if (flags != 0) {
DataDescriptor desc = DataDescriptor.allocate()
.set(EXTLEN, dirUncompressed)
.set(EXTSIZ, dirCompressed);
out.write(desc);
}
}
out.close();
}
public static class FileInfo {
private final String name;
private final short method;
private final int date;
private final int uncompressed;
private final byte[] data;
private final byte[] extra;
private final String comment;
boolean maskSize;
static final short STORED = 0;
static final short DEFLATED = 8;
public FileInfo(String filename, String content) {
this(filename, DosTime.EPOCH.time, STORED, 0,
(content == null ? EMPTY : content.getBytes(CHARSET)), null, null);
}
public FileInfo(String filename, byte[] data) {
this(filename, DosTime.EPOCH.time, STORED, 0, data, null, null);
}
public FileInfo(String filename, byte[] data, int uncompressed) {
this(filename, DosTime.EPOCH.time, DEFLATED, uncompressed, data, null, null);
}
public FileInfo(String filename, int dosTime, String content) {
this(filename, dosTime, STORED, 0,
(content == null ? EMPTY : content.getBytes(CHARSET)), null, null);
}
public FileInfo(String filename, int dosTime, byte[] data) {
this(filename, dosTime, STORED, 0, data, null, null);
}
public FileInfo(String filename, int dosTime, byte[] data, int uncompressed) {
this(filename, dosTime, DEFLATED, uncompressed, data, null, null);
}
public FileInfo(String filename, int dosTime, short method, int uncompressed,
byte[] content, byte[] extra, String comment) {
this.name = filename;
this.date = dosTime;
this.method = method;
this.uncompressed = uncompressed;
this.data = content;
this.extra = extra;
this.comment = comment;
maskSize = false;
}
public void setMaskSize(boolean ignore) {
maskSize = ignore;
}
int compressedSize() {
return method != 0 && !maskSize ? data.length : 0;
}
int uncompressedSize() {
return method == 0 ? data.length : maskSize ? 0 : uncompressed;
}
int dirCompressedSize() {
return method == 0 ? 0 : data.length;
}
int dirUncompressedSize() {
return method == 0 ? data.length : uncompressed;
}
short flags() {
return method != 0 && uncompressed == 0 ? LocalFileHeader.SIZE_MASKED_FLAG : 0;
}
}
}