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/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" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "chrome/utility/media_galleries/iapps_xml_utils.h" | 13 #include "chrome/utility/media_galleries/iapps_xml_utils.h" |
14 #include "third_party/libxml/chromium/libxml_utils.h" | 14 #include "third_party/libxml/chromium/libxml_utils.h" |
15 | 15 |
16 namespace iphoto { | 16 namespace iphoto { |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 struct PhotoInfo { | 20 struct PhotoInfo { |
vandebo (ex-Chrome)
2013/10/31 20:53:43
I think we should remove everything we don't use f
Greg Billock
2013/10/31 22:34:24
ok
| |
21 uint64 id; | 21 uint64 id; |
22 std::string guid; | 22 std::string guid; |
23 base::FilePath location; | 23 base::FilePath location; |
24 base::FilePath original_location; | |
25 base::Time time; | |
24 std::string type; | 26 std::string type; |
25 }; | 27 }; |
26 | 28 |
27 struct AlbumInfo { | 29 struct AlbumInfo { |
28 std::set<uint64> photo_ids; | 30 std::set<uint64> photo_ids; |
29 std::string name; | 31 std::string name; |
30 uint64 id; | 32 uint64 id; |
31 }; | 33 }; |
32 | 34 |
33 // Walk through a dictionary filling in |result| with photo information. Return | 35 // Walk through a dictionary filling in |result| with photo information. Return |
34 // true if at least the id and location were found. | 36 // true if at least the id and location were found. |
35 // In either case, the cursor is advanced out of the dictionary. | 37 // In either case, the cursor is advanced out of the dictionary. |
36 bool GetPhotoInfoFromDict(XmlReader* reader, PhotoInfo* result) { | 38 bool GetPhotoInfoFromDict(XmlReader* reader, PhotoInfo* result) { |
37 DCHECK(result); | 39 DCHECK(result); |
38 if (reader->NodeName() != "dict") | 40 if (reader->NodeName() != "dict") |
39 return false; | 41 return false; |
40 | 42 |
41 int dict_content_depth = reader->Depth() + 1; | 43 int dict_content_depth = reader->Depth() + 1; |
42 // Advance past the dict node and into the body of the dictionary. | 44 // Advance past the dict node and into the body of the dictionary. |
43 if (!reader->Read()) | 45 if (!reader->Read()) |
44 return false; | 46 return false; |
45 | 47 |
46 bool found_guid = false; | |
47 bool found_location = false; | 48 bool found_location = false; |
48 bool found_type = false; | 49 while (reader->Depth() >= dict_content_depth) { |
49 while (reader->Depth() >= dict_content_depth && | |
50 !(found_guid && found_location && found_type)) { | |
51 if (!iapps::SeekToNodeAtCurrentDepth(reader, "key")) | 50 if (!iapps::SeekToNodeAtCurrentDepth(reader, "key")) |
52 break; | 51 break; |
53 std::string found_key; | 52 std::string found_key; |
54 if (!reader->ReadElementContent(&found_key)) | 53 if (!reader->ReadElementContent(&found_key)) |
55 break; | 54 break; |
56 DCHECK_EQ(dict_content_depth, reader->Depth()); | 55 DCHECK_EQ(dict_content_depth, reader->Depth()); |
57 | 56 |
58 if (found_key == "GUID") { | 57 if (found_key == "GUID") { |
59 if (found_guid) | |
60 break; | |
61 if (!iapps::ReadString(reader, &result->guid)) | 58 if (!iapps::ReadString(reader, &result->guid)) |
62 break; | 59 break; |
63 found_guid = true; | |
64 } else if (found_key == "MediaType") { | 60 } else if (found_key == "MediaType") { |
65 if (found_type) | |
66 break; | |
67 if (!iapps::ReadString(reader, &result->type)) | 61 if (!iapps::ReadString(reader, &result->type)) |
68 break; | 62 break; |
69 found_type = true; | |
70 } else if (found_key == "ImagePath") { | 63 } else if (found_key == "ImagePath") { |
71 if (found_location) | 64 if (found_location) |
72 break; | 65 break; |
73 std::string value; | 66 std::string value; |
74 if (!iapps::ReadString(reader, &value)) | 67 if (!iapps::ReadString(reader, &value)) |
75 break; | 68 break; |
76 result->location = base::FilePath(value); | 69 result->location = base::FilePath(value); |
77 found_location = true; | 70 found_location = true; |
71 } else if (found_key == "OriginalPath") { | |
72 std::string value; | |
73 if (!iapps::ReadString(reader, &value)) | |
74 break; | |
75 result->original_location = base::FilePath(value); | |
76 } else if (found_key == "DateAsTimerIntervalGMT") { | |
77 std::string value; | |
78 if (!iapps::ReadString(reader, &value)) | |
79 break; | |
80 double time_double = 0.0; | |
81 if (!base::StringToDouble(value, &time_double)) | |
82 break; | |
83 // Add offset from Mac time (2001-based) to 1970-based. | |
84 result->time = base::Time::FromDoubleT(time_double + 978307200.0); | |
78 } else { | 85 } else { |
79 if (!iapps::SkipToNextElement(reader)) | 86 if (!iapps::SkipToNextElement(reader)) |
80 break; | 87 break; |
81 if (!reader->Next()) | 88 if (!reader->Next()) |
82 break; | 89 break; |
83 } | 90 } |
84 } | 91 } |
85 | 92 |
86 // Seek to the end of the dictionary | 93 // Seek to the end of the dictionary |
87 while (reader->Depth() >= dict_content_depth) | 94 while (reader->Depth() >= dict_content_depth) |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
222 break; | 229 break; |
223 } | 230 } |
224 | 231 |
225 PhotoInfo photo_info; | 232 PhotoInfo photo_info; |
226 photo_info.id = id; | 233 photo_info.id = id; |
227 if (!GetPhotoInfoFromDict(reader, &photo_info)) { | 234 if (!GetPhotoInfoFromDict(reader, &photo_info)) { |
228 errors = true; | 235 errors = true; |
229 break; | 236 break; |
230 } | 237 } |
231 | 238 |
232 parser::Photo photo(photo_info.id, photo_info.location); | 239 parser::Photo photo(photo_info.id, photo_info.location, |
240 photo_info.original_location, photo_info.time); | |
233 all_photos->insert(photo); | 241 all_photos->insert(photo); |
234 } | 242 } |
235 | 243 |
236 return !errors; | 244 return !errors; |
237 } | 245 } |
238 | 246 |
239 } // namespace | 247 } // namespace |
240 | 248 |
241 IPhotoLibraryParser::IPhotoLibraryParser() {} | 249 IPhotoLibraryParser::IPhotoLibraryParser() {} |
242 IPhotoLibraryParser::~IPhotoLibraryParser() {} | 250 IPhotoLibraryParser::~IPhotoLibraryParser() {} |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "array") || | 287 if (!iapps::SeekToNodeAtCurrentDepth(&reader, "array") || |
280 !reader.Read()) { | 288 !reader.Read()) { |
281 continue; | 289 continue; |
282 } | 290 } |
283 | 291 |
284 while (iapps::SeekToNodeAtCurrentDepth(&reader, "dict")) { | 292 while (iapps::SeekToNodeAtCurrentDepth(&reader, "dict")) { |
285 AlbumInfo album_info; | 293 AlbumInfo album_info; |
286 if (GetAlbumInfoFromDict(&reader, &album_info)) { | 294 if (GetAlbumInfoFromDict(&reader, &album_info)) { |
287 parser::Album album; | 295 parser::Album album; |
288 album = album_info.photo_ids; | 296 album = album_info.photo_ids; |
289 // Strip / from album name. | 297 // Strip / from album name and dedupe any collisions. |
290 std::string name; | 298 std::string name; |
291 ReplaceChars(album_info.name, "//", " ", &name); | 299 ReplaceChars(album_info.name, "//", " ", &name); |
292 library_.albums[name] = album; | 300 if (!ContainsKey(library_.albums, name)) { |
301 library_.albums[name] = album; | |
vandebo (ex-Chrome)
2013/10/31 20:53:43
So first in the xml file wins? Maybe we should tr
Greg Billock
2013/10/31 22:34:24
Sounds good.
vandebo (ex-Chrome)
2013/11/01 18:50:33
Should we keep a separate list of dup album names
| |
302 } else { | |
303 library_.albums[name+"("+base::Uint64ToString(album_info.id)+")"] = | |
vandebo (ex-Chrome)
2013/10/31 20:53:43
Date might be a more useful uniquifier, is there a
Greg Billock
2013/10/31 22:34:24
No, there's no real good signal. There's a GUID, a
| |
304 album; | |
305 } | |
293 } | 306 } |
294 } | 307 } |
295 } else if (found_key == "Master Image List") { | 308 } else if (found_key == "Master Image List") { |
296 if (found_photos) | 309 if (found_photos) |
297 continue; | 310 continue; |
298 found_photos = true; | 311 found_photos = true; |
299 if (!ParseAllPhotos(&reader, &library_.all_photos)) | 312 if (!ParseAllPhotos(&reader, &library_.all_photos)) |
300 return false; | 313 return false; |
301 } | 314 } |
302 } | 315 } |
303 | 316 |
304 return true; | 317 return true; |
305 } | 318 } |
306 | 319 |
307 } // namespace iphoto | 320 } // namespace iphoto |
OLD | NEW |