summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSen Jiang <senj@google.com>2016-05-09 16:43:34 -0700
committerSen Jiang <senj@google.com>2017-02-02 14:42:45 -0800
commit716d569273ef2aeacfe7555f60f7784b2366225d (patch)
treebe33f4bfa1310cb51e9840a3406acd1f4e79e2ac
parent02416b52d7890edace797b5bc6902d61601a30b5 (diff)
downloadbsdiff-716d569273ef2aeacfe7555f60f7784b2366225d.tar.gz
Provide interface for in memory bspatch.
Renamed existing MemoryFile to BufferFile, and added a read only MemoryFile to provide file interface to read file data already in memory without extra copy (extra memory usage). Added write only SinkFile to provide sink function support used in applypatch. It will enable imgpatch the ability to stream output. Test: mma Bug: 26982501 Change-Id: I025ce4064c9f46623dd73f24d30e21e88f08a292
-rw-r--r--Android.mk6
-rw-r--r--Makefile6
-rw-r--r--bspatch.cc222
-rw-r--r--bspatch.h12
-rw-r--r--buffer_file.cc49
-rw-r--r--buffer_file.h41
-rw-r--r--memory_file.cc38
-rw-r--r--memory_file.h20
-rw-r--r--sink_file.cc33
-rw-r--r--sink_file.h41
10 files changed, 341 insertions, 127 deletions
diff --git a/Android.mk b/Android.mk
index 12ee3e8..1073005 100644
--- a/Android.mk
+++ b/Android.mk
@@ -37,10 +37,12 @@ bsdiff_src_files := \
# "bspatch" program.
bspatch_src_files := \
bspatch.cc \
+ buffer_file.cc \
extents.cc \
extents_file.cc \
file.cc \
- memory_file.cc
+ memory_file.cc \
+ sink_file.cc
# Unit test files.
bsdiff_common_unittests := \
@@ -57,6 +59,7 @@ LOCAL_MODULE := libbspatch
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(bspatch_src_files)
LOCAL_CFLAGS := $(bsdiff_common_cflags)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
LOCAL_STATIC_LIBRARIES := $(bsdiff_common_static_libs)
include $(BUILD_STATIC_LIBRARY)
@@ -76,6 +79,7 @@ LOCAL_MODULE := libbspatch
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(bspatch_src_files)
LOCAL_CFLAGS := $(bsdiff_common_cflags)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
LOCAL_STATIC_LIBRARIES := $(bsdiff_common_static_libs)
include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/Makefile b/Makefile
index fbfe56a..4214637 100644
--- a/Makefile
+++ b/Makefile
@@ -32,10 +32,12 @@ BSDIFF_OBJS = \
BSPATCH_LIBS = -lbz2
BSPATCH_OBJS = \
bspatch.o \
+ buffer_file.o \
extents.o \
extents_file.o \
file.o \
- memory_file.o
+ memory_file.o \
+ sink_file.o
UNITTEST_LIBS = -lgmock -lgtest -lpthread
UNITTEST_OBJS = \
@@ -66,6 +68,7 @@ bspatch.o: bspatch.cc bspatch.h extents.h extents_file.h file_interface.h \
file.h
bspatch_main.o: bspatch_main.cc bspatch.h
bspatch_unittest.o: bspatch_unittest.cc bspatch.h test_utils.h
+buffer_file.o: buffer_file.cc buffer_file.h file_interface.h bspatch.h
extents.o: extents.cc extents.h extents_file.h file_interface.h
extents_file.o: extents_file.cc extents_file.h file_interface.h
extents_file_unittest.o: extents_file_unittest.cc extents_file.h \
@@ -74,6 +77,7 @@ extents_unittest.o: extents_unittest.cc extents.h extents_file.h \
file_interface.h
file.o: file.cc file.h file_interface.h
memory_file.o: memory_file.cc memory_file.h file_interface.h
+sink_file.o: sink_file.cc sink_file.h file_interface.h
testrunner.o: testrunner.cc
test_utils.o: test_utils.cc test_utils.h
diff --git a/bspatch.cc b/bspatch.cc
index 550c6c7..693213a 100644
--- a/bspatch.cc
+++ b/bspatch.cc
@@ -46,15 +46,17 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:
#include <limits>
#include <vector>
+#include "buffer_file.h"
#include "extents.h"
#include "extents_file.h"
#include "file.h"
#include "file_interface.h"
#include "memory_file.h"
+#include "sink_file.h"
namespace {
-int64_t ParseInt64(u_char* buf) {
+int64_t ParseInt64(const u_char* buf) {
int64_t y;
y = buf[7] & 0x7F;
@@ -79,22 +81,28 @@ int64_t ParseInt64(u_char* buf) {
return y;
}
-bool ReadBZ2(BZFILE* pfbz2, uint8_t* data, size_t size) {
- int bz2err;
- size_t lenread = BZ2_bzRead(&bz2err, pfbz2, data, size);
- if (lenread < size || (bz2err != BZ_OK && bz2err != BZ_STREAM_END))
- return false;
+bool ReadBZ2(bz_stream* stream, uint8_t* data, size_t size) {
+ stream->next_out = (char*)data;
+ while (size > 0) {
+ unsigned int read_size = std::min(
+ static_cast<size_t>(std::numeric_limits<unsigned int>::max()), size);
+ stream->avail_out = read_size;
+ int bz2err = BZ2_bzDecompress(stream);
+ if (bz2err != BZ_OK && bz2err != BZ_STREAM_END)
+ return false;
+ size -= read_size - stream->avail_out;
+ }
return true;
}
bool ReadBZ2AndWriteAll(const std::unique_ptr<bsdiff::FileInterface>& file,
- BZFILE* pfbz2,
+ bz_stream* stream,
size_t size,
uint8_t* buf,
size_t buf_size) {
while (size > 0) {
size_t bytes_to_read = std::min(size, buf_size);
- if (!ReadBZ2(pfbz2, buf, bytes_to_read))
+ if (!ReadBZ2(stream, buf, bytes_to_read))
return false;
if (!WriteAll(file, buf, bytes_to_read))
return false;
@@ -107,6 +115,18 @@ bool ReadBZ2AndWriteAll(const std::unique_ptr<bsdiff::FileInterface>& file,
namespace bsdiff {
+bool ReadAll(const std::unique_ptr<FileInterface>& file,
+ uint8_t* data,
+ size_t size) {
+ size_t offset = 0, read;
+ while (offset < size) {
+ if (!file->Read(data + offset, size - offset, &read) || read == 0)
+ return false;
+ offset += read;
+ }
+ return true;
+}
+
bool WriteAll(const std::unique_ptr<FileInterface>& file,
const uint8_t* data,
size_t size) {
@@ -151,78 +171,23 @@ int bspatch(
const char* old_filename, const char* new_filename,
const char* patch_filename,
const char* old_extents, const char* new_extents) {
- FILE* f, *cpf, *dpf, *epf;
- BZFILE* cpfbz2, *dpfbz2, *epfbz2;
- int bz2err;
- ssize_t bzctrllen, bzdatalen;
- u_char header[32], buf[8];
- off_t ctrl[3];
-
- int using_extents = (old_extents != NULL || new_extents != NULL);
-
- // Open patch file.
- if ((f = fopen(patch_filename, "r")) == NULL)
- err(1, "fopen(%s)", patch_filename);
-
- // File format:
- // 0 8 "BSDIFF40"
- // 8 8 X
- // 16 8 Y
- // 24 8 sizeof(new_filename)
- // 32 X bzip2(control block)
- // 32+X Y bzip2(diff block)
- // 32+X+Y ??? bzip2(extra block)
- // with control block a set of triples (x,y,z) meaning "add x bytes
- // from oldfile to x bytes from the diff block; copy y bytes from the
- // extra block; seek forwards in oldfile by z bytes".
-
- // Read header.
- if (fread(header, 1, 32, f) < 32) {
- if (feof(f))
- errx(1, "Corrupt patch\n");
- err(1, "fread(%s)", patch_filename);
- }
-
- // Check for appropriate magic.
- if (memcmp(header, "BSDIFF40", 8) != 0)
- errx(1, "Corrupt patch\n");
-
- // Read lengths from header.
- uint64_t oldsize, newsize;
- bzctrllen = ParseInt64(header + 8);
- bzdatalen = ParseInt64(header + 16);
- int64_t signed_newsize = ParseInt64(header + 24);
- newsize = signed_newsize;
- if ((bzctrllen < 0) || (bzdatalen < 0) || (signed_newsize < 0))
+ std::unique_ptr<FileInterface> patch_file =
+ File::FOpen(patch_filename, O_RDONLY);
+ if (!patch_file)
+ err(1, "Error opening the patch filename %s", patch_filename);
+ uint64_t patch_size;
+ patch_file->GetSize(&patch_size);
+ std::vector<uint8_t> patch(patch_size);
+ if (!ReadAll(patch_file, patch.data(), patch_size))
errx(1, "Corrupt patch\n");
+ patch_file.reset();
- // Close patch file and re-open it via libbzip2 at the right places.
- if (fclose(f))
- err(1, "fclose(%s)", patch_filename);
- if ((cpf = fopen(patch_filename, "r")) == NULL)
- err(1, "fopen(%s)", patch_filename);
- if (fseek(cpf, 32, SEEK_SET))
- err(1, "fseeko(%s, %lld)", patch_filename, (long long)32);
- if ((cpfbz2 = BZ2_bzReadOpen(&bz2err, cpf, 0, 0, NULL, 0)) == NULL)
- errx(1, "BZ2_bzReadOpen, bz2err = %d", bz2err);
- if ((dpf = fopen(patch_filename, "r")) == NULL)
- err(1, "fopen(%s)", patch_filename);
- if (fseek(dpf, 32 + bzctrllen, SEEK_SET))
- err(1, "fseeko(%s, %lld)", patch_filename, (long long)(32 + bzctrllen));
- if ((dpfbz2 = BZ2_bzReadOpen(&bz2err, dpf, 0, 0, NULL, 0)) == NULL)
- errx(1, "BZ2_bzReadOpen, bz2err = %d", bz2err);
- if ((epf = fopen(patch_filename, "r")) == NULL)
- err(1, "fopen(%s)", patch_filename);
- if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
- err(1, "fseeko(%s, %lld)", patch_filename,
- (long long)(32 + bzctrllen + bzdatalen));
- if ((epfbz2 = BZ2_bzReadOpen(&bz2err, epf, 0, 0, NULL, 0)) == NULL)
- errx(1, "BZ2_bzReadOpen, bz2err = %d", bz2err);
+ int using_extents = (old_extents != NULL || new_extents != NULL);
// Open input file for reading.
std::unique_ptr<FileInterface> old_file = File::FOpen(old_filename, O_RDONLY);
if (!old_file)
- err(1, "Error opening the old filename");
+ err(1, "Error opening the old filename %s", old_filename);
std::vector<ex_t> parsed_old_extents;
if (using_extents) {
@@ -231,10 +196,6 @@ int bspatch(
old_file.reset(new ExtentsFile(std::move(old_file), parsed_old_extents));
}
- if (!old_file->GetSize(&oldsize))
- err(1, "cannot obtain the size of %s", old_filename);
- uint64_t old_file_pos = 0;
-
// Open output file for writing.
std::unique_ptr<FileInterface> new_file =
File::FOpen(new_filename, O_CREAT | O_WRONLY);
@@ -251,10 +212,91 @@ int bspatch(
if (IsOverlapping(old_filename, new_filename, parsed_old_extents,
parsed_new_extents)) {
// New and old file is overlapping, we can not stream output to new file,
- // cache it in the memory and write to the file at the end.
- new_file.reset(new MemoryFile(std::move(new_file), newsize));
+ // cache it in a buffer and write to the file at the end.
+ uint64_t newsize = ParseInt64(patch.data() + 24);
+ new_file.reset(new BufferFile(std::move(new_file), newsize));
}
+ return bspatch(old_file, new_file, patch.data(), patch_size);
+}
+
+int bspatch(const uint8_t* old_data,
+ size_t old_size,
+ const uint8_t* patch_data,
+ size_t patch_size,
+ const sink_func& sink) {
+ std::unique_ptr<FileInterface> old_file(new MemoryFile(old_data, old_size));
+ std::unique_ptr<FileInterface> new_file(new SinkFile(sink));
+
+ return bspatch(old_file, new_file, patch_data, patch_size);
+}
+
+int bspatch(const std::unique_ptr<FileInterface>& old_file,
+ const std::unique_ptr<FileInterface>& new_file,
+ const uint8_t* patch_data,
+ size_t patch_size) {
+ int bz2err;
+ u_char buf[8];
+ off_t ctrl[3];
+
+ // File format:
+ // 0 8 "BSDIFF40"
+ // 8 8 X
+ // 16 8 Y
+ // 24 8 sizeof(new_filename)
+ // 32 X bzip2(control block)
+ // 32+X Y bzip2(diff block)
+ // 32+X+Y ??? bzip2(extra block)
+ // with control block a set of triples (x,y,z) meaning "add x bytes
+ // from oldfile to x bytes from the diff block; copy y bytes from the
+ // extra block; seek forwards in oldfile by z bytes".
+
+ // Check for appropriate magic.
+ if (memcmp(patch_data, "BSDIFF40", 8) != 0)
+ errx(1, "Corrupt patch\n");
+
+ // Read lengths from header.
+ uint64_t oldsize, newsize;
+ int64_t ctrl_len = ParseInt64(patch_data + 8);
+ int64_t data_len = ParseInt64(patch_data + 16);
+ int64_t signed_newsize = ParseInt64(patch_data + 24);
+ newsize = signed_newsize;
+ if ((ctrl_len < 0) || (data_len < 0) || (signed_newsize < 0) ||
+ (32 + ctrl_len + data_len > static_cast<int64_t>(patch_size)))
+ errx(1, "Corrupt patch\n");
+
+ bz_stream cstream;
+ cstream.next_in = (char*)patch_data + 32;
+ cstream.avail_in = ctrl_len;
+ cstream.bzalloc = nullptr;
+ cstream.bzfree = nullptr;
+ cstream.opaque = nullptr;
+ if ((bz2err = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK)
+ errx(1, "failed to bzinit control stream (%d)\n", bz2err);
+
+ bz_stream dstream;
+ dstream.next_in = (char*)patch_data + 32 + ctrl_len;
+ dstream.avail_in = data_len;
+ dstream.bzalloc = nullptr;
+ dstream.bzfree = nullptr;
+ dstream.opaque = nullptr;
+ if ((bz2err = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK)
+ errx(1, "failed to bzinit diff stream (%d)\n", bz2err);
+
+ bz_stream estream;
+ estream.next_in = (char*)patch_data + 32 + ctrl_len + data_len;
+ estream.avail_in = patch_size - (32 + ctrl_len + data_len);
+ estream.bzalloc = nullptr;
+ estream.bzfree = nullptr;
+ estream.opaque = nullptr;
+ if ((bz2err = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK)
+ errx(1, "failed to bzinit extra stream (%d)\n", bz2err);
+
+ uint64_t old_file_pos = 0;
+
+ if (!old_file->GetSize(&oldsize))
+ err(1, "cannot obtain the size of old file");
+
// The oldpos can be negative, but the new pos is only incremented linearly.
int64_t oldpos = 0;
uint64_t newpos = 0;
@@ -263,7 +305,7 @@ int bspatch(
int64_t i;
// Read control data.
for (i = 0; i <= 2; i++) {
- if (!ReadBZ2(cpfbz2, buf, 8))
+ if (!ReadBZ2(&cstream, buf, 8))
errx(1, "Corrupt patch\n");
ctrl[i] = ParseInt64(buf);
}
@@ -281,7 +323,7 @@ int bspatch(
if ((i = oldpos) < 0) {
// Write diff block directly to new file without adding old data,
// because we will skip part where |oldpos| < 0.
- if (!ReadBZ2AndWriteAll(new_file, dpfbz2, -i, new_buf.data(),
+ if (!ReadBZ2AndWriteAll(new_file, &dstream, -i, new_buf.data(),
new_buf.size()))
errx(1, "Error during ReadBZ2AndWriteAll()");
@@ -303,7 +345,7 @@ int bspatch(
if (!read_bytes)
errx(1, "EOF reached while reading from input file");
// Read same amount of bytes from diff block
- if (!ReadBZ2(dpfbz2, new_buf.data(), read_bytes))
+ if (!ReadBZ2(&dstream, new_buf.data(), read_bytes))
errx(1, "Corrupt patch\n");
// new_buf already has data from diff block, adds old data to it.
for (size_t k = 0; k < read_bytes; k++)
@@ -320,7 +362,7 @@ int bspatch(
if (oldpos > static_cast<int64_t>(oldsize)) {
// Write diff block directly to new file without adding old data,
// because we skipped part where |oldpos| > oldsize.
- if (!ReadBZ2AndWriteAll(new_file, dpfbz2, oldpos - oldsize,
+ if (!ReadBZ2AndWriteAll(new_file, &dstream, oldpos - oldsize,
new_buf.data(), new_buf.size()))
errx(1, "Error during ReadBZ2AndWriteAll()");
}
@@ -330,7 +372,7 @@ int bspatch(
errx(1, "Corrupt patch\n");
// Read extra block.
- if (!ReadBZ2AndWriteAll(new_file, epfbz2, ctrl[1], new_buf.data(),
+ if (!ReadBZ2AndWriteAll(new_file, &estream, ctrl[1], new_buf.data(),
new_buf.size()))
errx(1, "Error during ReadBZ2AndWriteAll()");
@@ -343,14 +385,12 @@ int bspatch(
old_file->Close();
// Clean up the bzip2 reads.
- BZ2_bzReadClose(&bz2err, cpfbz2);
- BZ2_bzReadClose(&bz2err, dpfbz2);
- BZ2_bzReadClose(&bz2err, epfbz2);
- if (fclose(cpf) || fclose(dpf) || fclose(epf))
- err(1, "fclose(%s)", patch_filename);
+ BZ2_bzDecompressEnd(&cstream);
+ BZ2_bzDecompressEnd(&dstream);
+ BZ2_bzDecompressEnd(&estream);
if (!new_file->Close())
- err(1, "Error closing new file %s", new_filename);
+ err(1, "Error closing new file");
return 0;
}
diff --git a/bspatch.h b/bspatch.h
index 3de2874..2507879 100644
--- a/bspatch.h
+++ b/bspatch.h
@@ -5,6 +5,7 @@
#ifndef _BSDIFF_BSPATCH_H_
#define _BSDIFF_BSPATCH_H_
+#include <functional>
#include <memory>
#include <vector>
@@ -18,6 +19,17 @@ int bspatch(const char* old_filename,
const char* old_extents,
const char* new_extents);
+int bspatch(const uint8_t* old_data,
+ size_t old_size,
+ const uint8_t* patch_data,
+ size_t patch_size,
+ const std::function<size_t(const uint8_t*, size_t)>& sink);
+
+int bspatch(const std::unique_ptr<FileInterface>& old_file,
+ const std::unique_ptr<FileInterface>& new_file,
+ const uint8_t* patch_data,
+ size_t patch_size);
+
bool WriteAll(const std::unique_ptr<FileInterface>& file,
const uint8_t* data,
size_t size);
diff --git a/buffer_file.cc b/buffer_file.cc
new file mode 100644
index 0000000..1e1c213
--- /dev/null
+++ b/buffer_file.cc
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "buffer_file.h"
+
+#include "bspatch.h"
+
+namespace bsdiff {
+
+BufferFile::BufferFile(std::unique_ptr<FileInterface> file, size_t size)
+ : file_(std::move(file)) {
+ buffer_.reserve(size);
+}
+
+BufferFile::~BufferFile() {
+ Close();
+}
+
+bool BufferFile::Read(void* buf, size_t count, size_t* bytes_read) {
+ return false;
+}
+
+bool BufferFile::Write(const void* buf, size_t count, size_t* bytes_written) {
+ const uint8_t* data = static_cast<const uint8_t*>(buf);
+ buffer_.insert(buffer_.end(), data, data + count);
+ *bytes_written = count;
+ return true;
+}
+
+bool BufferFile::Seek(off_t pos) {
+ return false;
+}
+
+bool BufferFile::Close() {
+ if (!WriteAll(file_, buffer_.data(), buffer_.size()))
+ return false;
+ // Prevent writing |buffer_| to |file_| again if Close() is called more than
+ // once.
+ buffer_.clear();
+ return file_->Close();
+}
+
+bool BufferFile::GetSize(uint64_t* size) {
+ *size = buffer_.size();
+ return true;
+}
+
+} // namespace bsdiff
diff --git a/buffer_file.h b/buffer_file.h
new file mode 100644
index 0000000..514225b
--- /dev/null
+++ b/buffer_file.h
@@ -0,0 +1,41 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _BSDIFF_BUFFER_FILE_H_
+#define _BSDIFF_BUFFER_FILE_H_
+
+#include <memory>
+#include <vector>
+
+#include "file_interface.h"
+
+namespace bsdiff {
+
+class BufferFile : public FileInterface {
+ public:
+ // Creates a write only BufferFile based on the underlying |file| passed.
+ // The BufferFile will cache all the write in a buffer and write everything
+ // to |file| at once upon closing. Read and Seek are not supported.
+ // |size| should be the estimated total file size, it is used to reserve
+ // buffer space.
+ BufferFile(std::unique_ptr<FileInterface> file, size_t size);
+
+ ~BufferFile() override;
+
+ // FileInterface overrides.
+ bool Read(void* buf, size_t count, size_t* bytes_read) override;
+ bool Write(const void* buf, size_t count, size_t* bytes_written) override;
+ bool Seek(off_t pos) override;
+ bool Close() override;
+ bool GetSize(uint64_t* size) override;
+
+ private:
+ // The underlying FileInterace instance.
+ std::unique_ptr<FileInterface> file_ = nullptr;
+ std::vector<uint8_t> buffer_;
+};
+
+} // namespace bsdiff
+
+#endif // _BSDIFF_BUFFER_FILE_H_
diff --git a/memory_file.cc b/memory_file.cc
index 59e2c7d..ec179b9 100644
--- a/memory_file.cc
+++ b/memory_file.cc
@@ -4,45 +4,39 @@
#include "memory_file.h"
-#include "bspatch.h"
+#include <algorithm>
+#include <string.h>
namespace bsdiff {
-MemoryFile::MemoryFile(std::unique_ptr<FileInterface> file, size_t size)
- : file_(std::move(file)) {
- buffer_.reserve(size);
-}
-
-MemoryFile::~MemoryFile() {
- Close();
-}
+MemoryFile::MemoryFile(const uint8_t* data, size_t size)
+ : data_(data), size_(size) {}
bool MemoryFile::Read(void* buf, size_t count, size_t* bytes_read) {
- return false;
+ count = std::min(count, static_cast<size_t>(size_ - offset_));
+ memcpy(buf, data_ + offset_, count);
+ offset_ += count;
+ *bytes_read = count;
+ return true;
}
bool MemoryFile::Write(const void* buf, size_t count, size_t* bytes_written) {
- const uint8_t* data = static_cast<const uint8_t*>(buf);
- buffer_.insert(buffer_.end(), data, data + count);
- *bytes_written = count;
- return true;
+ return false;
}
bool MemoryFile::Seek(off_t pos) {
- return false;
+ if (pos > static_cast<off_t>(size_) || pos < 0)
+ return false;
+ offset_ = pos;
+ return true;
}
bool MemoryFile::Close() {
- if (!WriteAll(file_, buffer_.data(), buffer_.size()))
- return false;
- // Prevent writing |buffer_| to |file_| again if Close() is called more than
- // once.
- buffer_.clear();
- return file_->Close();
+ return true;
}
bool MemoryFile::GetSize(uint64_t* size) {
- *size = buffer_.size();
+ *size = size_;
return true;
}
diff --git a/memory_file.h b/memory_file.h
index 3e80b8a..2833649 100644
--- a/memory_file.h
+++ b/memory_file.h
@@ -6,7 +6,6 @@
#define _BSDIFF_MEMORY_FILE_H_
#include <memory>
-#include <vector>
#include "file_interface.h"
@@ -14,14 +13,12 @@ namespace bsdiff {
class MemoryFile : public FileInterface {
public:
- // Creates a MemoryFile based on the underlying |file| passed. The MemoryFile
- // will cache all the write in memory and write it to to |file| when it's
- // closed. MemoryFile does not support read and seek.
- // |size| should be the estimated total file size, it is used to reserve
- // buffer space.
- MemoryFile(std::unique_ptr<FileInterface> file, size_t size);
+ // Creates a read only MemoryFile based on the underlying |data| passed.
+ // The MemoryFile will use data starting from |data| with length of |size| as
+ // the file content. Write is not supported.
+ MemoryFile(const uint8_t* data, size_t size);
- ~MemoryFile() override;
+ ~MemoryFile() = default;
// FileInterface overrides.
bool Read(void* buf, size_t count, size_t* bytes_read) override;
@@ -31,10 +28,9 @@ class MemoryFile : public FileInterface {
bool GetSize(uint64_t* size) override;
private:
- // The underlying FileInterace instance.
- std::unique_ptr<FileInterface> file_;
-
- std::vector<uint8_t> buffer_;
+ const uint8_t* data_ = nullptr;
+ size_t size_ = 0;
+ off_t offset_ = 0;
};
} // namespace bsdiff
diff --git a/sink_file.cc b/sink_file.cc
new file mode 100644
index 0000000..5cbd3bd
--- /dev/null
+++ b/sink_file.cc
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sink_file.h"
+
+namespace bsdiff {
+
+SinkFile::SinkFile(const sink_func& sink)
+ : sink_(sink) {}
+
+bool SinkFile::Read(void* buf, size_t count, size_t* bytes_read) {
+ return false;
+}
+
+bool SinkFile::Write(const void* buf, size_t count, size_t* bytes_written) {
+ *bytes_written = sink_(static_cast<const uint8_t*>(buf), count);
+ return true;
+}
+
+bool SinkFile::Seek(off_t pos) {
+ return false;
+}
+
+bool SinkFile::Close() {
+ return true;
+}
+
+bool SinkFile::GetSize(uint64_t* size) {
+ return false;
+}
+
+} // namespace bsdiff
diff --git a/sink_file.h b/sink_file.h
new file mode 100644
index 0000000..b2ce33f
--- /dev/null
+++ b/sink_file.h
@@ -0,0 +1,41 @@
+// Copyright 2016 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef _BSDIFF_SINK_FILE_H_
+#define _BSDIFF_SINK_FILE_H_
+
+#include <stdint.h>
+
+#include <functional>
+
+#include "file_interface.h"
+
+using sink_func = std::function<size_t(const uint8_t*, size_t)>;
+
+namespace bsdiff {
+
+class SinkFile : public FileInterface {
+ public:
+ // Creates a SinkFile based on the underlying |sink| function passed.
+ // The SinkFile will call |sink| function upon write.
+ // Read, Seek and GetSize are not supported.
+ explicit SinkFile(const sink_func& sink);
+
+ ~SinkFile() = default;
+
+ // FileInterface overrides.
+ bool Read(void* buf, size_t count, size_t* bytes_read) override;
+ bool Write(const void* buf, size_t count, size_t* bytes_written) override;
+ bool Seek(off_t pos) override;
+ bool Close() override;
+ bool GetSize(uint64_t* size) override;
+
+ private:
+ // The sink() function used to write data.
+ const sink_func& sink_;
+};
+
+} // namespace bsdiff
+
+#endif // _BSDIFF_SINK_FILE_H_