Chromium Code Reviews| 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..7f2521344c88b616bae19f79cbb21c1e45d66be2 |
| --- /dev/null |
| +++ b/webkit/fileapi/media/picasa/pmp_column_reader.cc |
| @@ -0,0 +1,182 @@ |
| +// 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/logging.h" |
| +#include "webkit/fileapi/media/picasa/pmp_constants.h" |
| + |
| +namespace fileapi { |
| + |
| +PmpColumnReader::PmpColumnReader(std::string column_name) |
| + : column_name_(column_name), |
| + data_(NULL), |
| + length_(0), |
| + rows_(0), |
| + strings_(), |
| + fieldsize_(0) { } |
| + |
| +PmpColumnReader::~PmpColumnReader() { } |
| + |
| +bool PmpColumnReader::ReadFromMemory(uint32* rows_read, const uint8* data, |
| + const size_t len) { |
| + if(len < kPmpHeaderSize || data == NULL) { |
|
vandebo (ex-Chrome)
2013/03/27 00:06:19
nit: omit {}'s here.
tommycli
2013/03/27 19:34:30
Done.
|
| + return false; |
| + } |
| + |
| + length_ = len; |
| + data_.reset(new uint8[length_]); |
| + std::copy(data, data + length_, data_.get()); |
| + |
| + return ParseData(rows_read); |
| +} |
| + |
| +bool PmpColumnReader::ReadString(const uint32 row, std::string* target) const { |
|
vandebo (ex-Chrome)
2013/03/27 00:06:19
const std::string*
tommycli
2013/03/27 19:34:30
I use operator= on it.
|
| + DCHECK(data_.get() != NULL); |
| + DCHECK(length_ > kPmpHeaderSize); |
| + |
| + if(row < rows_) { |
|
vandebo (ex-Chrome)
2013/03/27 00:06:19
Check the field type?
tommycli
2013/03/27 19:34:30
Done.
|
| + *target = strings_[row]; |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| +bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* target) const { |
| + return ReadPrimitive<uint32>(row, target); |
| +} |
| + |
| +bool PmpColumnReader::ReadDouble64(const uint32 row, double* target) const { |
| + return ReadPrimitive<double>(row, target); |
| +} |
| + |
| +bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* target) const { |
| + return ReadPrimitive<uint8>(row, target); |
| +} |
| + |
| +bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* target) const { |
| + return ReadPrimitive<uint64>(row, target); |
| +} |
| + |
| +template<class T> |
| +bool PmpColumnReader::ReadPrimitive(uint32 row, T* target) const { |
| + DCHECK(data_.get() != NULL); |
| + DCHECK(length_ > kPmpHeaderSize); |
| + |
| + if(sizeof(T) != fieldsize_) { |
| + return false; |
| + } |
| + |
| + if(row < rows_) { |
| + *target = *(reinterpret_cast<T*>( |
| + data_.get() + kPmpHeaderSize + row*fieldsize_)); |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| +bool PmpColumnReader::ParseData(uint32* rows_read) { |
| + DCHECK(data_.get() != NULL); |
| + DCHECK(length_ >= kPmpHeaderSize); |
| + |
| + // Check all magic bytes. |
| + if (memcmp(kPmpMagicO0S4, data_.get(), 4) != 0|| |
| + memcmp(kPmpMagicO6S2, data_.get() + 6, 2) != 0 || |
| + memcmp(kPmpMagicO8S4, data_.get() + 8, 4) != 0 || |
| + memcmp(kPmpMagicO14S2, data_.get() + 14, 2) != 0) { |
| + return false; |
| + } |
| + |
| + // Verify row field type matches. |
| + if (data_[kPmpFieldTypeFirstOffset] != data_[kPmpFieldTypeSecondOffset]) { |
| + return false; |
| + } |
| + |
| + // Read the field type and number of rows expected. |
| + uint16 field_type = data_[kPmpFieldTypeFirstOffset]; |
| + rows_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset])); |
| + |
| + bool parse_success = false; |
| + |
| + switch (field_type) { |
| + case kPmpFieldTypeString: |
| + parse_success = IndexStrings(); |
| + break; |
| + case kPmpFieldTypeUInt32: |
| + parse_success = SetAndValidateFieldsize<uint32>(); |
| + break; |
| + case kPmpFieldTypeDouble64: |
| + parse_success = SetAndValidateFieldsize<double>(); |
| + break; |
| + case kPmpFieldTypeUInt8: |
| + parse_success = SetAndValidateFieldsize<uint8>(); |
| + break; |
| + case kPmpFieldTypeUInt64: |
| + parse_success = SetAndValidateFieldsize<uint64>(); |
| + break; |
| + default: |
| + parse_success = false; |
| + break; |
| + } |
| + |
| + if(parse_success) { |
| + // 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(length_ >= kPmpHeaderSize); |
| + |
| + strings_.clear(); |
| + strings_.reserve(rows_); |
| + |
| + size_t bytes_parsed = kPmpHeaderSize; |
| + const uint8* itr = data_.get() + kPmpHeaderSize; |
| + |
| + while (strings_.size() < rows_) { |
| + const uint8* ptr_to_str_end = static_cast<const uint8*>( |
| + memchr(itr, '\0', length_ - bytes_parsed)); |
| + |
| + // Fail if cannot find null termination. String runs on past file end. |
| + if(ptr_to_str_end == NULL) return false; |
| + |
| + // Length of string. (+1 to include the termination character). |
| + ptrdiff_t len_bytes = ptr_to_str_end - itr + 1; |
| + |
| + strings_.push_back(reinterpret_cast<const char*>(itr)); |
| + itr += len_bytes; |
| + bytes_parsed += len_bytes; |
| + } |
| + |
| + // This means the file has more bytes at the end we haven't parsed. |
| + if(bytes_parsed != length_) return false; |
|
vandebo (ex-Chrome)
2013/03/27 00:06:19
return false on next line.
tommycli
2013/03/27 19:34:30
Done.
|
| + |
| + return true; |
| +} |
| + |
| +template<class T> |
| +bool PmpColumnReader::SetAndValidateFieldsize() { |
| + unsigned long calculated_n_rows = (length_ - kPmpHeaderSize) / sizeof(T); |
| + |
| + if(calculated_n_rows == rows_) { |
| + fieldsize_ = sizeof(T); |
| + return true; |
| + } |
| + |
| + return false; |
| +} |
| + |
| +} // namespace |