Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Unified Diff: webkit/fileapi/media/picasa/pmp_column_reader.cc

Issue 12704024: Simple PMP reader to parse Picasa's metadata (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove unused constant. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webkit/fileapi/media/picasa/pmp_column_reader.cc
diff --git a/webkit/fileapi/media/picasa/pmp_column_reader.cc b/webkit/fileapi/media/picasa/pmp_column_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5b207167fbaeab5e8bcc162f8d665852ab505697
--- /dev/null
+++ b/webkit/fileapi/media/picasa/pmp_column_reader.cc
@@ -0,0 +1,205 @@
+// Copyright 2013 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 "webkit/fileapi/media/picasa/pmp_column_reader.h"
+
+#include <cstring>
+
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+#include "webkit/fileapi/media/picasa/pmp_constants.h"
+
+namespace fileapi {
+
+namespace {
+
+const size_t kPmpMaxFilesize = 50*1024*1024; // Maximum of 50 MB.
+
+} // namespace
+
+PmpColumnReader::PmpColumnReader()
+ : data_(NULL),
+ length_(0),
+ rows_(0),
+ strings_(),
+ field_type_(kPmpFieldTypeInvalid) { }
+
+PmpColumnReader::~PmpColumnReader() { }
+
+bool PmpColumnReader::InitFromFile(const base::FilePath& filepath,
+ uint32* rows_read) {
+ base::MemoryMappedFile file;
vandebo (ex-Chrome) 2013/03/29 21:35:07 So using a memory mapped file means you need enoug
vandebo (ex-Chrome) 2013/03/29 21:35:07 Add a DCHECK that we're on the FILE thread?
tommycli 2013/04/01 22:19:18 Done.
tommycli 2013/04/01 22:19:18 Done.
+
+ if(!file.Initialize(filepath) ||
vandebo (ex-Chrome) 2013/03/29 21:35:07 nit: s/if(/if (/g
tommycli 2013/04/01 22:19:18 Done.
+ file.length() < kPmpHeaderSize ||
+ file.length() > kPmpMaxFilesize ||
+ file.data() == NULL) {
+ return false;
+ }
+
+ length_ = file.length();
+ data_.reset(new uint8[length_]);
+ std::copy(file.data(), file.data() + length_, data_.get());
+
+ return ParseData(rows_read);
+}
+
+bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row);
+
+ if(field_type_ == kPmpFieldTypeString && row < rows_) {
vandebo (ex-Chrome) 2013/03/29 21:35:07 We like early exits of functions, especially when
tommycli 2013/04/01 22:19:18 Nice. That's definitely an improvement.
+ *result = strings_[row];
+ return true;
+ }
+
+ return false;
+}
+
+bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row*sizeof(uint32));
vandebo (ex-Chrome) 2013/03/29 21:35:07 nit: space around math operators: row * sizeof()
tommycli 2013/04/01 22:19:18 Done.
+
+ if(field_type_ == kPmpFieldTypeUInt32 && row < rows_) {
+ *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+ }
+
+ return false;
+}
+
+bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row*sizeof(double));
+
+ if(field_type_ == kPmpFieldTypeDouble64 && row < rows_) {
+ *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+ }
+
+ return false;
+}
+
+bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row*sizeof(uint8));
+
+ if(field_type_ == kPmpFieldTypeUInt8 && row < rows_) {
+ *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+ }
+
+ return false;
+}
+
+bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row*sizeof(uint64));
+
+ if(field_type_ == kPmpFieldTypeUInt64 && row < rows_) {
+ *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+ }
+
+ return false;
+}
+
+bool PmpColumnReader::ParseData(uint32* rows_read) {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GE(length_, kPmpHeaderSize);
+
+ // Check all magic bytes.
+ if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 ||
+ memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 ||
+ memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 ||
+ memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) {
+ return false;
+ }
+
+ // Read the field type
vandebo (ex-Chrome) 2013/03/29 21:35:07 nit: remove redundant comment.
tommycli 2013/04/01 22:19:18 Done.
+ field_type_ = *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset]));
+
+ // Verify if field type matches second declaration
+ if (field_type_ != *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset])))
+ return false;
+
+ // Read the number of rows expected.
vandebo (ex-Chrome) 2013/03/29 21:35:07 nit: redundant comment.
tommycli 2013/04/01 22:19:18 Done.
+ rows_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset]));
+
+ bool parse_success = false;
+
vandebo (ex-Chrome) 2013/03/29 21:35:07 nit: extra line.
tommycli 2013/04/01 22:19:18 Done.
+ switch (field_type_) {
+ case kPmpFieldTypeString:
+ parse_success = IndexStrings();
+ break;
+ case kPmpFieldTypeUInt32:
+ parse_success = ValidatePrimitiveArrayLength<uint32>();
+ break;
+ case kPmpFieldTypeDouble64:
+ parse_success = ValidatePrimitiveArrayLength<double>();
+ break;
+ case kPmpFieldTypeUInt8:
+ parse_success = ValidatePrimitiveArrayLength<uint8>();
+ break;
+ case kPmpFieldTypeUInt64:
+ parse_success = ValidatePrimitiveArrayLength<uint64>();
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ if(parse_success) {
vandebo (ex-Chrome) 2013/03/29 21:35:07 if (parse_success && rows_read) *rows_read = row
tommycli 2013/04/01 22:19:18 That's ninja.
+ // Set the number of rows read. Though it's not valid unless we return true.
+ if(rows_read != NULL)
+ *rows_read = rows_;
+ return true;
+ }
+
+ return false;
+}
+
+bool PmpColumnReader::IndexStrings() {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GE(length_, kPmpHeaderSize);
+
+ strings_.clear();
vandebo (ex-Chrome) 2013/03/29 21:35:07 not needed
tommycli 2013/04/01 22:19:18 Done.
+ strings_.reserve(rows_);
+
+ size_t bytes_parsed = kPmpHeaderSize;
+ const uint8* itr = data_.get() + kPmpHeaderSize;
vandebo (ex-Chrome) 2013/03/29 21:35:07 nit: We usually use it for iterators... though thi
tommycli 2013/04/01 22:19:18 Done.
+
+ while (strings_.size() < rows_) {
+ const uint8* string_end = static_cast<const uint8*>(
+ memchr(itr, '\0', length_ - bytes_parsed));
+
+ // Fail if cannot find null termination. String runs on past file end.
+ if(string_end == NULL)
+ return false;
+
+ // Length of string. (+1 to include the termination character).
+ ptrdiff_t length_in_bytes = string_end - itr + 1;
vandebo (ex-Chrome) 2013/03/29 21:35:07 Any word back from Picasa folks on the string enco
tommycli 2013/04/01 22:19:18 I fwded you email from them.
vandebo (ex-Chrome) 2013/04/02 18:10:55 You got an non-answer back. Can you peek into the
tommycli 2013/04/02 21:12:36 Done.
+
+ strings_.push_back(reinterpret_cast<const char*>(itr));
+ itr += length_in_bytes;
+ bytes_parsed += length_in_bytes;
+ }
+
+ // This means the file has more bytes at the end we haven't parsed.
vandebo (ex-Chrome) 2013/03/29 21:35:07 redundant comment.
tommycli 2013/04/01 22:19:18 Done.
+ if(bytes_parsed != length_)
+ return false;
vandebo (ex-Chrome) 2013/03/29 21:35:07 return bytes_parsed == length_;
tommycli 2013/04/01 22:19:18 Done.
+
+ return true;
+}
+
+template<class T>
+bool PmpColumnReader::ValidatePrimitiveArrayLength() {
vandebo (ex-Chrome) 2013/03/29 21:35:07 I think you can inline this template without much
tommycli 2013/04/01 22:19:18 Done.
+ size_t body_length = length_ - kPmpHeaderSize;
+ size_t expected_body_length = rows_ * sizeof(T);
+
+ return body_length == expected_body_length;
+}
+
+} // namespace

Powered by Google App Engine
This is Rietveld 408576698