OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h" | 5 #include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h" |
6 | 6 |
7 #include <cstring> | 7 #include <cstring> |
8 | 8 |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/files/file_path.h" | |
11 #include "base/logging.h" | 10 #include "base/logging.h" |
12 #include "base/threading/thread_restrictions.h" | 11 #include "base/threading/thread_restrictions.h" |
13 | 12 |
14 namespace picasa { | 13 namespace picasa { |
15 | 14 |
16 namespace { | 15 namespace { |
17 | 16 |
| 17 COMPILE_ASSERT(sizeof(double) == 8, double_must_be_8_bytes_long); |
18 const int64 kPmpMaxFilesize = 50*1024*1024; // Arbitrary maximum of 50 MB. | 18 const int64 kPmpMaxFilesize = 50*1024*1024; // Arbitrary maximum of 50 MB. |
19 | 19 |
20 } // namespace | 20 } // namespace |
21 | 21 |
22 PmpColumnReader::PmpColumnReader() | 22 PmpColumnReader::PmpColumnReader() |
23 : length_(0), | 23 : length_(0), |
24 field_type_(PMP_TYPE_INVALID), | 24 field_type_(PMP_TYPE_INVALID), |
25 rows_(0) {} | 25 rows_read_(0) {} |
26 | 26 |
27 PmpColumnReader::~PmpColumnReader() {} | 27 PmpColumnReader::~PmpColumnReader() {} |
28 | 28 |
29 bool PmpColumnReader::Init(const base::FilePath& filepath, | 29 bool PmpColumnReader::ReadFile(base::PlatformFile file, |
30 const PmpFieldType expected_type, | 30 const PmpFieldType expected_type) { |
31 uint32* rows_read) { | |
32 DCHECK(!data_.get()); | 31 DCHECK(!data_.get()); |
33 base::ThreadRestrictions::AssertIOAllowed(); | 32 base::ThreadRestrictions::AssertIOAllowed(); |
34 | 33 |
35 if (!file_util::GetFileSize(filepath, &length_)) | 34 if (file == base::kInvalidPlatformFileValue) |
36 return false; | 35 return false; |
37 | 36 |
| 37 base::PlatformFileInfo info; |
| 38 if (!base::GetPlatformFileInfo(file, &info)) |
| 39 return false; |
| 40 length_ = info.size; |
| 41 |
38 if (length_ < kPmpHeaderSize || length_ > kPmpMaxFilesize) | 42 if (length_ < kPmpHeaderSize || length_ > kPmpMaxFilesize) |
39 return false; | 43 return false; |
40 | 44 |
41 data_.reset(new uint8[length_]); | 45 data_.reset(new uint8[length_]); |
42 | 46 |
43 char* data_begin = reinterpret_cast<char*>(data_.get()); | 47 char* data_begin = reinterpret_cast<char*>(data_.get()); |
44 | 48 |
45 DCHECK(length_ < kint32max); // ReadFile expects an int. | 49 DCHECK(length_ < kint32max); // ReadFile expects an int. |
46 | 50 |
47 bool success = file_util::ReadFile(filepath, data_begin, length_) && | 51 bool success = base::ReadPlatformFile(file, 0, data_begin, length_) && |
48 ParseData(expected_type, rows_read); | 52 ParseData(expected_type); |
49 | 53 |
| 54 // If any of the reading or parsing fails, prevent Read* calls. |
50 if (!success) | 55 if (!success) |
51 rows_ = 0; // If any of the reading or parsing fails, prevent Read* calls. | 56 rows_read_ = 0; |
52 | 57 |
53 return success; | 58 return success; |
54 } | 59 } |
55 | 60 |
56 bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const { | 61 bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const { |
57 DCHECK(data_.get() != NULL); | 62 DCHECK(data_.get() != NULL); |
58 | 63 |
59 if (field_type_ != PMP_TYPE_STRING || row >= rows_) | 64 if (field_type_ != PMP_TYPE_STRING || row >= rows_read_) |
60 return false; | 65 return false; |
61 | 66 |
62 DCHECK_LT(row, strings_.size()); | 67 DCHECK_LT(row, strings_.size()); |
63 *result = strings_[row]; | 68 *result = strings_[row]; |
64 return true; | 69 return true; |
65 } | 70 } |
66 | 71 |
67 bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const { | 72 bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const { |
68 DCHECK(data_.get() != NULL); | 73 DCHECK(data_.get() != NULL); |
69 | 74 |
70 if (field_type_ != PMP_TYPE_UINT32 || row >= rows_) | 75 if (field_type_ != PMP_TYPE_UINT32 || row >= rows_read_) |
71 return false; | 76 return false; |
72 | 77 |
73 *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row]; | 78 *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row]; |
74 return true; | 79 return true; |
75 } | 80 } |
76 | 81 |
77 bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const { | 82 bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const { |
78 DCHECK(data_.get() != NULL); | 83 DCHECK(data_.get() != NULL); |
79 | 84 |
80 if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_) | 85 if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_read_) |
81 return false; | 86 return false; |
82 | 87 |
83 *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row]; | 88 *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row]; |
84 return true; | 89 return true; |
85 } | 90 } |
86 | 91 |
87 bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const { | 92 bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const { |
88 DCHECK(data_.get() != NULL); | 93 DCHECK(data_.get() != NULL); |
89 | 94 |
90 if (field_type_ != PMP_TYPE_UINT8 || row >= rows_) | 95 if (field_type_ != PMP_TYPE_UINT8 || row >= rows_read_) |
91 return false; | 96 return false; |
92 | 97 |
93 *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row]; | 98 *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row]; |
94 return true; | 99 return true; |
95 } | 100 } |
96 | 101 |
97 bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const { | 102 bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const { |
98 DCHECK(data_.get() != NULL); | 103 DCHECK(data_.get() != NULL); |
99 | 104 |
100 if (field_type_ != PMP_TYPE_UINT64 || row >= rows_) | 105 if (field_type_ != PMP_TYPE_UINT64 || row >= rows_read_) |
101 return false; | 106 return false; |
102 | 107 |
103 *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row]; | 108 *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row]; |
104 return true; | 109 return true; |
105 } | 110 } |
106 | 111 |
107 bool PmpColumnReader::ParseData(const PmpFieldType expected_type, | 112 uint32 PmpColumnReader::rows_read() const { |
108 uint32* rows_read) { | 113 DCHECK(data_.get() != NULL); |
| 114 return rows_read_; |
| 115 } |
| 116 |
| 117 bool PmpColumnReader::ParseData(const PmpFieldType expected_type) { |
109 DCHECK(data_.get() != NULL); | 118 DCHECK(data_.get() != NULL); |
110 DCHECK_GE(length_, kPmpHeaderSize); | 119 DCHECK_GE(length_, kPmpHeaderSize); |
111 | 120 |
112 // Check all magic bytes. | 121 // Check all magic bytes. |
113 if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 || | 122 if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 || |
114 memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 || | 123 memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 || |
115 memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 || | 124 memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 || |
116 memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) { | 125 memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) { |
117 return false; | 126 return false; |
118 } | 127 } |
119 | 128 |
120 uint16 field_type_data = | 129 uint16 field_type_data = |
121 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset])); | 130 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset])); |
122 | 131 |
123 // Verify if field type matches second declaration | 132 // Verify if field type matches second declaration |
124 if (field_type_data != | 133 if (field_type_data != |
125 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset]))) { | 134 *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset]))) { |
126 return false; | 135 return false; |
127 } | 136 } |
128 | 137 |
129 field_type_ = static_cast<PmpFieldType>(field_type_data); | 138 field_type_ = static_cast<PmpFieldType>(field_type_data); |
130 | 139 |
131 if (field_type_ != expected_type) | 140 if (field_type_ != expected_type) |
132 return false; | 141 return false; |
133 | 142 |
134 rows_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset])); | 143 rows_read_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset])); |
135 | 144 |
136 // Sanity check against malicious row field. | 145 // Sanity check against malicious row field. |
137 if (rows_ > (kPmpMaxFilesize - kPmpHeaderSize)) | 146 if (rows_read_ > (kPmpMaxFilesize - kPmpHeaderSize)) |
138 return false; | 147 return false; |
139 | 148 |
140 DCHECK_GE(length_, kPmpHeaderSize); | 149 DCHECK_GE(length_, kPmpHeaderSize); |
141 int64 body_length = length_ - kPmpHeaderSize; | 150 int64 body_length = length_ - kPmpHeaderSize; |
142 int64 expected_body_length = 0; | 151 int64 expected_body_length = 0; |
143 switch (field_type_) { | 152 switch (field_type_) { |
144 case PMP_TYPE_STRING: | 153 case PMP_TYPE_STRING: |
145 expected_body_length = IndexStrings(); | 154 expected_body_length = IndexStrings(); |
146 break; | 155 break; |
147 case PMP_TYPE_UINT32: | 156 case PMP_TYPE_UINT32: |
148 expected_body_length = static_cast<int64>(rows_) * sizeof(uint32); | 157 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint32); |
149 break; | 158 break; |
150 case PMP_TYPE_DOUBLE64: | 159 case PMP_TYPE_DOUBLE64: |
151 expected_body_length = static_cast<int64>(rows_) * sizeof(double); | 160 expected_body_length = static_cast<int64>(rows_read_) * sizeof(double); |
152 break; | 161 break; |
153 case PMP_TYPE_UINT8: | 162 case PMP_TYPE_UINT8: |
154 expected_body_length = static_cast<int64>(rows_) * sizeof(uint8); | 163 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint8); |
155 break; | 164 break; |
156 case PMP_TYPE_UINT64: | 165 case PMP_TYPE_UINT64: |
157 expected_body_length = static_cast<int64>(rows_) * sizeof(uint64); | 166 expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint64); |
158 break; | 167 break; |
159 default: | 168 default: |
160 return false; | 169 return false; |
161 break; | 170 break; |
162 } | 171 } |
163 | 172 |
164 if (body_length == expected_body_length && rows_read) | |
165 *rows_read = rows_; | |
166 return body_length == expected_body_length; | 173 return body_length == expected_body_length; |
167 } | 174 } |
168 | 175 |
169 int64 PmpColumnReader::IndexStrings() { | 176 int64 PmpColumnReader::IndexStrings() { |
170 DCHECK(data_.get() != NULL); | 177 DCHECK(data_.get() != NULL); |
171 DCHECK_GE(length_, kPmpHeaderSize); | 178 DCHECK_GE(length_, kPmpHeaderSize); |
172 | 179 |
173 strings_.reserve(rows_); | 180 strings_.reserve(rows_read_); |
174 | 181 |
175 int64 bytes_parsed = kPmpHeaderSize; | 182 int64 bytes_parsed = kPmpHeaderSize; |
176 const uint8* data_cursor = data_.get() + kPmpHeaderSize; | 183 const uint8* data_cursor = data_.get() + kPmpHeaderSize; |
177 | 184 |
178 while (strings_.size() < rows_) { | 185 while (strings_.size() < rows_read_) { |
179 const uint8* string_end = static_cast<const uint8*>( | 186 const uint8* string_end = static_cast<const uint8*>( |
180 memchr(data_cursor, '\0', length_ - bytes_parsed)); | 187 memchr(data_cursor, '\0', length_ - bytes_parsed)); |
181 | 188 |
182 // Fail if cannot find null termination. String runs on past file end. | 189 // Fail if cannot find null termination. String runs on past file end. |
183 if (string_end == NULL) | 190 if (string_end == NULL) |
184 return -1; | 191 return -1; |
185 | 192 |
186 // Length of string. (+1 to include the termination character). | 193 // Length of string. (+1 to include the termination character). |
187 ptrdiff_t length_in_bytes = string_end - data_cursor + 1; | 194 ptrdiff_t length_in_bytes = string_end - data_cursor + 1; |
188 | 195 |
189 strings_.push_back(reinterpret_cast<const char*>(data_cursor)); | 196 strings_.push_back(reinterpret_cast<const char*>(data_cursor)); |
190 data_cursor += length_in_bytes; | 197 data_cursor += length_in_bytes; |
191 bytes_parsed += length_in_bytes; | 198 bytes_parsed += length_in_bytes; |
192 } | 199 } |
193 | 200 |
194 return bytes_parsed - kPmpHeaderSize; | 201 return bytes_parsed - kPmpHeaderSize; |
195 } | 202 } |
196 | 203 |
197 } // namespace picasa | 204 } // namespace picasa |
OLD | NEW |