summaryrefslogtreecommitdiffstats
path: root/o3d/import/cross/tar_generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/import/cross/tar_generator.cc')
-rw-r--r--o3d/import/cross/tar_generator.cc195
1 files changed, 195 insertions, 0 deletions
diff --git a/o3d/import/cross/tar_generator.cc b/o3d/import/cross/tar_generator.cc
new file mode 100644
index 0000000..019ec0e
--- /dev/null
+++ b/o3d/import/cross/tar_generator.cc
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "import/cross/memory_buffer.h"
+#include "import/cross/tar_generator.h"
+
+using std::string;
+
+namespace o3d {
+
+const int kMaxFilenameSize = 100;
+
+const int kFileNameOffset = 0;
+const int kFileModeOffset = 100;
+const int kUserIDOffset = 108;
+const int kGroupIDOffset = 116;
+const int kFileSizeOffset = 124;
+const int kModifyTimeOffset = 136;
+const int kHeaderCheckSumOffset = 148;
+const int kLinkFlagOffset = 156;
+const int kMagicOffset = 257;
+const int kUserNameOffset = 265;
+const int kGroupNameOffset = 297;
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void TarGenerator::AddFile(const String &file_name, size_t file_size) {
+ AddDirectoryEntryIfNeeded(file_name);
+ AddEntry(file_name, file_size, false);
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void TarGenerator::AddDirectory(const String &file_name) {
+ AddEntry(file_name, 0, true);
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// We keep a map so we add a particular directory entry only once
+void TarGenerator::AddDirectoryEntryIfNeeded(const String &file_name) {
+ string::size_type index = file_name.find_last_of('/');
+
+ if (index != string::npos) {
+ String dir_name = file_name.substr(0, index + 1); // keep the '/' at end
+ if (!directory_map_[dir_name]) {
+ directory_map_[dir_name] = true;
+ AddDirectory(dir_name);
+ }
+ }
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void TarGenerator::AddEntry(const String &file_name,
+ size_t file_size,
+ bool is_directory) {
+ // first write out last data block from last file (if any)
+ FlushDataBuffer(true);
+
+ // next fill out a tar header
+ MemoryBuffer<uint8> header(TAR_HEADER_SIZE); // initializes header to zeroes
+
+ // leave room for NULL-termination
+ uint8 *h = header;
+ char *p = reinterpret_cast<char*>(h);
+
+ // File name
+ strncpy(p, file_name.c_str(), kMaxFilenameSize - 1);
+
+ // File mode
+ snprintf(p + kFileModeOffset, 8, "%07o", is_directory ? 0755 : 0644);
+
+ // UserID
+ snprintf(p + kUserIDOffset, 8, "%07o", 0765);
+
+ // GroupID
+ snprintf(p + kGroupIDOffset, 8, "%07o", 0204);
+
+ // File size
+ snprintf(p + kFileSizeOffset, 12, "%011o", file_size);
+
+ // Modification time
+ // TODO: write the correct current time here...
+ snprintf(p + kModifyTimeOffset, 12, "%07o", 011131753141);
+
+ // Initialize Header checksum so check sum can be computed
+ // by ComputeCheckSum() which will fill in the value here
+ memset(p + kHeaderCheckSumOffset, 32, 8);
+
+ // We only support ordinary files and directories, which is fine
+ // for our use case
+ int link_flag = is_directory ? '5' : '0';
+ p[kLinkFlagOffset] = link_flag;
+
+ // Magic offset
+ snprintf(p + kMagicOffset, 8, "ustar ");
+
+ // User name
+ snprintf(p + kUserNameOffset, 32, "guest");
+
+ // Group name
+ snprintf(p + kGroupNameOffset, 32, "staff");
+
+
+ // This has to be done at the end
+ ComputeCheckSum(header);
+
+ if (callback_client_) {
+ MemoryReadStream stream(header, TAR_HEADER_SIZE);
+ callback_client_->ProcessBytes(&stream, TAR_HEADER_SIZE);
+ }
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void TarGenerator::ComputeCheckSum(uint8 *header) {
+ unsigned int checksum = 0;
+ for (int i = 0; i < TAR_HEADER_SIZE; ++i) {
+ checksum += header[i];
+ }
+ snprintf(reinterpret_cast<char*>(header + kHeaderCheckSumOffset),
+ 8, "%06o\0\0", checksum);
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int TarGenerator::AddFileBytes(MemoryReadStream *stream, size_t n) {
+ if (callback_client_) {
+ FlushDataBuffer(false); // flush any old data sitting around
+
+ // we'll directly write as much of the data as we can, writing full blocks
+ int nblocks = n / TAR_BLOCK_SIZE;
+ size_t direct_bytes_to_write = nblocks * TAR_BLOCK_SIZE;
+ if (direct_bytes_to_write > 0) {
+ callback_client_->ProcessBytes(stream, direct_bytes_to_write);
+ }
+
+ // now, buffer the remainder (less than TAR_BLOCK_SIZE)
+ size_t remainder = n - direct_bytes_to_write;
+
+ const uint8 *p = stream->GetDirectMemoryPointer();
+ data_buffer_stream_.Write(p, remainder);
+ stream->Skip(remainder);
+ }
+
+ return 0;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void TarGenerator::FlushDataBuffer(bool flush_padding_zeroes) {
+ size_t buffered_bytes = data_buffer_stream_.GetStreamPosition();
+ if (buffered_bytes > 0 && callback_client_) {
+ // write out the complete data block (which may be zero padded at the end)
+ size_t bytes_to_flush =
+ flush_padding_zeroes ? TAR_BLOCK_SIZE : buffered_bytes;
+
+ MemoryReadStream stream(data_block_buffer_, bytes_to_flush);
+ callback_client_->ProcessBytes(&stream, bytes_to_flush);
+
+ // get ready to start buffering next data block
+ data_block_buffer_.Clear();
+ data_buffer_stream_.Seek(0);
+ }
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void TarGenerator::Finalize() {
+ FlushDataBuffer(true);
+}
+
+} // namespace o3d