Index: storage/browser/blob/blob_flattener.cc |
diff --git a/storage/browser/blob/blob_flattener.cc b/storage/browser/blob/blob_flattener.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1242c5b7e7e125974191e56f8f9a76ebe35724dc |
--- /dev/null |
+++ b/storage/browser/blob/blob_flattener.cc |
@@ -0,0 +1,127 @@ |
+// Copyright 2016 The Chromium 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 "storage/browser/blob/blob_flattener.h" |
+ |
+#include <limits> |
+#include <set> |
+#include <utility> |
+ |
+#include "storage/browser/blob/blob_async_transport_request_builder.h" |
+#include "storage/browser/blob/blob_data_builder.h" |
+#include "storage/browser/blob/blob_slice.h" |
+#include "storage/browser/blob/blob_storage_context.h" |
+#include "storage/browser/blob/blob_storage_registry.h" |
+#include "storage/browser/blob/shareable_blob_data_item.h" |
+#include "storage/common/data_element.h" |
+ |
+namespace storage { |
+namespace { |
+using ItemCopyEntry = InternalBlobData::ItemCopyEntry; |
+ |
+bool IsBytes(DataElement::Type type) { |
+ return type == DataElement::TYPE_BYTES || |
+ type == DataElement::TYPE_BYTES_DESCRIPTION; |
+} |
+ |
+} // namespace |
+ |
+// static |
+BlobFlattener::BlobFlattener(const BlobDataBuilder& input_builder, |
+ InternalBlobData* output_blob, |
+ BlobStorageRegistry* registry) { |
+ const std::vector<scoped_refptr<BlobDataItem>>& transport_items = |
+ input_builder.items_; |
+ const std::string& uuid = input_builder.uuid_; |
+ |
+ std::set<std::string> dependent_blob_uuids; |
+ bool contains_pending_content = false; |
+ for (scoped_refptr<BlobDataItem> transport_item : transport_items) { |
+ DataElement::Type type = transport_item->type(); |
+ contains_pending_content |= type == DataElement::TYPE_BYTES_DESCRIPTION; |
+ |
+ if (IsBytes(type)) { |
+ DCHECK_NE(0 + DataElement::kUnknownSize, transport_item->length()); |
+ memory_needed += transport_item->length(); |
+ total_size += transport_item->length(); |
+ output_blob->AppendSharedBlobItem( |
+ uuid, new ShareableBlobDataItem(std::move(transport_item))); |
+ continue; |
+ } |
+ if (type == DataElement::TYPE_BLOB) { |
+ InternalBlobData* ref_entry = |
+ registry->GetEntry(transport_item->blob_uuid()); |
+ |
+ if (!ref_entry || transport_item->blob_uuid() == uuid) { |
+ status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; |
+ return; |
+ } |
+ |
+ if (BlobStatusIsError(ref_entry->status())) { |
+ status = BlobStatus::ERR_REFERENCED_BLOB_BROKEN; |
+ return; |
+ } |
+ |
+ if (dependent_blob_uuids.find(transport_item->blob_uuid()) == |
+ dependent_blob_uuids.end()) { |
+ dependent_blobs.push_back( |
+ std::make_pair(transport_item->blob_uuid(), ref_entry)); |
+ dependent_blob_uuids.insert(transport_item->blob_uuid()); |
+ } |
+ |
+ uint64_t length = transport_item->length() == DataElement::kUnknownSize |
+ ? ref_entry->total_size() |
+ : transport_item->length(); |
+ total_size += length; |
+ |
+ // If we're referencing the whole blob, then we don't need to slice. |
+ if (transport_item->offset() == 0 && length == ref_entry->total_size()) { |
+ for (const auto& shareable_item : ref_entry->items()) { |
+ output_blob->AppendSharedBlobItem(uuid, shareable_item); |
+ } |
+ continue; |
+ } |
+ |
+ // Validate our reference has good offset & length. |
+ if (transport_item->offset() + transport_item->length() > |
+ ref_entry->total_size()) { |
+ status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS; |
+ return; |
+ } |
+ |
+ BlobSlice slice(*ref_entry, transport_item->offset(), |
+ transport_item->length()); |
+ |
+ if (slice.first_source_item) { |
+ copies.push_back(ItemCopyEntry(slice.first_source_item, |
+ slice.first_item_slice_offset, |
+ slice.dest_items.front())); |
+ } |
+ if (slice.last_source_item) { |
+ copies.push_back( |
+ ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back())); |
+ } |
+ |
+ memory_needed += slice.copying_memory_size; |
+ for (auto& shareable_item : slice.dest_items) { |
+ output_blob->AppendSharedBlobItem(uuid, std::move(shareable_item)); |
+ } |
+ continue; |
+ } |
+ if (type == DataElement::TYPE_FILE) { |
+ contains_pending_content |= |
+ transport_item->path().value() == |
+ BlobDataBuilder::kAppendFutureFileTemporaryFileName; |
+ } |
+ total_size += transport_item->length(); |
+ output_blob->AppendSharedBlobItem( |
+ uuid, new ShareableBlobDataItem(std::move(transport_item))); |
+ } |
+ status = contains_pending_content ? BlobStatus::PENDING_DATA_POPULATION |
+ : BlobStatus::DONE; |
+} |
+ |
+BlobFlattener::~BlobFlattener() {} |
+ |
+} // namespace storage |