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