Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: chrome/utility/media_galleries/iphoto_library_parser.cc

Issue 436293002: Created helper class for parsing Apple style XML dictionaries. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: One more tweak Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/utility/media_galleries/iphoto_library_parser.h" 5 #include "chrome/utility/media_galleries/iphoto_library_parser.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 11 matching lines...) Expand all
22 base::FilePath location; 22 base::FilePath location;
23 base::FilePath original_location; 23 base::FilePath original_location;
24 }; 24 };
25 25
26 struct AlbumInfo { 26 struct AlbumInfo {
27 std::set<uint64> photo_ids; 27 std::set<uint64> photo_ids;
28 std::string name; 28 std::string name;
29 uint64 id; 29 uint64 id;
30 }; 30 };
31 31
32 // Walk through a dictionary filling in |result| with photo information. Return 32 class PhotosXmlDictReader : public iapps::XmlDictReader {
33 // true if at least the id and location were found. 33 public:
34 // In either case, the cursor is advanced out of the dictionary. 34 PhotosXmlDictReader(XmlReader* reader, PhotoInfo* photo_info)
35 bool GetPhotoInfoFromDict(XmlReader* reader, PhotoInfo* result) { 35 : iapps::XmlDictReader(reader), photo_info_(photo_info) {}
36 DCHECK(result);
37 if (reader->NodeName() != "dict")
38 return false;
39 36
40 int dict_content_depth = reader->Depth() + 1; 37 virtual bool HandleKeyImpl(const std::string& key) OVERRIDE {
41 // Advance past the dict node and into the body of the dictionary. 38 if (key == "ImagePath") {
42 if (!reader->Read())
43 return false;
44
45 bool found_location = false;
46 while (reader->Depth() >= dict_content_depth) {
47 if (!iapps::SeekToNodeAtCurrentDepth(reader, "key"))
48 break;
49 std::string found_key;
50 if (!reader->ReadElementContent(&found_key))
51 break;
52 DCHECK_EQ(dict_content_depth, reader->Depth());
53
54 if (found_key == "ImagePath") {
55 if (found_location)
56 break;
57 std::string value; 39 std::string value;
58 if (!iapps::ReadString(reader, &value)) 40 if (!iapps::ReadString(reader_, &value))
59 break; 41 return false;
60 result->location = base::FilePath(value); 42 photo_info_->location = base::FilePath(value);
61 found_location = true; 43 } else if (key == "OriginalPath") {
62 } else if (found_key == "OriginalPath") {
63 std::string value; 44 std::string value;
64 if (!iapps::ReadString(reader, &value)) 45 if (!iapps::ReadString(reader_, &value))
65 break; 46 return false;
66 result->original_location = base::FilePath(value); 47 photo_info_->original_location = base::FilePath(value);
67 } else { 48 } else if (!SkipToNext()) {
68 if (!iapps::SkipToNextElement(reader)) 49 return false;
69 break;
70 if (!reader->Next())
71 break;
72 } 50 }
51 return true;
73 } 52 }
74 53
75 // Seek to the end of the dictionary 54 virtual bool FinishedOk() OVERRIDE {
76 while (reader->Depth() >= dict_content_depth) 55 return Found("ImagePath");
77 reader->Next(); 56 }
78 57
79 return found_location; 58 private:
80 } 59 PhotoInfo* photo_info_;
60 };
81 61
82 // Contents of the album 'KeyList' key are 62 // Contents of the album 'KeyList' key are
83 // <array> 63 // <array>
84 // <string>1</string> 64 // <string>1</string>
85 // <string>2</string> 65 // <string>2</string>
86 // <string>3</string> 66 // <string>3</string>
87 // </array> 67 // </array>
88 bool ReadStringArray(XmlReader* reader, std::set<uint64>* photo_ids) { 68 bool ReadStringArray(XmlReader* reader, std::set<uint64>* photo_ids) {
89 if (reader->NodeName() != "array") 69 if (reader->NodeName() != "array")
90 return false; 70 return false;
(...skipping 12 matching lines...) Expand all
103 continue; 83 continue;
104 uint64 id; 84 uint64 id;
105 if (!base::StringToUint64(photo_id, &id)) 85 if (!base::StringToUint64(photo_id, &id))
106 continue; 86 continue;
107 photo_ids->insert(id); 87 photo_ids->insert(id);
108 } 88 }
109 89
110 return true; 90 return true;
111 } 91 }
112 92
113 bool GetAlbumInfoFromDict(XmlReader* reader, AlbumInfo* result) { 93 class AlbumXmlDictReader : public iapps::XmlDictReader {
114 DCHECK(result); 94 public:
115 if (reader->NodeName() != "dict") 95 AlbumXmlDictReader(XmlReader* reader, AlbumInfo* album_info)
116 return false; 96 : iapps::XmlDictReader(reader), album_info_(album_info) {}
117 97
118 int dict_content_depth = reader->Depth() + 1; 98 virtual bool ShouldLoop() OVERRIDE {
119 // Advance past the dict node and into the body of the dictionary. 99 return !(Found("AlbumId") && Found("AlbumName") && Found("KeyList"));
120 if (!reader->Read())
121 return false;
122
123 bool found_id = false;
124 bool found_name = false;
125 bool found_contents = false;
126 while (reader->Depth() >= dict_content_depth &&
127 !(found_id && found_name && found_contents)) {
128 if (!iapps::SeekToNodeAtCurrentDepth(reader, "key"))
129 break;
130 std::string found_key;
131 if (!reader->ReadElementContent(&found_key))
132 break;
133 DCHECK_EQ(dict_content_depth, reader->Depth());
134
135 if (found_key == "AlbumId") {
136 if (found_id)
137 break;
138 if (!iapps::ReadInteger(reader, &result->id))
139 break;
140 found_id = true;
141 } else if (found_key == "AlbumName") {
142 if (found_name)
143 break;
144 if (!iapps::ReadString(reader, &result->name))
145 break;
146 found_name = true;
147 } else if (found_key == "KeyList") {
148 if (found_contents)
149 break;
150 if (!iapps::SeekToNodeAtCurrentDepth(reader, "array"))
151 break;
152 if (!ReadStringArray(reader, &result->photo_ids))
153 break;
154 found_contents = true;
155 } else {
156 if (!iapps::SkipToNextElement(reader))
157 break;
158 if (!reader->Next())
159 break;
160 }
161 } 100 }
162 101
163 // Seek to the end of the dictionary 102 virtual bool HandleKeyImpl(const std::string& key) OVERRIDE {
164 while (reader->Depth() >= dict_content_depth) 103 if (key == "AlbumId") {
165 reader->Next(); 104 if (!iapps::ReadInteger(reader_, &album_info_->id))
105 return false;
106 } else if (key == "AlbumName") {
107 if (!iapps::ReadString(reader_, &album_info_->name))
108 return false;
109 } else if (key == "KeyList") {
110 if (!iapps::SeekToNodeAtCurrentDepth(reader_, "array"))
111 return false;
112 if (!ReadStringArray(reader_, &album_info_->photo_ids))
113 return false;
114 } else if (!SkipToNext()) {
115 return false;
116 }
117 return true;
118 }
166 119
167 return found_id && found_name && found_contents; 120 virtual bool FinishedOk() OVERRIDE {
168 } 121 return !ShouldLoop();
122 }
123
124 private:
125 AlbumInfo* album_info_;
126 };
169 127
170 // Inside the master image list, we expect photos to be arranged as 128 // Inside the master image list, we expect photos to be arranged as
171 // <dict> 129 // <dict>
172 // <key>$PHOTO_ID</key> 130 // <key>$PHOTO_ID</key>
173 // <dict> 131 // <dict>
174 // $photo properties 132 // $photo properties
175 // </dict> 133 // </dict>
176 // <key>$PHOTO_ID</key> 134 // <key>$PHOTO_ID</key>
177 // <dict> 135 // <dict>
178 // $photo properties 136 // $photo properties
(...skipping 27 matching lines...) Expand all
206 errors = true; 164 errors = true;
207 break; 165 break;
208 } 166 }
209 if (!iapps::SeekToNodeAtCurrentDepth(reader, "dict")) { 167 if (!iapps::SeekToNodeAtCurrentDepth(reader, "dict")) {
210 errors = true; 168 errors = true;
211 break; 169 break;
212 } 170 }
213 171
214 PhotoInfo photo_info; 172 PhotoInfo photo_info;
215 photo_info.id = id; 173 photo_info.id = id;
216 if (!GetPhotoInfoFromDict(reader, &photo_info)) { 174 // Walk through a dictionary filling in |result| with photo information.
175 // Return true if at least the location was found.
176 // In either case, the cursor is advanced out of the dictionary.
177 PhotosXmlDictReader dict_reader(reader, &photo_info);
178 if (!dict_reader.Read()) {
217 errors = true; 179 errors = true;
218 break; 180 break;
219 } 181 }
220 182
221 parser::Photo photo(photo_info.id, photo_info.location, 183 parser::Photo photo(photo_info.id, photo_info.location,
222 photo_info.original_location); 184 photo_info.original_location);
223 all_photos->insert(photo); 185 all_photos->insert(photo);
224 } 186 }
225 187
226 return !errors; 188 return !errors;
227 } 189 }
228 190
229 } // namespace 191 } // namespace
230 192
231 IPhotoLibraryParser::IPhotoLibraryParser() {} 193 IPhotoLibraryParser::IPhotoLibraryParser() {}
232 IPhotoLibraryParser::~IPhotoLibraryParser() {} 194 IPhotoLibraryParser::~IPhotoLibraryParser() {}
233 195
196 class IPhotoLibraryXmlDictReader : public iapps::XmlDictReader {
197 public:
198 IPhotoLibraryXmlDictReader(XmlReader* reader, parser::Library* library)
199 : iapps::XmlDictReader(reader), library_(library), ok_(true) {}
200
201 virtual bool ShouldLoop() OVERRIDE {
202 return !(Found("List of Albums") && Found("Master Image List"));
203 }
204
205 virtual bool HandleKeyImpl(const std::string& key) OVERRIDE {
206 if (key == "List of Albums") {
207 if (!iapps::SeekToNodeAtCurrentDepth(reader_, "array") ||
208 !reader_->Read()) {
209 return true;
210 }
211 while (iapps::SeekToNodeAtCurrentDepth(reader_, "dict")) {
212 AlbumInfo album_info;
213 AlbumXmlDictReader dict_reader(reader_, &album_info);
214 if (dict_reader.Read()) {
215 parser::Album album;
216 album = album_info.photo_ids;
217 // Strip / from album name and dedupe any collisions.
218 std::string name;
219 base::ReplaceChars(album_info.name, "//", " ", &name);
220 if (ContainsKey(library_->albums, name))
221 name = name + "("+base::Uint64ToString(album_info.id)+")";
222 library_->albums[name] = album;
223 }
224 }
225 } else if (key == "Master Image List") {
226 if (!ParseAllPhotos(reader_, &library_->all_photos)) {
227 ok_ = false;
228 return false;
229 }
230 }
231 return true;
232 }
233
234 virtual bool FinishedOk() OVERRIDE {
235 return ok_;
236 }
237
238 // The IPhotoLibrary allows duplicate "List of Albums" and
239 // "Master Image List" keys (although that seems odd.)
240 virtual bool AllowRepeats() OVERRIDE {
241 return true;
242 }
243
244 private:
245 parser::Library* library_;
246
247 // The base class bails when we request, and then calls |FinishedOk()|
248 // to decide what to return. We need to remember that we bailed because
249 // of an error. That's what |ok_| does.
250 bool ok_;
251 };
252
234 bool IPhotoLibraryParser::Parse(const std::string& library_xml) { 253 bool IPhotoLibraryParser::Parse(const std::string& library_xml) {
235 XmlReader reader; 254 XmlReader reader;
236 if (!reader.Load(library_xml)) 255 if (!reader.Load(library_xml))
237 return false; 256 return false;
238 257
239 // Find the plist node and then search within that tag. 258 // Find the plist node and then search within that tag.
240 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "plist")) 259 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "plist"))
241 return false; 260 return false;
242 if (!reader.Read()) 261 if (!reader.Read())
243 return false; 262 return false;
244 263
245 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "dict")) 264 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "dict"))
246 return false; 265 return false;
247 266
248 int dict_content_depth = reader.Depth() + 1; 267 IPhotoLibraryXmlDictReader dict_reader(&reader, &library_);
249 // Advance past the dict node and into the body of the dictionary. 268 return dict_reader.Read();
250 if (!reader.Read())
251 return false;
252
253 bool found_photos = false;
254 bool found_albums = false;
255 while (reader.Depth() >= dict_content_depth &&
256 !(found_photos && found_albums)) {
257 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "key"))
258 break;
259 std::string found_key;
260 if (!reader.ReadElementContent(&found_key))
261 break;
262 DCHECK_EQ(dict_content_depth, reader.Depth());
263
264 if (found_key == "List of Albums") {
265 if (found_albums)
266 continue;
267 found_albums = true;
268
269 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "array") ||
270 !reader.Read()) {
271 continue;
272 }
273
274 while (iapps::SeekToNodeAtCurrentDepth(&reader, "dict")) {
275 AlbumInfo album_info;
276 if (GetAlbumInfoFromDict(&reader, &album_info)) {
277 parser::Album album;
278 album = album_info.photo_ids;
279 // Strip / from album name and dedupe any collisions.
280 std::string name;
281 base::ReplaceChars(album_info.name, "//", " ", &name);
282 if (!ContainsKey(library_.albums, name)) {
283 library_.albums[name] = album;
284 } else {
285 library_.albums[name+"("+base::Uint64ToString(album_info.id)+")"] =
286 album;
287 }
288 }
289 }
290 } else if (found_key == "Master Image List") {
291 if (found_photos)
292 continue;
293 found_photos = true;
294 if (!ParseAllPhotos(&reader, &library_.all_photos))
295 return false;
296 }
297 }
298
299 return true;
300 } 269 }
301 270
302 } // namespace iphoto 271 } // namespace iphoto
OLDNEW
« no previous file with comments | « chrome/utility/media_galleries/iapps_xml_utils.cc ('k') | chrome/utility/media_galleries/itunes_library_parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698