Commit 08665122 authored by tommycli@chromium.org's avatar tommycli@chromium.org

Media Galleries API - Picasa: Change PMP Parsing to deal with PlatformFile.

BUG=151701
R=vandebo

Review URL: https://chromiumcodereview.appspot.com/17101030

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207941 0039d316-1c4b-4281-b951-d872f2087c98
parent 877296dd
......@@ -4,6 +4,7 @@
#include "chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reader.h"
#include <algorithm>
#include <vector>
#include "base/path_service.h"
......@@ -11,7 +12,6 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
namespace picasa {
......@@ -25,6 +25,25 @@ base::Time TimeFromMicrosoftVariantTime(double variant_time) {
return base::Time::FromLocalExploded(kPicasaVariantTimeEpoch) + variant_delta;
}
base::PlatformFile OpenPlatformFile(const base::FilePath& directory_path,
const std::string& suffix) {
base::FilePath path = directory_path.Append(base::FilePath::FromUTF8Unsafe(
std::string(kPicasaAlbumTableName) + "_" + suffix));
int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
return base::CreatePlatformFile(path, flags, NULL, NULL);
}
base::PlatformFile OpenColumnPlatformFile(const base::FilePath& directory_path,
const std::string& column_name) {
return OpenPlatformFile(directory_path, column_name + "." + kPmpExtension);
}
void ClosePlatformFile(base::PlatformFile* platform_file) {
DCHECK(platform_file);
if (base::ClosePlatformFile(*platform_file))
*platform_file = base::kInvalidPlatformFileValue;
}
} // namespace
AlbumInfo::AlbumInfo() {}
......@@ -39,10 +58,32 @@ AlbumInfo::AlbumInfo(const std::string& name, const base::Time& timestamp,
AlbumInfo::~AlbumInfo() {}
PicasaAlbumTableFiles::PicasaAlbumTableFiles(
const base::FilePath& directory_path) {
indicator_file = OpenPlatformFile(directory_path, "0");
category_file = OpenColumnPlatformFile(directory_path, "category");
date_file = OpenColumnPlatformFile(directory_path, "date");
filename_file = OpenColumnPlatformFile(directory_path, "filename");
name_file = OpenColumnPlatformFile(directory_path, "name");
token_file = OpenColumnPlatformFile(directory_path, "token");
uid_file = OpenColumnPlatformFile(directory_path, "uid");
}
void ClosePicasaAlbumTableFiles(PicasaAlbumTableFiles* table_files) {
ClosePlatformFile(&(table_files->indicator_file));
ClosePlatformFile(&(table_files->category_file));
ClosePlatformFile(&(table_files->date_file));
ClosePlatformFile(&(table_files->filename_file));
ClosePlatformFile(&(table_files->name_file));
ClosePlatformFile(&(table_files->token_file));
ClosePlatformFile(&(table_files->uid_file));
}
PicasaAlbumTableReader::PicasaAlbumTableReader(
const base::FilePath& directory_path)
: directory_path_(directory_path),
initialized_(false) {}
const PicasaAlbumTableFiles& table_files)
: table_files_(table_files),
initialized_(false) {
}
PicasaAlbumTableReader::~PicasaAlbumTableReader() {}
......@@ -60,33 +101,41 @@ bool PicasaAlbumTableReader::Init() {
if (initialized_)
return true;
PmpTableReader pmp_reader(kPicasaAlbumTableName, directory_path_);
const PmpColumnReader* category_column =
pmp_reader.AddColumn("category", PMP_TYPE_UINT32);
const PmpColumnReader* date_column =
pmp_reader.AddColumn("date", PMP_TYPE_DOUBLE64);
const PmpColumnReader* filename_column =
pmp_reader.AddColumn("filename", PMP_TYPE_STRING);
const PmpColumnReader* name_column =
pmp_reader.AddColumn("name", PMP_TYPE_STRING);
const PmpColumnReader* token_column =
pmp_reader.AddColumn("token", PMP_TYPE_STRING);
const PmpColumnReader* uid_column =
pmp_reader.AddColumn("uid", PMP_TYPE_STRING);
if (pmp_reader.Columns().size() != 6)
if (table_files_.indicator_file == base::kInvalidPlatformFileValue)
return false;
for (uint32 i = 0; i < pmp_reader.RowCount(); i++) {
PmpColumnReader category_column, date_column, filename_column, name_column,
token_column, uid_column;
if (!category_column.ReadFile(table_files_.category_file, PMP_TYPE_UINT32) ||
!date_column.ReadFile(table_files_.date_file, PMP_TYPE_DOUBLE64) ||
!filename_column.ReadFile(table_files_.filename_file, PMP_TYPE_STRING) ||
!name_column.ReadFile(table_files_.name_file, PMP_TYPE_STRING) ||
!token_column.ReadFile(table_files_.token_file, PMP_TYPE_STRING) ||
!uid_column.ReadFile(table_files_.uid_file, PMP_TYPE_STRING)) {
return false;
}
// In the PMP format, columns can be different lengths. The number of rows
// in the table is max of all the columns, and short columns are NULL padded.
uint32 row_count = 0;
row_count = std::max(row_count, category_column.rows_read());
row_count = std::max(row_count, date_column.rows_read());
row_count = std::max(row_count, filename_column.rows_read());
row_count = std::max(row_count, name_column.rows_read());
row_count = std::max(row_count, token_column.rows_read());
row_count = std::max(row_count, uid_column.rows_read());
for (uint32 i = 0; i < row_count; i++) {
uint32 category = kAlbumCategoryInvalid;
double date = 0;
std::string name;
std::string uid;
if (!category_column->ReadUInt32(i, &category) ||
!date_column->ReadDouble64(i, &date) ||
!name_column->ReadString(i, &name) || name.empty() ||
!uid_column->ReadString(i, &uid) || uid.empty()) {
// PMP tables often contain 'garbage' rows of deleted or auto-generated
// album-like entities. We ignore those rows.
if (!category_column.ReadUInt32(i, &category) ||
!date_column.ReadDouble64(i, &date) ||
!name_column.ReadString(i, &name) || name.empty() ||
!uid_column.ReadString(i, &uid) || uid.empty()) {
continue;
}
......@@ -95,7 +144,7 @@ bool PicasaAlbumTableReader::Init() {
switch (category) {
case kAlbumCategoryAlbum: {
std::string token;
if (!token_column->ReadString(i, &token) || token.empty() ||
if (!token_column.ReadString(i, &token) || token.empty() ||
!StartsWithASCII(token, kAlbumTokenPrefix, false)) {
continue;
}
......@@ -105,7 +154,7 @@ bool PicasaAlbumTableReader::Init() {
}
case kAlbumCategoryFolder: {
std::string filename;
if (!filename_column->ReadString(i, &filename) || filename.empty())
if (!filename_column.ReadString(i, &filename) || filename.empty())
continue;
base::FilePath path =
......
......@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/platform_file.h"
#include "base/time.h"
namespace picasa {
......@@ -37,10 +38,23 @@ struct AlbumInfo {
base::FilePath path;
};
struct PicasaAlbumTableFiles {
explicit PicasaAlbumTableFiles(const base::FilePath& directory_path);
// Special empty file used to confirm existence of table.
base::PlatformFile indicator_file;
base::PlatformFile category_file;
base::PlatformFile date_file;
base::PlatformFile filename_file;
base::PlatformFile name_file;
base::PlatformFile token_file;
base::PlatformFile uid_file;
};
class PicasaAlbumTableReader {
public:
// |directory_path| is Picasa's db3 directory where the PMP table is stored.
explicit PicasaAlbumTableReader(const base::FilePath& directory_path);
explicit PicasaAlbumTableReader(const PicasaAlbumTableFiles& table_files);
virtual ~PicasaAlbumTableReader();
bool Init();
......@@ -49,7 +63,7 @@ class PicasaAlbumTableReader {
const std::vector<AlbumInfo>& folders() const;
private:
const base::FilePath directory_path_;
const PicasaAlbumTableFiles table_files_;
bool initialized_;
......@@ -59,6 +73,8 @@ class PicasaAlbumTableReader {
DISALLOW_COPY_AND_ASSIGN(PicasaAlbumTableReader);
};
void ClosePicasaAlbumTableFiles(PicasaAlbumTableFiles* table_files);
} // namespace picasa
#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PICASA_ALBUM_TABLE_READER_H_
......@@ -7,21 +7,20 @@
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
namespace picasa {
using picasa::PmpTestHelper;
using picasa::PMP_TYPE_UINT32;
namespace {
TEST(PicasaAlbumTableReaderTest, FoldersAndAlbums) {
PmpTestHelper test_helper(picasa::kPicasaAlbumTableName);
PmpTestHelper test_helper(kPicasaAlbumTableName);
ASSERT_TRUE(test_helper.Init());
int test_time_delta = 100;
std::vector<uint32> category_vector;
category_vector.push_back(picasa::kAlbumCategoryFolder);
category_vector.push_back(picasa::kAlbumCategoryInvalid);
category_vector.push_back(picasa::kAlbumCategoryAlbum);
category_vector.push_back(kAlbumCategoryFolder);
category_vector.push_back(kAlbumCategoryInvalid);
category_vector.push_back(kAlbumCategoryAlbum);
std::vector<double> date_vector;
date_vector.push_back(0.0);
......@@ -46,7 +45,7 @@ TEST(PicasaAlbumTableReaderTest, FoldersAndAlbums) {
std::vector<std::string> token_vector;
token_vector.push_back("");
token_vector.push_back("");
token_vector.push_back(std::string(picasa::kAlbumTokenPrefix) + "uid3");
token_vector.push_back(std::string(kAlbumTokenPrefix) + "uid3");
std::vector<std::string> uid_vector;
uid_vector.push_back("uid1");
......@@ -54,24 +53,26 @@ TEST(PicasaAlbumTableReaderTest, FoldersAndAlbums) {
uid_vector.push_back("uid3");
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
"category", picasa::PMP_TYPE_UINT32, category_vector));
"category", PMP_TYPE_UINT32, category_vector));
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
"date", picasa::PMP_TYPE_DOUBLE64, date_vector));
"date", PMP_TYPE_DOUBLE64, date_vector));
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
"filename", picasa::PMP_TYPE_STRING, filename_vector));
"filename", PMP_TYPE_STRING, filename_vector));
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
"name", picasa::PMP_TYPE_STRING, name_vector));
"name", PMP_TYPE_STRING, name_vector));
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
"token", picasa::PMP_TYPE_STRING, token_vector));
"token", PMP_TYPE_STRING, token_vector));
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
"uid", picasa::PMP_TYPE_STRING, uid_vector));
"uid", PMP_TYPE_STRING, uid_vector));
picasa::PicasaAlbumTableReader reader(test_helper.GetTempDirPath());
PicasaAlbumTableFiles album_table_files(test_helper.GetTempDirPath());
PicasaAlbumTableReader reader(album_table_files);
ASSERT_TRUE(reader.Init());
ClosePicasaAlbumTableFiles(&album_table_files);
const std::vector<picasa::AlbumInfo>& albums = reader.albums();
const std::vector<picasa::AlbumInfo>& folders = reader.folders();
const std::vector<AlbumInfo>& albums = reader.albums();
const std::vector<AlbumInfo>& folders = reader.folders();
ASSERT_EQ(1u, albums.size());
ASSERT_EQ(1u, folders.size());
......@@ -87,3 +88,5 @@ TEST(PicasaAlbumTableReaderTest, FoldersAndAlbums) {
}
} // namespace
} // namespace picasa
......@@ -89,15 +89,17 @@ void PicasaDataProvider::UniquifyNames(const std::vector<AlbumInfo>& info_list,
}
bool PicasaDataProvider::ReadData() {
PicasaAlbumTableReader album_table_reader(database_path_);
PicasaAlbumTableFiles album_table_files(database_path_);
PicasaAlbumTableReader album_table_reader((album_table_files));
if (!album_table_reader.Init())
return false;
bool read_success = album_table_reader.Init();
InitializeWith(album_table_reader.albums(),
album_table_reader.folders());
ClosePicasaAlbumTableFiles(&album_table_files);
return true;
if (read_success)
InitializeWith(album_table_reader.albums(), album_table_reader.folders());
return read_success;
}
} // namespace picasa
......@@ -7,7 +7,6 @@
#include <cstring>
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
......@@ -15,6 +14,7 @@ namespace picasa {
namespace {
COMPILE_ASSERT(sizeof(double) == 8, double_must_be_8_bytes_long);
const int64 kPmpMaxFilesize = 50*1024*1024; // Arbitrary maximum of 50 MB.
} // namespace
......@@ -22,19 +22,23 @@ const int64 kPmpMaxFilesize = 50*1024*1024; // Arbitrary maximum of 50 MB.
PmpColumnReader::PmpColumnReader()
: length_(0),
field_type_(PMP_TYPE_INVALID),
rows_(0) {}
rows_read_(0) {}
PmpColumnReader::~PmpColumnReader() {}
bool PmpColumnReader::Init(const base::FilePath& filepath,
const PmpFieldType expected_type,
uint32* rows_read) {
bool PmpColumnReader::ReadFile(base::PlatformFile file,
const PmpFieldType expected_type) {
DCHECK(!data_.get());
base::ThreadRestrictions::AssertIOAllowed();
if (!file_util::GetFileSize(filepath, &length_))
if (file == base::kInvalidPlatformFileValue)
return false;
base::PlatformFileInfo info;
if (!base::GetPlatformFileInfo(file, &info))
return false;
length_ = info.size;
if (length_ < kPmpHeaderSize || length_ > kPmpMaxFilesize)
return false;
......@@ -44,11 +48,12 @@ bool PmpColumnReader::Init(const base::FilePath& filepath,
DCHECK(length_ < kint32max); // ReadFile expects an int.
bool success = file_util::ReadFile(filepath, data_begin, length_) &&
ParseData(expected_type, rows_read);
bool success = base::ReadPlatformFile(file, 0, data_begin, length_) &&
ParseData(expected_type);
// If any of the reading or parsing fails, prevent Read* calls.
if (!success)
rows_ = 0; // If any of the reading or parsing fails, prevent Read* calls.
rows_read_ = 0;
return success;
}
......@@ -56,7 +61,7 @@ bool PmpColumnReader::Init(const base::FilePath& filepath,
bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const {
DCHECK(data_.get() != NULL);
if (field_type_ != PMP_TYPE_STRING || row >= rows_)
if (field_type_ != PMP_TYPE_STRING || row >= rows_read_)
return false;
DCHECK_LT(row, strings_.size());
......@@ -67,7 +72,7 @@ bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const {
bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const {
DCHECK(data_.get() != NULL);
if (field_type_ != PMP_TYPE_UINT32 || row >= rows_)
if (field_type_ != PMP_TYPE_UINT32 || row >= rows_read_)
return false;
*result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row];
......@@ -77,7 +82,7 @@ bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const {
bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const {
DCHECK(data_.get() != NULL);
if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_)
if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_read_)
return false;
*result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row];
......@@ -87,7 +92,7 @@ bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const {
bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const {
DCHECK(data_.get() != NULL);
if (field_type_ != PMP_TYPE_UINT8 || row >= rows_)
if (field_type_ != PMP_TYPE_UINT8 || row >= rows_read_)
return false;
*result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row];
......@@ -97,15 +102,19 @@ bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const {
bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const {
DCHECK(data_.get() != NULL);
if (field_type_ != PMP_TYPE_UINT64 || row >= rows_)
if (field_type_ != PMP_TYPE_UINT64 || row >= rows_read_)
return false;
*result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row];
return true;
}
bool PmpColumnReader::ParseData(const PmpFieldType expected_type,
uint32* rows_read) {
uint32 PmpColumnReader::rows_read() const {
DCHECK(data_.get() != NULL);
return rows_read_;
}
bool PmpColumnReader::ParseData(const PmpFieldType expected_type) {
DCHECK(data_.get() != NULL);
DCHECK_GE(length_, kPmpHeaderSize);
......@@ -131,10 +140,10 @@ bool PmpColumnReader::ParseData(const PmpFieldType expected_type,
if (field_type_ != expected_type)
return false;
rows_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset]));
rows_read_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset]));
// Sanity check against malicious row field.
if (rows_ > (kPmpMaxFilesize - kPmpHeaderSize))
if (rows_read_ > (kPmpMaxFilesize - kPmpHeaderSize))
return false;
DCHECK_GE(length_, kPmpHeaderSize);
......@@ -145,24 +154,22 @@ bool PmpColumnReader::ParseData(const PmpFieldType expected_type,
expected_body_length = IndexStrings();
break;
case PMP_TYPE_UINT32:
expected_body_length = static_cast<int64>(rows_) * sizeof(uint32);
expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint32);
break;
case PMP_TYPE_DOUBLE64:
expected_body_length = static_cast<int64>(rows_) * sizeof(double);
expected_body_length = static_cast<int64>(rows_read_) * sizeof(double);
break;
case PMP_TYPE_UINT8:
expected_body_length = static_cast<int64>(rows_) * sizeof(uint8);
expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint8);
break;
case PMP_TYPE_UINT64:
expected_body_length = static_cast<int64>(rows_) * sizeof(uint64);
expected_body_length = static_cast<int64>(rows_read_) * sizeof(uint64);
break;
default:
return false;
break;
}
if (body_length == expected_body_length && rows_read)
*rows_read = rows_;
return body_length == expected_body_length;
}
......@@ -170,12 +177,12 @@ int64 PmpColumnReader::IndexStrings() {
DCHECK(data_.get() != NULL);
DCHECK_GE(length_, kPmpHeaderSize);
strings_.reserve(rows_);
strings_.reserve(rows_read_);
int64 bytes_parsed = kPmpHeaderSize;
const uint8* data_cursor = data_.get() + kPmpHeaderSize;
while (strings_.size() < rows_) {
while (strings_.size() < rows_read_) {
const uint8* string_end = static_cast<const uint8*>(
memchr(data_cursor, '\0', length_ - bytes_parsed));
......
......@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/platform_file.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
namespace base {
......@@ -26,20 +27,22 @@ class PmpColumnReader {
// Returns true if read successfully.
// |rows_read| is undefined if returns false.
bool Init(const base::FilePath& filepath, const PmpFieldType expected_type,
uint32* rows_read);
bool ReadFile(base::PlatformFile file, const PmpFieldType expected_type);
// These functions read the value of that |row| into |result|.
// Functions return false if the column is of the wrong type or the row
// is out of range.
// is out of range. May only be called after successful ReadColumn.
bool ReadString(const uint32 row, std::string* result) const;
bool ReadUInt32(const uint32 row, uint32* result) const;
bool ReadDouble64(const uint32 row, double* result) const;
bool ReadUInt8(const uint32 row, uint8* result) const;
bool ReadUInt64(const uint32 row, uint64* result) const;
// May only be called after successful ReadColumn.
uint32 rows_read() const;
private:
bool ParseData(const PmpFieldType expected_type, uint32* rows_read);
bool ParseData(const PmpFieldType expected_type);
// Returns the number of bytes parsed in the body, or, -1 on failure.
int64 IndexStrings();
......@@ -49,7 +52,7 @@ class PmpColumnReader {
// Header data
PmpFieldType field_type_;
uint32 rows_;
uint32 rows_read_;
// Index of string start locations if fields are strings. Empty otherwise.
std::vector<const char*> strings_;
......
......@@ -44,16 +44,13 @@ void TestValid(const picasa::PmpFieldType field_type,
ASSERT_TRUE(test_helper.Init());
PmpColumnReader reader;
uint32 rows_read = 0xFF;
std::vector<uint8> data =
PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
ASSERT_TRUE(test_helper.InitColumnReaderFromBytes(
&reader, data, field_type, &rows_read));
EXPECT_EQ(elems.size(), rows_read);
&reader, data, field_type));
EXPECT_EQ(elems.size(), reader.rows_read());
for (uint32 i = 0; i < elems.size() && i < rows_read; i++) {
for (uint32 i = 0; i < elems.size() && i < reader.rows_read(); i++) {
T target;
EXPECT_TRUE(DoRead(&reader, i, &target));
EXPECT_EQ(elems[i], target);
......@@ -72,8 +69,7 @@ void TestMalformed(const picasa::PmpFieldType field_type,
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_too_few_declared_rows,
data_too_few_declared_rows,
field_type,
NULL));
field_type));
PmpColumnReader reader_too_many_declared_rows;
std::vector<uint8> data_too_many_declared_rows =
......@@ -81,22 +77,21 @@ void TestMalformed(const picasa::PmpFieldType field_type,
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_too_many_declared_rows,
data_too_many_declared_rows,
field_type,
NULL));
field_type));
PmpColumnReader reader_truncated;
std::vector<uint8> data_truncated =
PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
data_truncated.resize(data_truncated.size()-10);
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_truncated, data_truncated, field_type, NULL));
&reader_truncated, data_truncated, field_type));
PmpColumnReader reader_padded;
std::vector<uint8> data_padded =
PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
data_padded.resize(data_padded.size()+10);
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_padded, data_padded, field_type, NULL));
&reader_padded, data_padded, field_type));
}
template<class T>
......@@ -118,15 +113,14 @@ TEST(PmpColumnReaderTest, HeaderParsingAndValidation) {
ASSERT_TRUE(test_helper.Init());
PmpColumnReader reader_good_header;
uint32 rows_read = 0xFF;
std::vector<uint8> good_header =
PmpTestHelper::MakeHeader(picasa::PMP_TYPE_STRING, 0);
EXPECT_TRUE(test_helper.InitColumnReaderFromBytes(
&reader_good_header,
good_header,
picasa::PMP_TYPE_STRING,
&rows_read));
EXPECT_EQ(0U, rows_read) << "Read non-zero rows from header-only data.";
picasa::PMP_TYPE_STRING));
EXPECT_EQ(0U, reader_good_header.rows_read()) <<
"Read non-zero rows from header-only data.";
PmpColumnReader reader_bad_magic_bytes;
std::vector<uint8> bad_magic_bytes =
......@@ -135,8 +129,7 @@ TEST(PmpColumnReaderTest, HeaderParsingAndValidation) {
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_bad_magic_bytes,
bad_magic_bytes,
picasa::PMP_TYPE_STRING,
NULL));
picasa::PMP_TYPE_STRING));
PmpColumnReader reader_inconsistent_types;
std::vector<uint8> inconsistent_type =
......@@ -145,8 +138,7 @@ TEST(PmpColumnReaderTest, HeaderParsingAndValidation) {
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_inconsistent_types,
inconsistent_type,
picasa::PMP_TYPE_STRING,
NULL));
picasa::PMP_TYPE_STRING));
PmpColumnReader reader_invalid_type;
std::vector<uint8> invalid_type =
......@@ -156,8 +148,7 @@ TEST(PmpColumnReaderTest, HeaderParsingAndValidation) {
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_invalid_type,
invalid_type,
picasa::PMP_TYPE_STRING,
NULL));
picasa::PMP_TYPE_STRING));
PmpColumnReader reader_incomplete_header;
std::vector<uint8> incomplete_header =
......@@ -166,8 +157,7 @@ TEST(PmpColumnReaderTest, HeaderParsingAndValidation) {
EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
&reader_incomplete_header,
incomplete_header,
picasa::PMP_TYPE_STRING,
NULL));
picasa::PMP_TYPE_STRING));
}
TEST(PmpColumnReaderTest, StringParsing) {
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
#include <algorithm>
#include "base/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
namespace picasa {
namespace {
COMPILE_ASSERT(sizeof(double) == 8, double_must_be_8_bytes_long);
} // namespace
PmpTableReader::PmpTableReader(const std::string& table_name,
const base::FilePath& directory_path)
: initialized_(false),
table_name_(table_name),
directory_path_(directory_path),
max_row_count_(0) {
base::ThreadRestrictions::AssertIOAllowed();
if (!file_util::DirectoryExists(directory_path_))
return;
std::string indicator_file_name = table_name_ + "_0";
base::FilePath indicator_file = directory_path_.Append(
base::FilePath::FromUTF8Unsafe(indicator_file_name));
// Look for the indicator_file file, indicating table existence.
initialized_ = file_util::PathExists(indicator_file) &&
!file_util::DirectoryExists(indicator_file);
}
PmpTableReader::~PmpTableReader() {}
const PmpColumnReader* PmpTableReader::AddColumn(
const std::string& column_name, const PmpFieldType expected_type) {
if (!initialized_)
return NULL;
std::string filename = table_name_ + "_" + column_name + "." + kPmpExtension;
base::FilePath column_file_path = directory_path_.Append(
base::FilePath::FromUTF8Unsafe(filename));
scoped_ptr<PmpColumnReader> column_reader(new PmpColumnReader());
uint32 row_count;
if (!column_reader->Init(column_file_path, expected_type, &row_count))
return NULL;
column_readers_.push_back(column_reader.release());
column_map_[column_name] = column_readers_.back();
max_row_count_ = std::max(max_row_count_, row_count);
return column_readers_.back();
}
uint32 PmpTableReader::RowCount() const {
return max_row_count_;
}
std::map<std::string, const PmpColumnReader*> PmpTableReader::Columns() const {
return column_map_;
}
} // namespace picasa
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
#include <map>
#include <string>
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_vector.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
namespace base {
class FilePath;
}
namespace picasa {
class PmpColumnReader;
class PmpTableReader {
public:
PmpTableReader(const std::string& table_name,
const base::FilePath& directory_path);
virtual ~PmpTableReader();
// Returns NULL on failure.
const PmpColumnReader* AddColumn(const std::string& column_name,
const PmpFieldType expected_type);
// Returns a const "view" of the successfully added columns.
std::map<std::string, const PmpColumnReader*> Columns() const;
// This value may change after calls to AddColumn().
uint32 RowCount() const;
private:
bool initialized_;
std::string table_name_;
base::FilePath directory_path_;
ScopedVector<PmpColumnReader> column_readers_;
std::map<std::string, const PmpColumnReader*> column_map_;
uint32 max_row_count_;
DISALLOW_COPY_AND_ASSIGN(PmpTableReader);
};
} // namespace picasa
#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include <vector>
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using picasa::PmpTestHelper;
TEST(PmpTableReaderTest, RowCountAndFieldType) {
std::string table_name("tabletest");
PmpTestHelper test_helper(table_name);
ASSERT_TRUE(test_helper.Init());
std::vector<std::string> column_names;
column_names.push_back("strings");
column_names.push_back("uint32s");
column_names.push_back("doubles");
const std::vector<std::string> strings_vector(10, "Hello");
const std::vector<uint32> uint32s_vector(30, 42);
const std::vector<double> doubles_vector(20, 0.5);
picasa::PmpFieldType column_field_types[] = {
picasa::PMP_TYPE_STRING,
picasa::PMP_TYPE_UINT32,
picasa::PMP_TYPE_DOUBLE64
};
const uint32 max_rows = uint32s_vector.size();
// Write three column files, one each for strings, uint32s, and doubles.
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
column_names[0], column_field_types[0], strings_vector));
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
column_names[1], column_field_types[1], uint32s_vector));
ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
column_names[2], column_field_types[2], doubles_vector));
picasa::PmpTableReader table_reader(table_name,
test_helper.GetTempDirPath());
for (unsigned int i = 0; i < column_names.size(); i++) {
ASSERT_TRUE(
table_reader.AddColumn(column_names[i], column_field_types[i]) != NULL);
}
EXPECT_EQ(max_rows, table_reader.RowCount());
}
} // namespace
......@@ -9,6 +9,7 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/platform_file.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
......@@ -110,10 +111,10 @@ template bool PmpTestHelper::WriteColumnFileFromVector<uint8>(
template bool PmpTestHelper::WriteColumnFileFromVector<uint64>(
const std::string&, const PmpFieldType, const std::vector<uint64>&);
bool PmpTestHelper::InitColumnReaderFromBytes(PmpColumnReader* const reader,
const std::vector<uint8>& data,
const PmpFieldType expected_type,
uint32* rows_read) {
bool PmpTestHelper::InitColumnReaderFromBytes(
PmpColumnReader* const reader,
const std::vector<uint8>& data,
const PmpFieldType expected_type) {
DCHECK(temp_dir_.IsValid());
base::FilePath temp_path;
......@@ -123,12 +124,18 @@ bool PmpTestHelper::InitColumnReaderFromBytes(PmpColumnReader* const reader,
return false;
}
bool success = reader->Init(temp_path, expected_type, rows_read);
int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
base::PlatformFile platform_file =
base::CreatePlatformFile(temp_path, flags, NULL, NULL);
if (platform_file == base::kInvalidPlatformFileValue)
return false;
file_util::Delete(temp_path, true);
bool read_success = reader->ReadFile(platform_file, expected_type);
return success;
base::ClosePlatformFile(platform_file);
file_util::Delete(temp_path, false /* recursive */);
return read_success;
}
// Return a vector so we don't have to worry about memory management.
......
......@@ -35,8 +35,7 @@ class PmpTestHelper {
bool InitColumnReaderFromBytes(PmpColumnReader* const reader,
const std::vector<uint8>& data,
const PmpFieldType expected_type,
uint32* rows_read);
const PmpFieldType expected_type);
static std::vector<uint8> MakeHeader(const PmpFieldType field_type,
const uint32 row_count);
......
......@@ -1011,12 +1011,8 @@
'browser/media_galleries/fileapi/picasa/picasa_finder.cc',
'browser/media_galleries/fileapi/picasa/picasa_finder.h',
'browser/media_galleries/fileapi/picasa/pmp_column_reader.cc',
'browser/media_galleries/fileapi/picasa/pmp_column_reader.cc',
'browser/media_galleries/fileapi/picasa/pmp_column_reader.cc',
'browser/media_galleries/fileapi/picasa/pmp_column_reader.h',
'browser/media_galleries/fileapi/picasa/pmp_constants.h',
'browser/media_galleries/fileapi/picasa/pmp_table_reader.cc',
'browser/media_galleries/fileapi/picasa/pmp_table_reader.h',
'browser/media_galleries/fileapi/safe_itunes_pref_parser_win.cc',
'browser/media_galleries/fileapi/safe_itunes_pref_parser_win.h',
'browser/media_galleries/fileapi/supported_image_type_validator.cc',
......
......@@ -948,7 +948,6 @@
'browser/media_galleries/fileapi/picasa/picasa_album_table_reader_unittest.cc',
'browser/media_galleries/fileapi/picasa/picasa_file_util_unittest.cc',
'browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc',
'browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc',
'browser/media_galleries/linux/mtp_device_object_enumerator_unittest.cc',
'browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm',
'browser/media_galleries/media_file_system_registry_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment