Implement ZipWriter for quickly writing ZipFiles.
The ZipWriter implementation exposes a stateful interface that allows
bytes of data to be streamed in as they arrive. ZipEntries can be
compressed and/or aligned on a 32-bit boundary for mmapping at runtime.
Change-Id: I43ac9e661aa5022f00d9e12b247c4314d61c441c
diff --git a/zip_writer_test.cc b/zip_writer_test.cc
new file mode 100644
index 0000000..5269730
--- /dev/null
+++ b/zip_writer_test.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "ziparchive/zip_archive.h"
+#include "ziparchive/zip_writer.h"
+
+#include <base/test_utils.h>
+#include <gtest/gtest.h>
+#include <memory>
+
+struct zipwriter : public ::testing::Test {
+ TemporaryFile* temp_file_;
+ int fd_;
+ FILE* file_;
+
+ void SetUp() override {
+ temp_file_ = new TemporaryFile();
+ fd_ = temp_file_->fd;
+ file_ = fdopen(fd_, "w");
+ ASSERT_NE(file_, nullptr);
+ }
+
+ void TearDown() override {
+ fclose(file_);
+ delete temp_file_;
+ }
+};
+
+TEST_F(zipwriter, WriteUncompressedZipWithOneFile) {
+ ZipWriter writer(file_);
+
+ const char* expected = "hello";
+
+ ASSERT_EQ(writer.StartEntry("file.txt", 0), 0);
+ ASSERT_EQ(writer.WriteBytes("he", 2), 0);
+ ASSERT_EQ(writer.WriteBytes("llo", 3), 0);
+ ASSERT_EQ(writer.FinishEntry(), 0);
+ ASSERT_EQ(writer.Finish(), 0);
+
+ ASSERT_GE(lseek(fd_, 0, SEEK_SET), 0);
+
+ ZipArchiveHandle handle;
+ ASSERT_EQ(OpenArchiveFd(fd_, "temp", &handle, false), 0);
+
+ ZipEntry data;
+ ASSERT_EQ(FindEntry(handle, ZipString("file.txt"), &data), 0);
+ EXPECT_EQ(data.compressed_length, strlen(expected));
+ EXPECT_EQ(data.uncompressed_length, strlen(expected));
+ EXPECT_EQ(data.method, kCompressStored);
+
+ char buffer[6];
+ EXPECT_EQ(ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer)),
+ 0);
+ buffer[5] = 0;
+
+ EXPECT_STREQ(expected, buffer);
+
+ CloseArchive(handle);
+}
+
+TEST_F(zipwriter, WriteUncompressedZipWithMultipleFiles) {
+ ZipWriter writer(file_);
+
+ ASSERT_EQ(writer.StartEntry("file.txt", 0), 0);
+ ASSERT_EQ(writer.WriteBytes("he", 2), 0);
+ ASSERT_EQ(writer.FinishEntry(), 0);
+
+ ASSERT_EQ(writer.StartEntry("file/file.txt", 0), 0);
+ ASSERT_EQ(writer.WriteBytes("llo", 3), 0);
+ ASSERT_EQ(writer.FinishEntry(), 0);
+
+ ASSERT_EQ(writer.StartEntry("file/file2.txt", 0), 0);
+ ASSERT_EQ(writer.FinishEntry(), 0);
+
+ ASSERT_EQ(writer.Finish(), 0);
+
+ ASSERT_GE(lseek(fd_, 0, SEEK_SET), 0);
+
+ ZipArchiveHandle handle;
+ ASSERT_EQ(OpenArchiveFd(fd_, "temp", &handle, false), 0);
+
+ char buffer[4];
+ ZipEntry data;
+
+ ASSERT_EQ(FindEntry(handle, ZipString("file.txt"), &data), 0);
+ EXPECT_EQ(data.method, kCompressStored);
+ EXPECT_EQ(data.compressed_length, 2u);
+ EXPECT_EQ(data.uncompressed_length, 2u);
+ ASSERT_EQ(ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)),
+ 0);
+ buffer[2] = 0;
+ EXPECT_STREQ("he", buffer);
+
+ ASSERT_EQ(FindEntry(handle, ZipString("file/file.txt"), &data), 0);
+ EXPECT_EQ(data.method, kCompressStored);
+ EXPECT_EQ(data.compressed_length, 3u);
+ EXPECT_EQ(data.uncompressed_length, 3u);
+ ASSERT_EQ(ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)),
+ 0);
+ buffer[3] = 0;
+ EXPECT_STREQ("llo", buffer);
+
+ ASSERT_EQ(FindEntry(handle, ZipString("file/file2.txt"), &data), 0);
+ EXPECT_EQ(data.method, kCompressStored);
+ EXPECT_EQ(data.compressed_length, 0u);
+ EXPECT_EQ(data.uncompressed_length, 0u);
+
+ CloseArchive(handle);
+}
+
+TEST_F(zipwriter, WriteUncompressedZipWithAlignedFile) {
+ ZipWriter writer(file_);
+
+ ASSERT_EQ(writer.StartEntry("align.txt", ZipWriter::kAlign32), 0);
+ ASSERT_EQ(writer.WriteBytes("he", 2), 0);
+ ASSERT_EQ(writer.FinishEntry(), 0);
+ ASSERT_EQ(writer.Finish(), 0);
+
+ ASSERT_GE(lseek(fd_, 0, SEEK_SET), 0);
+
+ ZipArchiveHandle handle;
+ ASSERT_EQ(OpenArchiveFd(fd_, "temp", &handle, false), 0);
+
+ ZipEntry data;
+ ASSERT_EQ(FindEntry(handle, ZipString("align.txt"), &data), 0);
+ EXPECT_EQ(data.offset & 0x03, 0);
+}