Update CrOS OOBE throbber to MD throbber; delete old asset
[chromium-blink-merge.git] / chrome / utility / media_galleries / pmp_column_reader.cc
blob56527e02357e17d6bb7b53b7364c30fd2e9e8703
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.
5 #include "chrome/utility/media_galleries/pmp_column_reader.h"
7 #include <cstring>
9 #include "base/files/file.h"
10 #include "base/files/file_util.h"
11 #include "base/logging.h"
12 #include "base/threading/thread_restrictions.h"
14 namespace picasa {
16 namespace {
18 static_assert(sizeof(double) == 8, "double must be 8 bytes long");
19 const int64 kPmpMaxFilesize = 50*1024*1024; // Arbitrary maximum of 50 MB.
21 } // namespace
23 PmpColumnReader::PmpColumnReader()
24 : length_(0),
25 field_type_(PMP_TYPE_INVALID),
26 rows_read_(0) {}
28 PmpColumnReader::~PmpColumnReader() {}
30 bool PmpColumnReader::ReadFile(base::File* file,
31 const PmpFieldType expected_type) {
32 DCHECK(!data_.get());
33 base::ThreadRestrictions::AssertIOAllowed();
35 if (!file->IsValid())
36 return false;
38 base::File::Info info;
39 if (!file->GetInfo(&info))
40 return false;
41 length_ = info.size;
43 if (length_ < kPmpHeaderSize || length_ > kPmpMaxFilesize)
44 return false;
46 data_.reset(new uint8[length_]);
48 char* data_begin = reinterpret_cast<char*>(data_.get());
50 DCHECK(length_ < kint32max); // ReadFile expects an int.
52 bool success = file->Read(0, data_begin, length_) &&
53 ParseData(expected_type);
55 // If any of the reading or parsing fails, prevent Read* calls.
56 if (!success)
57 rows_read_ = 0;
59 return success;
62 bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const {
63 DCHECK(data_.get() != NULL);
65 if (field_type_ != PMP_TYPE_STRING || row >= rows_read_)
66 return false;
68 DCHECK_LT(row, strings_.size());
69 *result = strings_[row];
70 return true;
73 bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const {
74 DCHECK(data_.get() != NULL);
76 if (field_type_ != PMP_TYPE_UINT32 || row >= rows_read_)
77 return false;
79 *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row];
80 return true;
83 bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const {
84 DCHECK(data_.get() != NULL);
86 if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_read_)
87 return false;
89 *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row];
90 return true;
93 bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const {
94 DCHECK(data_.get() != NULL);
96 if (field_type_ != PMP_TYPE_UINT8 || row >= rows_read_)
97 return false;
99 *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row];
100 return true;
103 bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const {
104 DCHECK(data_.get() != NULL);
106 if (field_type_ != PMP_TYPE_UINT64 || row >= rows_read_)
107 return false;
109 *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row];
110 return true;
113 uint32 PmpColumnReader::rows_read() const {
114 DCHECK(data_.get() != NULL);
115 return rows_read_;
118 bool PmpColumnReader::ParseData(const PmpFieldType expected_type) {
119 DCHECK(data_.get() != NULL);
120 DCHECK_GE(length_, kPmpHeaderSize);
122 // Check all magic bytes.
123 if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 ||
124 memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 ||
125 memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 ||
126 memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) {
127 return false;
130 uint16 field_type_data =
131 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset]));
133 // Verify if field type matches second declaration
134 if (field_type_data !=
135 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset]))) {
136 return false;
139 field_type_ = static_cast<PmpFieldType>(field_type_data);
141 if (field_type_ != expected_type)
142 return false;
144 rows_read_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset]));
146 // Sanity check against malicious row field.
147 if (rows_read_ > (kPmpMaxFilesize - kPmpHeaderSize))
148 return false;
150 DCHECK_GE(length_, kPmpHeaderSize);
151 int64 body_length = length_ - kPmpHeaderSize;
152 int64 expected_body_length = 0;
153 switch (field_type_) {
154 case PMP_TYPE_STRING:
155 expected_body_length = IndexStrings();
156 break;
157 case PMP_TYPE_UINT32:
158 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint32);
159 break;
160 case PMP_TYPE_DOUBLE64:
161 expected_body_length = static_cast<int64>(rows_read_) * sizeof(double);
162 break;
163 case PMP_TYPE_UINT8:
164 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint8);
165 break;
166 case PMP_TYPE_UINT64:
167 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint64);
168 break;
169 default:
170 return false;
171 break;
174 return body_length == expected_body_length;
177 int64 PmpColumnReader::IndexStrings() {
178 DCHECK(data_.get() != NULL);
179 DCHECK_GE(length_, kPmpHeaderSize);
181 strings_.reserve(rows_read_);
183 int64 bytes_parsed = kPmpHeaderSize;
184 const uint8* data_cursor = data_.get() + kPmpHeaderSize;
186 while (strings_.size() < rows_read_) {
187 const uint8* string_end = static_cast<const uint8*>(
188 memchr(data_cursor, '\0', length_ - bytes_parsed));
190 // Fail if cannot find null termination. String runs on past file end.
191 if (string_end == NULL)
192 return -1;
194 // Length of string. (+1 to include the termination character).
195 ptrdiff_t length_in_bytes = string_end - data_cursor + 1;
197 strings_.push_back(reinterpret_cast<const char*>(data_cursor));
198 data_cursor += length_in_bytes;
199 bytes_parsed += length_in_bytes;
202 return bytes_parsed - kPmpHeaderSize;
205 } // namespace picasa