Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "webkit/fileapi/media/picasa/pmp_column_reader.h" | |
| 6 | |
| 7 #include <cstring> | |
| 8 | |
| 9 #include "base/files/file_path.h" | |
| 10 #include "base/files/memory_mapped_file.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "webkit/fileapi/media/picasa/pmp_constants.h" | |
| 13 | |
| 14 namespace fileapi { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 const size_t kPmpMaxFilesize = 50*1024*1024; // Maximum of 50 MB. | |
| 19 | |
| 20 } // namespace | |
| 21 | |
| 22 PmpColumnReader::PmpColumnReader() | |
| 23 : data_(NULL), | |
| 24 length_(0), | |
| 25 rows_(0), | |
| 26 strings_(), | |
| 27 field_type_(kPmpFieldTypeInvalid) { } | |
| 28 | |
| 29 PmpColumnReader::~PmpColumnReader() { } | |
| 30 | |
| 31 bool PmpColumnReader::InitFromFile(const base::FilePath& filepath, | |
| 32 uint32* rows_read) { | |
| 33 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.
| |
| 34 | |
| 35 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.
| |
| 36 file.length() < kPmpHeaderSize || | |
| 37 file.length() > kPmpMaxFilesize || | |
| 38 file.data() == NULL) { | |
| 39 return false; | |
| 40 } | |
| 41 | |
| 42 length_ = file.length(); | |
| 43 data_.reset(new uint8[length_]); | |
| 44 std::copy(file.data(), file.data() + length_, data_.get()); | |
| 45 | |
| 46 return ParseData(rows_read); | |
| 47 } | |
| 48 | |
| 49 bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const { | |
| 50 DCHECK(data_.get() != NULL); | |
| 51 DCHECK_GT(length_, kPmpHeaderSize + row); | |
| 52 | |
| 53 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.
| |
| 54 *result = strings_[row]; | |
| 55 return true; | |
| 56 } | |
| 57 | |
| 58 return false; | |
| 59 } | |
| 60 | |
| 61 bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const { | |
| 62 DCHECK(data_.get() != NULL); | |
| 63 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.
| |
| 64 | |
| 65 if(field_type_ == kPmpFieldTypeUInt32 && row < rows_) { | |
| 66 *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row]; | |
| 67 return true; | |
| 68 } | |
| 69 | |
| 70 return false; | |
| 71 } | |
| 72 | |
| 73 bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const { | |
| 74 DCHECK(data_.get() != NULL); | |
| 75 DCHECK_GT(length_, kPmpHeaderSize + row*sizeof(double)); | |
| 76 | |
| 77 if(field_type_ == kPmpFieldTypeDouble64 && row < rows_) { | |
| 78 *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row]; | |
| 79 return true; | |
| 80 } | |
| 81 | |
| 82 return false; | |
| 83 } | |
| 84 | |
| 85 bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const { | |
| 86 DCHECK(data_.get() != NULL); | |
| 87 DCHECK_GT(length_, kPmpHeaderSize + row*sizeof(uint8)); | |
| 88 | |
| 89 if(field_type_ == kPmpFieldTypeUInt8 && row < rows_) { | |
| 90 *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row]; | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 return false; | |
| 95 } | |
| 96 | |
| 97 bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const { | |
| 98 DCHECK(data_.get() != NULL); | |
| 99 DCHECK_GT(length_, kPmpHeaderSize + row*sizeof(uint64)); | |
| 100 | |
| 101 if(field_type_ == kPmpFieldTypeUInt64 && row < rows_) { | |
| 102 *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row]; | |
| 103 return true; | |
| 104 } | |
| 105 | |
| 106 return false; | |
| 107 } | |
| 108 | |
| 109 bool PmpColumnReader::ParseData(uint32* rows_read) { | |
| 110 DCHECK(data_.get() != NULL); | |
| 111 DCHECK_GE(length_, kPmpHeaderSize); | |
| 112 | |
| 113 // Check all magic bytes. | |
| 114 if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 || | |
| 115 memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 || | |
| 116 memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 || | |
| 117 memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) { | |
| 118 return false; | |
| 119 } | |
| 120 | |
| 121 // 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.
| |
| 122 field_type_ = *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset])); | |
| 123 | |
| 124 // Verify if field type matches second declaration | |
| 125 if (field_type_ != *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset]))) | |
| 126 return false; | |
| 127 | |
| 128 // 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.
| |
| 129 rows_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset])); | |
| 130 | |
| 131 bool parse_success = false; | |
| 132 | |
|
vandebo (ex-Chrome)
2013/03/29 21:35:07
nit: extra line.
tommycli
2013/04/01 22:19:18
Done.
| |
| 133 switch (field_type_) { | |
| 134 case kPmpFieldTypeString: | |
| 135 parse_success = IndexStrings(); | |
| 136 break; | |
| 137 case kPmpFieldTypeUInt32: | |
| 138 parse_success = ValidatePrimitiveArrayLength<uint32>(); | |
| 139 break; | |
| 140 case kPmpFieldTypeDouble64: | |
| 141 parse_success = ValidatePrimitiveArrayLength<double>(); | |
| 142 break; | |
| 143 case kPmpFieldTypeUInt8: | |
| 144 parse_success = ValidatePrimitiveArrayLength<uint8>(); | |
| 145 break; | |
| 146 case kPmpFieldTypeUInt64: | |
| 147 parse_success = ValidatePrimitiveArrayLength<uint64>(); | |
| 148 break; | |
| 149 default: | |
| 150 return false; | |
| 151 break; | |
| 152 } | |
| 153 | |
| 154 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.
| |
| 155 // Set the number of rows read. Though it's not valid unless we return true. | |
| 156 if(rows_read != NULL) | |
| 157 *rows_read = rows_; | |
| 158 return true; | |
| 159 } | |
| 160 | |
| 161 return false; | |
| 162 } | |
| 163 | |
| 164 bool PmpColumnReader::IndexStrings() { | |
| 165 DCHECK(data_.get() != NULL); | |
| 166 DCHECK_GE(length_, kPmpHeaderSize); | |
| 167 | |
| 168 strings_.clear(); | |
|
vandebo (ex-Chrome)
2013/03/29 21:35:07
not needed
tommycli
2013/04/01 22:19:18
Done.
| |
| 169 strings_.reserve(rows_); | |
| 170 | |
| 171 size_t bytes_parsed = kPmpHeaderSize; | |
| 172 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.
| |
| 173 | |
| 174 while (strings_.size() < rows_) { | |
| 175 const uint8* string_end = static_cast<const uint8*>( | |
| 176 memchr(itr, '\0', length_ - bytes_parsed)); | |
| 177 | |
| 178 // Fail if cannot find null termination. String runs on past file end. | |
| 179 if(string_end == NULL) | |
| 180 return false; | |
| 181 | |
| 182 // Length of string. (+1 to include the termination character). | |
| 183 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.
| |
| 184 | |
| 185 strings_.push_back(reinterpret_cast<const char*>(itr)); | |
| 186 itr += length_in_bytes; | |
| 187 bytes_parsed += length_in_bytes; | |
| 188 } | |
| 189 | |
| 190 // 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.
| |
| 191 if(bytes_parsed != length_) | |
| 192 return false; | |
|
vandebo (ex-Chrome)
2013/03/29 21:35:07
return bytes_parsed == length_;
tommycli
2013/04/01 22:19:18
Done.
| |
| 193 | |
| 194 return true; | |
| 195 } | |
| 196 | |
| 197 template<class T> | |
| 198 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.
| |
| 199 size_t body_length = length_ - kPmpHeaderSize; | |
| 200 size_t expected_body_length = rows_ * sizeof(T); | |
| 201 | |
| 202 return body_length == expected_body_length; | |
| 203 } | |
| 204 | |
| 205 } // namespace | |
| OLD | NEW |