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/picasa_album_table_reade
r.h" | 5 #include "chrome/browser/media_galleries/fileapi/picasa/picasa_album_table_reade
r.h" |
6 | 6 |
| 7 #include <algorithm> |
7 #include <vector> | 8 #include <vector> |
8 | 9 |
9 #include "base/path_service.h" | 10 #include "base/path_service.h" |
10 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
11 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
12 #include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h" | 13 #include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h" |
13 #include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h" | 14 #include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h" |
14 #include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h" | |
15 | 15 |
16 namespace picasa { | 16 namespace picasa { |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 // |variant_time| is specified as the number of days from Dec 30, 1899. | 20 // |variant_time| is specified as the number of days from Dec 30, 1899. |
21 base::Time TimeFromMicrosoftVariantTime(double variant_time) { | 21 base::Time TimeFromMicrosoftVariantTime(double variant_time) { |
22 base::TimeDelta variant_delta = base::TimeDelta::FromMicroseconds( | 22 base::TimeDelta variant_delta = base::TimeDelta::FromMicroseconds( |
23 static_cast<int64>(variant_time * base::Time::kMicrosecondsPerDay)); | 23 static_cast<int64>(variant_time * base::Time::kMicrosecondsPerDay)); |
24 | 24 |
25 return base::Time::FromLocalExploded(kPicasaVariantTimeEpoch) + variant_delta; | 25 return base::Time::FromLocalExploded(kPicasaVariantTimeEpoch) + variant_delta; |
26 } | 26 } |
27 | 27 |
| 28 base::PlatformFile OpenPlatformFile(const base::FilePath& directory_path, |
| 29 const std::string& suffix) { |
| 30 base::FilePath path = directory_path.Append(base::FilePath::FromUTF8Unsafe( |
| 31 std::string(kPicasaAlbumTableName) + "_" + suffix)); |
| 32 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; |
| 33 return base::CreatePlatformFile(path, flags, NULL, NULL); |
| 34 } |
| 35 |
| 36 base::PlatformFile OpenColumnPlatformFile(const base::FilePath& directory_path, |
| 37 const std::string& column_name) { |
| 38 return OpenPlatformFile(directory_path, column_name + "." + kPmpExtension); |
| 39 } |
| 40 |
| 41 void ClosePlatformFile(base::PlatformFile* platform_file) { |
| 42 DCHECK(platform_file); |
| 43 if (base::ClosePlatformFile(*platform_file)) |
| 44 *platform_file = base::kInvalidPlatformFileValue; |
| 45 } |
| 46 |
28 } // namespace | 47 } // namespace |
29 | 48 |
30 AlbumInfo::AlbumInfo() {} | 49 AlbumInfo::AlbumInfo() {} |
31 | 50 |
32 AlbumInfo::AlbumInfo(const std::string& name, const base::Time& timestamp, | 51 AlbumInfo::AlbumInfo(const std::string& name, const base::Time& timestamp, |
33 const std::string& uid, const base::FilePath& path) | 52 const std::string& uid, const base::FilePath& path) |
34 : name(name), | 53 : name(name), |
35 timestamp(timestamp), | 54 timestamp(timestamp), |
36 uid(uid), | 55 uid(uid), |
37 path(path) { | 56 path(path) { |
38 } | 57 } |
39 | 58 |
40 AlbumInfo::~AlbumInfo() {} | 59 AlbumInfo::~AlbumInfo() {} |
41 | 60 |
| 61 PicasaAlbumTableFiles::PicasaAlbumTableFiles( |
| 62 const base::FilePath& directory_path) { |
| 63 indicator_file = OpenPlatformFile(directory_path, "0"); |
| 64 category_file = OpenColumnPlatformFile(directory_path, "category"); |
| 65 date_file = OpenColumnPlatformFile(directory_path, "date"); |
| 66 filename_file = OpenColumnPlatformFile(directory_path, "filename"); |
| 67 name_file = OpenColumnPlatformFile(directory_path, "name"); |
| 68 token_file = OpenColumnPlatformFile(directory_path, "token"); |
| 69 uid_file = OpenColumnPlatformFile(directory_path, "uid"); |
| 70 } |
| 71 |
| 72 void ClosePicasaAlbumTableFiles(PicasaAlbumTableFiles* table_files) { |
| 73 ClosePlatformFile(&(table_files->indicator_file)); |
| 74 ClosePlatformFile(&(table_files->category_file)); |
| 75 ClosePlatformFile(&(table_files->date_file)); |
| 76 ClosePlatformFile(&(table_files->filename_file)); |
| 77 ClosePlatformFile(&(table_files->name_file)); |
| 78 ClosePlatformFile(&(table_files->token_file)); |
| 79 ClosePlatformFile(&(table_files->uid_file)); |
| 80 } |
| 81 |
42 PicasaAlbumTableReader::PicasaAlbumTableReader( | 82 PicasaAlbumTableReader::PicasaAlbumTableReader( |
43 const base::FilePath& directory_path) | 83 const PicasaAlbumTableFiles& table_files) |
44 : directory_path_(directory_path), | 84 : table_files_(table_files), |
45 initialized_(false) {} | 85 initialized_(false) { |
| 86 } |
46 | 87 |
47 PicasaAlbumTableReader::~PicasaAlbumTableReader() {} | 88 PicasaAlbumTableReader::~PicasaAlbumTableReader() {} |
48 | 89 |
49 const std::vector<AlbumInfo>& PicasaAlbumTableReader::folders() const { | 90 const std::vector<AlbumInfo>& PicasaAlbumTableReader::folders() const { |
50 DCHECK(initialized_); | 91 DCHECK(initialized_); |
51 return folders_; | 92 return folders_; |
52 } | 93 } |
53 | 94 |
54 const std::vector<AlbumInfo>& PicasaAlbumTableReader::albums() const { | 95 const std::vector<AlbumInfo>& PicasaAlbumTableReader::albums() const { |
55 DCHECK(initialized_); | 96 DCHECK(initialized_); |
56 return albums_; | 97 return albums_; |
57 } | 98 } |
58 | 99 |
59 bool PicasaAlbumTableReader::Init() { | 100 bool PicasaAlbumTableReader::Init() { |
60 if (initialized_) | 101 if (initialized_) |
61 return true; | 102 return true; |
62 | 103 |
63 PmpTableReader pmp_reader(kPicasaAlbumTableName, directory_path_); | 104 if (table_files_.indicator_file == base::kInvalidPlatformFileValue) |
64 | |
65 const PmpColumnReader* category_column = | |
66 pmp_reader.AddColumn("category", PMP_TYPE_UINT32); | |
67 const PmpColumnReader* date_column = | |
68 pmp_reader.AddColumn("date", PMP_TYPE_DOUBLE64); | |
69 const PmpColumnReader* filename_column = | |
70 pmp_reader.AddColumn("filename", PMP_TYPE_STRING); | |
71 const PmpColumnReader* name_column = | |
72 pmp_reader.AddColumn("name", PMP_TYPE_STRING); | |
73 const PmpColumnReader* token_column = | |
74 pmp_reader.AddColumn("token", PMP_TYPE_STRING); | |
75 const PmpColumnReader* uid_column = | |
76 pmp_reader.AddColumn("uid", PMP_TYPE_STRING); | |
77 | |
78 if (pmp_reader.Columns().size() != 6) | |
79 return false; | 105 return false; |
80 | 106 |
81 for (uint32 i = 0; i < pmp_reader.RowCount(); i++) { | 107 PmpColumnReader category_column, date_column, filename_column, name_column, |
| 108 token_column, uid_column; |
| 109 if (!category_column.ReadFile(table_files_.category_file, PMP_TYPE_UINT32) || |
| 110 !date_column.ReadFile(table_files_.date_file, PMP_TYPE_DOUBLE64) || |
| 111 !filename_column.ReadFile(table_files_.filename_file, PMP_TYPE_STRING) || |
| 112 !name_column.ReadFile(table_files_.name_file, PMP_TYPE_STRING) || |
| 113 !token_column.ReadFile(table_files_.token_file, PMP_TYPE_STRING) || |
| 114 !uid_column.ReadFile(table_files_.uid_file, PMP_TYPE_STRING)) { |
| 115 return false; |
| 116 } |
| 117 |
| 118 // In the PMP format, columns can be different lengths. The number of rows |
| 119 // in the table is max of all the columns, and short columns are NULL padded. |
| 120 uint32 row_count = 0; |
| 121 row_count = std::max(row_count, category_column.rows_read()); |
| 122 row_count = std::max(row_count, date_column.rows_read()); |
| 123 row_count = std::max(row_count, filename_column.rows_read()); |
| 124 row_count = std::max(row_count, name_column.rows_read()); |
| 125 row_count = std::max(row_count, token_column.rows_read()); |
| 126 row_count = std::max(row_count, uid_column.rows_read()); |
| 127 |
| 128 for (uint32 i = 0; i < row_count; i++) { |
82 uint32 category = kAlbumCategoryInvalid; | 129 uint32 category = kAlbumCategoryInvalid; |
83 double date = 0; | 130 double date = 0; |
84 std::string name; | 131 std::string name; |
85 std::string uid; | 132 std::string uid; |
86 if (!category_column->ReadUInt32(i, &category) || | 133 // PMP tables often contain 'garbage' rows of deleted or auto-generated |
87 !date_column->ReadDouble64(i, &date) || | 134 // album-like entities. We ignore those rows. |
88 !name_column->ReadString(i, &name) || name.empty() || | 135 if (!category_column.ReadUInt32(i, &category) || |
89 !uid_column->ReadString(i, &uid) || uid.empty()) { | 136 !date_column.ReadDouble64(i, &date) || |
| 137 !name_column.ReadString(i, &name) || name.empty() || |
| 138 !uid_column.ReadString(i, &uid) || uid.empty()) { |
90 continue; | 139 continue; |
91 } | 140 } |
92 | 141 |
93 base::Time timestamp = TimeFromMicrosoftVariantTime(date); | 142 base::Time timestamp = TimeFromMicrosoftVariantTime(date); |
94 | 143 |
95 switch (category) { | 144 switch (category) { |
96 case kAlbumCategoryAlbum: { | 145 case kAlbumCategoryAlbum: { |
97 std::string token; | 146 std::string token; |
98 if (!token_column->ReadString(i, &token) || token.empty() || | 147 if (!token_column.ReadString(i, &token) || token.empty() || |
99 !StartsWithASCII(token, kAlbumTokenPrefix, false)) { | 148 !StartsWithASCII(token, kAlbumTokenPrefix, false)) { |
100 continue; | 149 continue; |
101 } | 150 } |
102 | 151 |
103 albums_.push_back(AlbumInfo(name, timestamp, uid, base::FilePath())); | 152 albums_.push_back(AlbumInfo(name, timestamp, uid, base::FilePath())); |
104 break; | 153 break; |
105 } | 154 } |
106 case kAlbumCategoryFolder: { | 155 case kAlbumCategoryFolder: { |
107 std::string filename; | 156 std::string filename; |
108 if (!filename_column->ReadString(i, &filename) || filename.empty()) | 157 if (!filename_column.ReadString(i, &filename) || filename.empty()) |
109 continue; | 158 continue; |
110 | 159 |
111 base::FilePath path = | 160 base::FilePath path = |
112 base::FilePath(base::FilePath::FromUTF8Unsafe(filename)); | 161 base::FilePath(base::FilePath::FromUTF8Unsafe(filename)); |
113 | 162 |
114 folders_.push_back(AlbumInfo(name, timestamp, uid, path)); | 163 folders_.push_back(AlbumInfo(name, timestamp, uid, path)); |
115 break; | 164 break; |
116 } | 165 } |
117 default: { | 166 default: { |
118 break; | 167 break; |
119 } | 168 } |
120 } | 169 } |
121 } | 170 } |
122 | 171 |
123 initialized_ = true; | 172 initialized_ = true; |
124 return true; | 173 return true; |
125 } | 174 } |
126 | 175 |
127 } // namespace picasa | 176 } // namespace picasa |
OLD | NEW |