Get foreground tab on Android
[chromium-blink-merge.git] / chrome / utility / media_galleries / pmp_column_reader.cc
blob5150c2e57a4ea18825292430227500e7f920b100
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/file_util.h"
10 #include "base/logging.h"
11 #include "base/threading/thread_restrictions.h"
13 namespace picasa {
15 namespace {
17 COMPILE_ASSERT(sizeof(double) == 8, double_must_be_8_bytes_long);
18 const int64 kPmpMaxFilesize = 50*1024*1024; // Arbitrary maximum of 50 MB.
20 } // namespace
22 PmpColumnReader::PmpColumnReader()
23 : length_(0),
24 field_type_(PMP_TYPE_INVALID),
25 rows_read_(0) {}
27 PmpColumnReader::~PmpColumnReader() {}
29 bool PmpColumnReader::ReadFile(base::PlatformFile file,
30 const PmpFieldType expected_type) {
31 DCHECK(!data_.get());
32 base::ThreadRestrictions::AssertIOAllowed();
34 if (file == base::kInvalidPlatformFileValue)
35 return false;
37 base::PlatformFileInfo info;
38 if (!base::GetPlatformFileInfo(file, &info))
39 return false;
40 length_ = info.size;
42 if (length_ < kPmpHeaderSize || length_ > kPmpMaxFilesize)
43 return false;
45 data_.reset(new uint8[length_]);
47 char* data_begin = reinterpret_cast<char*>(data_.get());
49 DCHECK(length_ < kint32max); // ReadFile expects an int.
51 bool success = base::ReadPlatformFile(file, 0, data_begin, length_) &&
52 ParseData(expected_type);
54 // If any of the reading or parsing fails, prevent Read* calls.
55 if (!success)
56 rows_read_ = 0;
58 return success;
61 bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const {
62 DCHECK(data_.get() != NULL);
64 if (field_type_ != PMP_TYPE_STRING || row >= rows_read_)
65 return false;
67 DCHECK_LT(row, strings_.size());
68 *result = strings_[row];
69 return true;
72 bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const {
73 DCHECK(data_.get() != NULL);
75 if (field_type_ != PMP_TYPE_UINT32 || row >= rows_read_)
76 return false;
78 *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row];
79 return true;
82 bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const {
83 DCHECK(data_.get() != NULL);
85 if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_read_)
86 return false;
88 *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row];
89 return true;
92 bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const {
93 DCHECK(data_.get() != NULL);
95 if (field_type_ != PMP_TYPE_UINT8 || row >= rows_read_)
96 return false;
98 *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row];
99 return true;
102 bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const {
103 DCHECK(data_.get() != NULL);
105 if (field_type_ != PMP_TYPE_UINT64 || row >= rows_read_)
106 return false;
108 *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row];
109 return true;
112 uint32 PmpColumnReader::rows_read() const {
113 DCHECK(data_.get() != NULL);
114 return rows_read_;
117 bool PmpColumnReader::ParseData(const PmpFieldType expected_type) {
118 DCHECK(data_.get() != NULL);
119 DCHECK_GE(length_, kPmpHeaderSize);
121 // Check all magic bytes.
122 if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 ||
123 memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 ||
124 memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 ||
125 memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) {
126 return false;
129 uint16 field_type_data =
130 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset]));
132 // Verify if field type matches second declaration
133 if (field_type_data !=
134 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset]))) {
135 return false;
138 field_type_ = static_cast<PmpFieldType>(field_type_data);
140 if (field_type_ != expected_type)
141 return false;
143 rows_read_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset]));
145 // Sanity check against malicious row field.
146 if (rows_read_ > (kPmpMaxFilesize - kPmpHeaderSize))
147 return false;
149 DCHECK_GE(length_, kPmpHeaderSize);
150 int64 body_length = length_ - kPmpHeaderSize;
151 int64 expected_body_length = 0;
152 switch (field_type_) {
153 case PMP_TYPE_STRING:
154 expected_body_length = IndexStrings();
155 break;
156 case PMP_TYPE_UINT32:
157 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint32);
158 break;
159 case PMP_TYPE_DOUBLE64:
160 expected_body_length = static_cast<int64>(rows_read_) * sizeof(double);
161 break;
162 case PMP_TYPE_UINT8:
163 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint8);
164 break;
165 case PMP_TYPE_UINT64:
166 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint64);
167 break;
168 default:
169 return false;
170 break;
173 return body_length == expected_body_length;
176 int64 PmpColumnReader::IndexStrings() {
177 DCHECK(data_.get() != NULL);
178 DCHECK_GE(length_, kPmpHeaderSize);
180 strings_.reserve(rows_read_);
182 int64 bytes_parsed = kPmpHeaderSize;
183 const uint8* data_cursor = data_.get() + kPmpHeaderSize;
185 while (strings_.size() < rows_read_) {
186 const uint8* string_end = static_cast<const uint8*>(
187 memchr(data_cursor, '\0', length_ - bytes_parsed));
189 // Fail if cannot find null termination. String runs on past file end.
190 if (string_end == NULL)
191 return -1;
193 // Length of string. (+1 to include the termination character).
194 ptrdiff_t length_in_bytes = string_end - data_cursor + 1;
196 strings_.push_back(reinterpret_cast<const char*>(data_cursor));
197 data_cursor += length_in_bytes;
198 bytes_parsed += length_in_bytes;
201 return bytes_parsed - kPmpHeaderSize;
204 } // namespace picasa