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

Side by Side Diff: chrome/browser/chromeos/gdata/gdata_parser.cc

Issue 10692152: Rename gdata_parser to gdata_wapi_parser (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase. Created 8 years, 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/gdata/gdata_parser.h"
6
7 #include <algorithm>
8
9 #include "base/basictypes.h"
10 #include "base/file_path.h"
11 #include "base/json/json_value_converter.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/string_number_conversions.h"
14 #include "base/string_piece.h"
15 #include "base/string_util.h"
16 #include "base/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "third_party/libxml/chromium/libxml_utils.h"
19
20 using base::Value;
21 using base::DictionaryValue;
22 using base::ListValue;
23
24 namespace gdata {
25
26 namespace {
27
28 // Term values for kSchemeKind category:
29 const char kSchemeKind[] = "http://schemas.google.com/g/2005#kind";
30 const char kTermPrefix[] = "http://schemas.google.com/docs/2007#";
31 const char kFileTerm[] = "file";
32 const char kFolderTerm[] = "folder";
33 const char kItemTerm[] = "item";
34 const char kPdfTerm[] = "pdf";
35 const char kDocumentTerm[] = "document";
36 const char kSpreadSheetTerm[] = "spreadsheet";
37 const char kPresentationTerm[] = "presentation";
38
39 const char kSchemeLabels[] = "http://schemas.google.com/g/2005/labels";
40
41 // Node names.
42 const char kAuthorNode[] = "author";
43 const char kCategoryNode[] = "category";
44 const char kContentNode[] = "content";
45 const char kEditedNode[] = "edited";
46 const char kEmailNode[] = "email";
47 const char kEntryNode[] = "entry";
48 const char kFeedLinkNode[] = "feedLink";
49 const char kFilenameNode[] = "filename";
50 const char kIDNode[] = "id";
51 const char kLastModifiedByNode[] = "lastModifiedBy";
52 const char kLinkNode[] = "link";
53 const char kMd5ChecksumNode[] = "md5Checksum";
54 const char kModifiedByMeDateNode[] = "modifiedByMeDate";
55 const char kNameNode[] = "name";
56 const char kPublishedNode[] = "published";
57 const char kQuotaBytesUsedNode[] = "quotaBytesUsed";
58 const char kResourceIdNode[] = "resourceId";
59 const char kSizeNode[] = "size";
60 const char kSuggestedFilenameNode[] = "suggestedFilename";
61 const char kTitleNode[] = "title";
62 const char kUpdatedNode[] = "updated";
63 const char kWritersCanInviteNode[] = "writersCanInvite";
64
65 // Field names.
66 const char kAuthorField[] = "author";
67 const char kCategoryField[] = "category";
68 const char kContentField[] = "content";
69 const char kDeletedField[] = "gd$deleted";
70 const char kETagField[] = "gd$etag";
71 const char kEmailField[] = "email.$t";
72 const char kEntryField[] = "entry";
73 const char kFeedField[] = "feed";
74 const char kFeedLinkField[] = "gd$feedLink";
75 const char kFileNameField[] = "docs$filename.$t";
76 const char kHrefField[] = "href";
77 const char kIDField[] = "id.$t";
78 const char kInstalledAppField[] = "docs$installedApp";
79 const char kInstalledAppNameField[] = "docs$installedAppName";
80 const char kInstalledAppIdField[] = "docs$installedAppId";
81 const char kInstalledAppIconField[] = "docs$installedAppIcon";
82 const char kInstalledAppIconCategoryField[] = "docs$installedAppIconCategory";
83 const char kInstalledAppIconSizeField[] = "docs$installedAppIconSize";
84 const char kInstalledAppObjectTypeField[] = "docs$installedAppObjectType";
85 const char kInstalledAppPrimaryFileExtensionField[] =
86 "docs$installedAppPrimaryFileExtension";
87 const char kInstalledAppPrimaryMimeTypeField[] =
88 "docs$installedAppPrimaryMimeType";
89 const char kInstalledAppSecondaryFileExtensionField[] =
90 "docs$installedAppSecondaryFileExtension";
91 const char kInstalledAppSecondaryMimeTypeField[] =
92 "docs$installedAppSecondaryMimeType";
93 const char kInstalledAppSupportsCreateField[] =
94 "docs$installedAppSupportsCreate";
95 const char kItemsPerPageField[] = "openSearch$itemsPerPage.$t";
96 const char kLabelField[] = "label";
97 const char kLargestChangestampField[] = "docs$largestChangestamp.value";
98 const char kLinkField[] = "link";
99 const char kMD5Field[] = "docs$md5Checksum.$t";
100 const char kNameField[] = "name.$t";
101 const char kPublishedField[] = "published.$t";
102 const char kQuotaBytesTotalField[] = "gd$quotaBytesTotal.$t";
103 const char kQuotaBytesUsedField[] = "gd$quotaBytesUsed.$t";
104 const char kRelField[] = "rel";
105 const char kRemovedField[] = "gd$removed";
106 const char kResourceIdField[] = "gd$resourceId.$t";
107 const char kSchemeField[] = "scheme";
108 const char kSizeField[] = "docs$size.$t";
109 const char kSrcField[] = "src";
110 const char kStartIndexField[] = "openSearch$startIndex.$t";
111 const char kSuggestedFileNameField[] = "docs$suggestedFilename.$t";
112 const char kTField[] = "$t";
113 const char kTermField[] = "term";
114 const char kTitleField[] = "title";
115 const char kTitleTField[] = "title.$t";
116 const char kTypeField[] = "type";
117 const char kUpdatedField[] = "updated.$t";
118
119 // Attribute names.
120 // Attributes are not namespace-blind as node names in XmlReader.
121 const char kETagAttr[] = "gd:etag";
122 const char kEmailAttr[] = "email";
123 const char kHrefAttr[] = "href";
124 const char kLabelAttr[] = "label";
125 const char kNameAttr[] = "name";
126 const char kRelAttr[] = "rel";
127 const char kSchemeAttr[] = "scheme";
128 const char kSrcAttr[] = "src";
129 const char kTermAttr[] = "term";
130 const char kTypeAttr[] = "type";
131 const char kValueAttr[] = "value";
132
133 // Link Prefixes
134 const char kOpenWithPrefix[] = "http://schemas.google.com/docs/2007#open-with-";
135 const size_t kOpenWithPrefixSize = arraysize(kOpenWithPrefix) - 1;
136
137 struct EntryKindMap {
138 DocumentEntry::EntryKind kind;
139 const char* entry;
140 const char* extension;
141 };
142
143 const EntryKindMap kEntryKindMap[] = {
144 { DocumentEntry::ITEM, "item", NULL},
145 { DocumentEntry::DOCUMENT, "document", ".gdoc"},
146 { DocumentEntry::SPREADSHEET, "spreadsheet", ".gsheet"},
147 { DocumentEntry::PRESENTATION, "presentation", ".gslides" },
148 { DocumentEntry::DRAWING, "drawing", ".gdraw"},
149 { DocumentEntry::TABLE, "table", ".gtable"},
150 { DocumentEntry::EXTERNAL_APP, "externalapp", ".glink"},
151 { DocumentEntry::SITE, "site", NULL},
152 { DocumentEntry::FOLDER, "folder", NULL},
153 { DocumentEntry::FILE, "file", NULL},
154 { DocumentEntry::PDF, "pdf", NULL},
155 };
156
157 struct LinkTypeMap {
158 Link::LinkType type;
159 const char* rel;
160 };
161
162 const LinkTypeMap kLinkTypeMap[] = {
163 { Link::SELF,
164 "self" },
165 { Link::NEXT,
166 "next" },
167 { Link::PARENT,
168 "http://schemas.google.com/docs/2007#parent" },
169 { Link::ALTERNATE,
170 "alternate"},
171 { Link::EDIT,
172 "edit" },
173 { Link::EDIT_MEDIA,
174 "edit-media" },
175 { Link::ALT_EDIT_MEDIA,
176 "http://schemas.google.com/docs/2007#alt-edit-media" },
177 { Link::ALT_POST,
178 "http://schemas.google.com/docs/2007#alt-post" },
179 { Link::FEED,
180 "http://schemas.google.com/g/2005#feed"},
181 { Link::POST,
182 "http://schemas.google.com/g/2005#post"},
183 { Link::BATCH,
184 "http://schemas.google.com/g/2005#batch"},
185 { Link::THUMBNAIL,
186 "http://schemas.google.com/docs/2007/thumbnail"},
187 { Link::RESUMABLE_EDIT_MEDIA,
188 "http://schemas.google.com/g/2005#resumable-edit-media"},
189 { Link::RESUMABLE_CREATE_MEDIA,
190 "http://schemas.google.com/g/2005#resumable-create-media"},
191 { Link::TABLES_FEED,
192 "http://schemas.google.com/spreadsheets/2006#tablesfeed"},
193 { Link::WORKSHEET_FEED,
194 "http://schemas.google.com/spreadsheets/2006#worksheetsfeed"},
195 { Link::EMBED,
196 "http://schemas.google.com/docs/2007#embed"},
197 { Link::PRODUCT,
198 "http://schemas.google.com/docs/2007#product"},
199 { Link::ICON,
200 "http://schemas.google.com/docs/2007#icon"},
201 };
202
203 struct FeedLinkTypeMap {
204 FeedLink::FeedLinkType type;
205 const char* rel;
206 };
207
208 const FeedLinkTypeMap kFeedLinkTypeMap[] = {
209 { FeedLink::ACL, "http://schemas.google.com/acl/2007#accessControlList" },
210 { FeedLink::REVISIONS, "http://schemas.google.com/docs/2007/revisions" },
211 };
212
213 struct CategoryTypeMap {
214 Category::CategoryType type;
215 const char* scheme;
216 };
217
218 const CategoryTypeMap kCategoryTypeMap[] = {
219 { Category::KIND, "http://schemas.google.com/g/2005#kind" },
220 { Category::LABEL, "http://schemas.google.com/g/2005/labels" },
221 };
222
223 struct AppIconCategoryMap {
224 AppIcon::IconCategory category;
225 const char* category_name;
226 };
227
228 const AppIconCategoryMap kAppIconCategoryMap[] = {
229 { AppIcon::DOCUMENT, "document" },
230 { AppIcon::APPLICATION, "application" },
231 { AppIcon::SHARED_DOCUMENT, "documentShared" },
232 };
233
234 // Converts |url_string| to |result|. Always returns true to be used
235 // for JSONValueConverter::RegisterCustomField method.
236 // TODO(mukai): make it return false in case of invalid |url_string|.
237 bool GetGURLFromString(const base::StringPiece& url_string, GURL* result) {
238 *result = GURL(url_string.as_string());
239 return true;
240 }
241
242 // Converts boolean string values like "true" into bool.
243 bool GetBoolFromString(const base::StringPiece& value, bool* result) {
244 *result = (value == "true");
245 return true;
246 }
247
248 bool SortBySize(const InstalledApp::IconList::value_type& a,
249 const InstalledApp::IconList::value_type& b) {
250 return a.first < b.first;
251 }
252
253 } // namespace
254
255 ////////////////////////////////////////////////////////////////////////////////
256 // Author implementation
257
258 Author::Author() {
259 }
260
261 // static
262 void Author::RegisterJSONConverter(
263 base::JSONValueConverter<Author>* converter) {
264 converter->RegisterStringField(kNameField, &Author::name_);
265 converter->RegisterStringField(kEmailField, &Author::email_);
266 }
267
268 Author* Author::CreateFromXml(XmlReader* xml_reader) {
269 if (xml_reader->NodeName() != kAuthorNode)
270 return NULL;
271
272 if (!xml_reader->Read())
273 return NULL;
274
275 const int depth = xml_reader->Depth();
276 Author* author = new Author();
277 bool skip_read = false;
278 do {
279 skip_read = false;
280 DVLOG(1) << "Parsing author node " << xml_reader->NodeName()
281 << ", depth = " << depth;
282 if (xml_reader->NodeName() == kNameNode) {
283 std::string name;
284 if (xml_reader->ReadElementContent(&name))
285 author->name_ = UTF8ToUTF16(name);
286 skip_read = true;
287 } else if (xml_reader->NodeName() == kEmailNode) {
288 xml_reader->ReadElementContent(&author->email_);
289 skip_read = true;
290 }
291 } while (depth == xml_reader->Depth() && (skip_read || xml_reader->Next()));
292 return author;
293 }
294
295 ////////////////////////////////////////////////////////////////////////////////
296 // Link implementation
297
298 Link::Link() : type_(Link::UNKNOWN) {
299 }
300
301 Link::~Link() {
302 }
303
304 // static
305 bool Link::GetAppID(const base::StringPiece& rel, std::string* app_id) {
306 DCHECK(app_id);
307 // Fast return path if the link clearly isn't an OPEN_WITH link.
308 if (rel.size() < kOpenWithPrefixSize) {
309 app_id->clear();
310 return true;
311 }
312
313 const std::string kOpenWithPrefixStr(kOpenWithPrefix);
314 if (StartsWithASCII(rel.as_string(), kOpenWithPrefixStr, false)) {
315 *app_id = rel.as_string().substr(kOpenWithPrefixStr.size());
316 return true;
317 }
318
319 app_id->clear();
320 return true;
321 }
322
323 // static.
324 bool Link::GetLinkType(const base::StringPiece& rel, Link::LinkType* type) {
325 DCHECK(type);
326 for (size_t i = 0; i < arraysize(kLinkTypeMap); i++) {
327 if (rel == kLinkTypeMap[i].rel) {
328 *type = kLinkTypeMap[i].type;
329 return true;
330 }
331 }
332
333 // OPEN_WITH links have extra information at the end of the rel that is unique
334 // for each one, so we can't just check the usual map. This check is slightly
335 // redundant to provide a quick skip if it's obviously not an OPEN_WITH url.
336 if (rel.size() >= kOpenWithPrefixSize &&
337 StartsWithASCII(rel.as_string(), kOpenWithPrefix, false)) {
338 *type = OPEN_WITH;
339 return true;
340 }
341
342 // Let unknown link types through, just report it; if the link type is needed
343 // in the future, add it into LinkType and kLinkTypeMap.
344 DVLOG(1) << "Ignoring unknown link type for rel " << rel;
345 *type = UNKNOWN;
346 return true;
347 }
348
349 // static
350 void Link::RegisterJSONConverter(base::JSONValueConverter<Link>* converter) {
351 converter->RegisterCustomField<Link::LinkType>(kRelField,
352 &Link::type_,
353 &Link::GetLinkType);
354 // We have to register kRelField twice because we extract two different pieces
355 // of data from the same rel field.
356 converter->RegisterCustomField<std::string>(kRelField,
357 &Link::app_id_,
358 &Link::GetAppID);
359 converter->RegisterCustomField(kHrefField, &Link::href_, &GetGURLFromString);
360 converter->RegisterStringField(kTitleField, &Link::title_);
361 converter->RegisterStringField(kTypeField, &Link::mime_type_);
362 }
363
364 // static.
365 Link* Link::CreateFromXml(XmlReader* xml_reader) {
366 if (xml_reader->NodeName() != kLinkNode)
367 return NULL;
368
369 Link* link = new Link();
370 xml_reader->NodeAttribute(kTypeAttr, &link->mime_type_);
371
372 std::string href;
373 if (xml_reader->NodeAttribute(kHrefAttr, &href))
374 link->href_ = GURL(href);
375
376 std::string rel;
377 if (xml_reader->NodeAttribute(kRelAttr, &rel)) {
378 GetLinkType(rel, &link->type_);
379 if (link->type_ == OPEN_WITH)
380 GetAppID(rel, &link->app_id_);
381 }
382
383 return link;
384 }
385
386 ////////////////////////////////////////////////////////////////////////////////
387 // FeedLink implementation
388
389 FeedLink::FeedLink() : type_(FeedLink::UNKNOWN) {
390 }
391
392 // static.
393 bool FeedLink::GetFeedLinkType(
394 const base::StringPiece& rel, FeedLink::FeedLinkType* result) {
395 for (size_t i = 0; i < arraysize(kFeedLinkTypeMap); i++) {
396 if (rel == kFeedLinkTypeMap[i].rel) {
397 *result = kFeedLinkTypeMap[i].type;
398 return true;
399 }
400 }
401 DVLOG(1) << "Unknown feed link type for rel " << rel;
402 return false;
403 }
404
405 // static
406 void FeedLink::RegisterJSONConverter(
407 base::JSONValueConverter<FeedLink>* converter) {
408 converter->RegisterCustomField<FeedLink::FeedLinkType>(
409 kRelField, &FeedLink::type_, &FeedLink::GetFeedLinkType);
410 converter->RegisterCustomField(
411 kHrefField, &FeedLink::href_, &GetGURLFromString);
412 }
413
414 // static
415 FeedLink* FeedLink::CreateFromXml(XmlReader* xml_reader) {
416 if (xml_reader->NodeName() != kFeedLinkNode)
417 return NULL;
418
419 FeedLink* link = new FeedLink();
420 std::string href;
421 if (xml_reader->NodeAttribute(kHrefAttr, &href))
422 link->href_ = GURL(href);
423
424 std::string rel;
425 if (xml_reader->NodeAttribute(kRelAttr, &rel))
426 GetFeedLinkType(rel, &link->type_);
427
428 return link;
429 }
430
431 ////////////////////////////////////////////////////////////////////////////////
432 // Category implementation
433
434 Category::Category() : type_(UNKNOWN) {
435 }
436
437 // Converts category.scheme into CategoryType enum.
438 bool Category::GetCategoryTypeFromScheme(
439 const base::StringPiece& scheme, Category::CategoryType* result) {
440 for (size_t i = 0; i < arraysize(kCategoryTypeMap); i++) {
441 if (scheme == kCategoryTypeMap[i].scheme) {
442 *result = kCategoryTypeMap[i].type;
443 return true;
444 }
445 }
446 DVLOG(1) << "Unknown feed link type for scheme " << scheme;
447 return false;
448 }
449
450 // static
451 void Category::RegisterJSONConverter(
452 base::JSONValueConverter<Category>* converter) {
453 converter->RegisterStringField(kLabelField, &Category::label_);
454 converter->RegisterCustomField<Category::CategoryType>(
455 kSchemeField, &Category::type_, &Category::GetCategoryTypeFromScheme);
456 converter->RegisterStringField(kTermField, &Category::term_);
457 }
458
459 // static
460 Category* Category::CreateFromXml(XmlReader* xml_reader) {
461 if (xml_reader->NodeName() != kCategoryNode)
462 return NULL;
463
464 Category* category = new Category();
465 xml_reader->NodeAttribute(kTermAttr, &category->term_);
466
467 std::string scheme;
468 if (xml_reader->NodeAttribute(kSchemeAttr, &scheme))
469 GetCategoryTypeFromScheme(scheme, &category->type_);
470
471 std::string label;
472 if (xml_reader->NodeAttribute(kLabelAttr, &label))
473 category->label_ = UTF8ToUTF16(label);
474
475 return category;
476 }
477
478 const Link* FeedEntry::GetLinkByType(Link::LinkType type) const {
479 for (size_t i = 0; i < links_.size(); ++i) {
480 if (links_[i]->type() == type)
481 return links_[i];
482 }
483 return NULL;
484 }
485
486 ////////////////////////////////////////////////////////////////////////////////
487 // Content implementation
488
489 Content::Content() {
490 }
491
492 // static
493 void Content::RegisterJSONConverter(
494 base::JSONValueConverter<Content>* converter) {
495 converter->RegisterCustomField(kSrcField, &Content::url_, &GetGURLFromString);
496 converter->RegisterStringField(kTypeField, &Content::mime_type_);
497 }
498
499 Content* Content::CreateFromXml(XmlReader* xml_reader) {
500 if (xml_reader->NodeName() != kContentNode)
501 return NULL;
502
503 Content* content = new Content();
504 std::string src;
505 if (xml_reader->NodeAttribute(kSrcAttr, &src))
506 content->url_ = GURL(src);
507
508 xml_reader->NodeAttribute(kTypeAttr, &content->mime_type_);
509 return content;
510 }
511
512
513 ////////////////////////////////////////////////////////////////////////////////
514 // AppIcon implementation
515
516 AppIcon::AppIcon() : category_(AppIcon::UNKNOWN), icon_side_length_(0) {
517 }
518
519 AppIcon::~AppIcon() {
520 }
521
522 // static
523 void AppIcon::RegisterJSONConverter(
524 base::JSONValueConverter<AppIcon>* converter) {
525 converter->RegisterCustomField<AppIcon::IconCategory>(
526 kInstalledAppIconCategoryField,
527 &AppIcon::category_,
528 &AppIcon::GetIconCategory);
529 converter->RegisterCustomField<int>(kInstalledAppIconSizeField,
530 &AppIcon::icon_side_length_,
531 base::StringToInt);
532 converter->RegisterRepeatedMessage(kLinkField, &AppIcon::links_);
533 }
534
535 GURL AppIcon::GetIconURL() const {
536 for (size_t i = 0; i < links_.size(); ++i) {
537 if (links_[i]->type() == Link::ICON)
538 return links_[i]->href();
539 }
540 return GURL();
541 }
542
543 // static
544 bool AppIcon::GetIconCategory(const base::StringPiece& category,
545 AppIcon::IconCategory* result) {
546 for (size_t i = 0; i < arraysize(kAppIconCategoryMap); i++) {
547 if (category == kAppIconCategoryMap[i].category_name) {
548 *result = kAppIconCategoryMap[i].category;
549 return true;
550 }
551 }
552 DVLOG(1) << "Unknown icon category " << category;
553 return false;
554 }
555
556 ////////////////////////////////////////////////////////////////////////////////
557 // FeedEntry implementation
558
559 FeedEntry::FeedEntry() {
560 }
561
562 FeedEntry::~FeedEntry() {
563 }
564
565 // static
566 void FeedEntry::RegisterJSONConverter(
567 base::JSONValueConverter<FeedEntry>* converter) {
568 converter->RegisterStringField(kETagField, &FeedEntry::etag_);
569 converter->RegisterRepeatedMessage(kAuthorField, &FeedEntry::authors_);
570 converter->RegisterRepeatedMessage(kLinkField, &FeedEntry::links_);
571 converter->RegisterRepeatedMessage(kCategoryField, &FeedEntry::categories_);
572 converter->RegisterCustomField<base::Time>(
573 kUpdatedField,
574 &FeedEntry::updated_time_,
575 &FeedEntry::GetTimeFromString);
576 }
577
578 // static
579 bool FeedEntry::GetTimeFromString(const base::StringPiece& raw_value,
580 base::Time* time) {
581 const char kTimeParsingDelimiters[] = "-:.TZ";
582 std::vector<base::StringPiece> parts;
583 if (Tokenize(raw_value, kTimeParsingDelimiters, &parts) != 7)
584 return false;
585
586 base::Time::Exploded exploded;
587 if (!base::StringToInt(parts[0], &exploded.year) ||
588 !base::StringToInt(parts[1], &exploded.month) ||
589 !base::StringToInt(parts[2], &exploded.day_of_month) ||
590 !base::StringToInt(parts[3], &exploded.hour) ||
591 !base::StringToInt(parts[4], &exploded.minute) ||
592 !base::StringToInt(parts[5], &exploded.second) ||
593 !base::StringToInt(parts[6], &exploded.millisecond)) {
594 return false;
595 }
596
597 exploded.day_of_week = 0;
598 if (!exploded.HasValidValues())
599 return false;
600
601 *time = base::Time::FromLocalExploded(exploded);
602 return true;
603 }
604
605 ////////////////////////////////////////////////////////////////////////////////
606 // DocumentEntry implementation
607
608 DocumentEntry::DocumentEntry()
609 : kind_(DocumentEntry::UNKNOWN),
610 file_size_(0),
611 deleted_(false),
612 removed_(false) {
613 }
614
615 DocumentEntry::~DocumentEntry() {
616 }
617
618 bool DocumentEntry::HasFieldPresent(const base::Value* value,
619 bool* result) {
620 *result = (value != NULL);
621 return true;
622 }
623
624 // static
625 void DocumentEntry::RegisterJSONConverter(
626 base::JSONValueConverter<DocumentEntry>* converter) {
627 // inheritant the parent registrations.
628 FeedEntry::RegisterJSONConverter(
629 reinterpret_cast<base::JSONValueConverter<FeedEntry>*>(converter));
630 converter->RegisterStringField(
631 kResourceIdField, &DocumentEntry::resource_id_);
632 converter->RegisterStringField(kIDField, &DocumentEntry::id_);
633 converter->RegisterStringField(kTitleTField, &DocumentEntry::title_);
634 converter->RegisterCustomField<base::Time>(
635 kPublishedField, &DocumentEntry::published_time_,
636 &FeedEntry::GetTimeFromString);
637 converter->RegisterRepeatedMessage(
638 kFeedLinkField, &DocumentEntry::feed_links_);
639 converter->RegisterNestedField(kContentField, &DocumentEntry::content_);
640
641 // File properties. If the document type is not a normal file, then
642 // that's no problem because those feed must not have these fields
643 // themselves, which does not report errors.
644 converter->RegisterStringField(kFileNameField, &DocumentEntry::filename_);
645 converter->RegisterStringField(kMD5Field, &DocumentEntry::file_md5_);
646 converter->RegisterCustomField<int64>(
647 kSizeField, &DocumentEntry::file_size_, &base::StringToInt64);
648 converter->RegisterStringField(
649 kSuggestedFileNameField, &DocumentEntry::suggested_filename_);
650 // Deleted are treated as 'trashed' items on web client side. Removed files
651 // are gone for good. We treat both cases as 'deleted' for this client.
652 converter->RegisterCustomValueField<bool>(
653 kDeletedField, &DocumentEntry::deleted_, &DocumentEntry::HasFieldPresent);
654 converter->RegisterCustomValueField<bool>(
655 kRemovedField, &DocumentEntry::removed_, &DocumentEntry::HasFieldPresent);
656 }
657
658 std::string DocumentEntry::GetHostedDocumentExtension() const {
659 for (size_t i = 0; i < arraysize(kEntryKindMap); i++) {
660 if (kEntryKindMap[i].kind == kind_) {
661 if (kEntryKindMap[i].extension)
662 return std::string(kEntryKindMap[i].extension);
663 else
664 return std::string();
665 }
666 }
667 return std::string();
668 }
669
670 // static
671 bool DocumentEntry::HasHostedDocumentExtension(const FilePath& file) {
672 FilePath::StringType file_extension = file.Extension();
673 for (size_t i = 0; i < arraysize(kEntryKindMap); ++i) {
674 const char* document_extension = kEntryKindMap[i].extension;
675 if (document_extension && file_extension == document_extension)
676 return true;
677 }
678 return false;
679 }
680
681 // static
682 std::vector<int> DocumentEntry::GetAllEntryKinds() {
683 std::vector<int> entry_kinds;
684 entry_kinds.push_back(UNKNOWN);
685 for (size_t i = 0; i < arraysize(kEntryKindMap); ++i)
686 entry_kinds.push_back(kEntryKindMap[i].kind);
687 return entry_kinds;
688 }
689
690 // static
691 DocumentEntry::EntryKind DocumentEntry::GetEntryKindFromTerm(
692 const std::string& term) {
693 if (!StartsWithASCII(term, kTermPrefix, false)) {
694 DVLOG(1) << "Unexpected term prefix term " << term;
695 return DocumentEntry::UNKNOWN;
696 }
697
698 std::string type = term.substr(strlen(kTermPrefix));
699 for (size_t i = 0; i < arraysize(kEntryKindMap); i++) {
700 if (type == kEntryKindMap[i].entry)
701 return kEntryKindMap[i].kind;
702 }
703 DVLOG(1) << "Unknown entry type for term " << term << ", type " << type;
704 return DocumentEntry::UNKNOWN;
705 }
706
707 void DocumentEntry::FillRemainingFields() {
708 // Set |kind_| and |labels_| based on the |categories_| in the class.
709 // JSONValueConverter does not have the ability to catch an element in a list
710 // based on a predicate. Thus we need to iterate over |categories_| and
711 // find the elements to set these fields as a post-process.
712 for (size_t i = 0; i < categories_.size(); ++i) {
713 const Category* category = categories_[i];
714 if (category->type() == Category::KIND)
715 kind_ = GetEntryKindFromTerm(category->term());
716 else if (category->type() == Category::LABEL)
717 labels_.push_back(category->label());
718 }
719 }
720
721 // static
722 DocumentEntry* DocumentEntry::ExtractAndParse(
723 const base::Value& value) {
724 const base::DictionaryValue* as_dict = NULL;
725 base::DictionaryValue* entry_dict = NULL;
726 if (value.GetAsDictionary(&as_dict) &&
727 as_dict->GetDictionary(kEntryField, &entry_dict)) {
728 return DocumentEntry::CreateFrom(entry_dict);
729 }
730 return NULL;
731 }
732
733 // static
734 DocumentEntry* DocumentEntry::CreateFrom(const base::Value* value) {
735 base::JSONValueConverter<DocumentEntry> converter;
736 scoped_ptr<DocumentEntry> entry(new DocumentEntry());
737 if (!converter.Convert(*value, entry.get())) {
738 DVLOG(1) << "Invalid document entry!";
739 return NULL;
740 }
741
742 entry->FillRemainingFields();
743 return entry.release();
744 }
745
746 // static.
747 DocumentEntry* DocumentEntry::CreateFromXml(XmlReader* xml_reader) {
748 if (xml_reader->NodeName() != kEntryNode)
749 return NULL;
750
751 DocumentEntry* entry = new DocumentEntry();
752 xml_reader->NodeAttribute(kETagAttr, &entry->etag_);
753
754 if (!xml_reader->Read())
755 return entry;
756
757 bool skip_read = false;
758 do {
759 DVLOG(1) << "Parsing node " << xml_reader->NodeName();
760 skip_read = false;
761
762 if (xml_reader->NodeName() == kAuthorNode) {
763 scoped_ptr<Author> author(Author::CreateFromXml(xml_reader));
764 if (author.get())
765 entry->authors_.push_back(author.release());
766 }
767
768 if (xml_reader->NodeName() == kContentNode) {
769 scoped_ptr<Content> content(Content::CreateFromXml(xml_reader));
770 if (content.get())
771 entry->content_ = *content.get();
772 } else if (xml_reader->NodeName() == kLinkNode) {
773 scoped_ptr<Link> link(Link::CreateFromXml(xml_reader));
774 if (link.get())
775 entry->links_.push_back(link.release());
776 } else if (xml_reader->NodeName() == kFeedLinkNode) {
777 scoped_ptr<FeedLink> link(FeedLink::CreateFromXml(xml_reader));
778 if (link.get())
779 entry->feed_links_.push_back(link.release());
780 } else if (xml_reader->NodeName() == kCategoryNode) {
781 scoped_ptr<Category> category(Category::CreateFromXml(xml_reader));
782 if (category.get())
783 entry->categories_.push_back(category.release());
784 } else if (xml_reader->NodeName() == kUpdatedNode) {
785 std::string time;
786 if (xml_reader->ReadElementContent(&time))
787 GetTimeFromString(time, &entry->updated_time_);
788 skip_read = true;
789 } else if (xml_reader->NodeName() == kPublishedNode) {
790 std::string time;
791 if (xml_reader->ReadElementContent(&time))
792 GetTimeFromString(time, &entry->published_time_);
793 skip_read = true;
794 } else if (xml_reader->NodeName() == kIDNode) {
795 xml_reader->ReadElementContent(&entry->id_);
796 skip_read = true;
797 } else if (xml_reader->NodeName() == kResourceIdNode) {
798 xml_reader->ReadElementContent(&entry->resource_id_);
799 skip_read = true;
800 } else if (xml_reader->NodeName() == kTitleNode) {
801 std::string title;
802 if (xml_reader->ReadElementContent(&title))
803 entry->title_ = UTF8ToUTF16(title);
804 skip_read = true;
805 } else if (xml_reader->NodeName() == kFilenameNode) {
806 std::string file_name;
807 if (xml_reader->ReadElementContent(&file_name))
808 entry->filename_ = UTF8ToUTF16(file_name);
809 skip_read = true;
810 } else if (xml_reader->NodeName() == kSuggestedFilenameNode) {
811 std::string suggested_filename;
812 if (xml_reader->ReadElementContent(&suggested_filename))
813 entry->suggested_filename_ = UTF8ToUTF16(suggested_filename);
814 skip_read = true;
815 } else if (xml_reader->NodeName() == kMd5ChecksumNode) {
816 xml_reader->ReadElementContent(&entry->file_md5_);
817 skip_read = true;
818 } else if (xml_reader->NodeName() == kSizeNode) {
819 std::string size;
820 if (xml_reader->ReadElementContent(&size))
821 base::StringToInt64(size, &entry->file_size_);
822 skip_read = true;
823 } else {
824 DVLOG(1) << "Unknown node " << xml_reader->NodeName();
825 }
826 } while (skip_read || xml_reader->Next());
827
828 entry->FillRemainingFields();
829 return entry;
830 }
831
832 // static
833 std::string DocumentEntry::GetEntryNodeName() {
834 return kEntryNode;
835 }
836
837 ////////////////////////////////////////////////////////////////////////////////
838 // DocumentFeed implementation
839
840 DocumentFeed::DocumentFeed()
841 : start_index_(0),
842 items_per_page_(0),
843 largest_changestamp_(0) {
844 }
845
846 DocumentFeed::~DocumentFeed() {
847 }
848
849 // static
850 void DocumentFeed::RegisterJSONConverter(
851 base::JSONValueConverter<DocumentFeed>* converter) {
852 // inheritance
853 FeedEntry::RegisterJSONConverter(
854 reinterpret_cast<base::JSONValueConverter<FeedEntry>*>(converter));
855 // TODO(zelidrag): Once we figure out where these will be used, we should
856 // check for valid start_index_ and items_per_page_ values.
857 converter->RegisterCustomField<int>(
858 kStartIndexField, &DocumentFeed::start_index_, &base::StringToInt);
859 converter->RegisterCustomField<int>(
860 kItemsPerPageField, &DocumentFeed::items_per_page_, &base::StringToInt);
861 converter->RegisterStringField(kTitleTField, &DocumentFeed::title_);
862 converter->RegisterRepeatedMessage(kEntryField, &DocumentFeed::entries_);
863 converter->RegisterCustomField<int>(
864 kLargestChangestampField, &DocumentFeed::largest_changestamp_,
865 &base::StringToInt);
866 }
867
868 bool DocumentFeed::Parse(const base::Value& value) {
869 base::JSONValueConverter<DocumentFeed> converter;
870 if (!converter.Convert(value, this)) {
871 DVLOG(1) << "Invalid document feed!";
872 return false;
873 }
874
875 ScopedVector<DocumentEntry>::iterator iter = entries_.begin();
876 while (iter != entries_.end()) {
877 DocumentEntry* entry = (*iter);
878 entry->FillRemainingFields();
879 ++iter;
880 }
881 return true;
882 }
883
884 // static
885 scoped_ptr<DocumentFeed> DocumentFeed::ExtractAndParse(
886 const base::Value& value) {
887 const base::DictionaryValue* as_dict = NULL;
888 base::DictionaryValue* feed_dict = NULL;
889 if (value.GetAsDictionary(&as_dict) &&
890 as_dict->GetDictionary(kFeedField, &feed_dict)) {
891 return DocumentFeed::CreateFrom(*feed_dict);
892 }
893 return scoped_ptr<DocumentFeed>(NULL);
894 }
895
896 // static
897 scoped_ptr<DocumentFeed> DocumentFeed::CreateFrom(const base::Value& value) {
898 scoped_ptr<DocumentFeed> feed(new DocumentFeed());
899 if (!feed->Parse(value)) {
900 DVLOG(1) << "Invalid document feed!";
901 return scoped_ptr<DocumentFeed>(NULL);
902 }
903
904 return feed.Pass();
905 }
906
907 bool DocumentFeed::GetNextFeedURL(GURL* url) {
908 DCHECK(url);
909 for (size_t i = 0; i < links_.size(); ++i) {
910 if (links_[i]->type() == Link::NEXT) {
911 *url = links_[i]->href();
912 return true;
913 }
914 }
915 return false;
916 }
917
918 ////////////////////////////////////////////////////////////////////////////////
919 // InstalledApp implementation
920
921 InstalledApp::InstalledApp() : supports_create_(false) {
922 }
923
924 InstalledApp::~InstalledApp() {
925 }
926
927 InstalledApp::IconList InstalledApp::GetIconsForCategory(
928 AppIcon::IconCategory category) const {
929 IconList result;
930
931 for (ScopedVector<AppIcon>::const_iterator icon_iter = app_icons_.begin();
932 icon_iter != app_icons_.end(); ++icon_iter) {
933 if ((*icon_iter)->category() != category)
934 continue;
935 GURL icon_url = (*icon_iter)->GetIconURL();
936 if (icon_url.is_empty())
937 continue;
938 result.push_back(std::make_pair((*icon_iter)->icon_side_length(),
939 icon_url));
940 }
941
942 // Return a sorted list, smallest to largest.
943 std::sort(result.begin(), result.end(), SortBySize);
944 return result;
945 }
946
947 GURL InstalledApp::GetProductUrl() const {
948 for (ScopedVector<Link>::const_iterator it = links_.begin();
949 it != links_.end(); ++it) {
950 const Link* link = *it;
951 if (link->type() == Link::PRODUCT)
952 return link->href();
953 }
954 return GURL();
955 }
956
957 // static
958 bool InstalledApp::GetValueString(const base::Value* value,
959 std::string* result) {
960 const base::DictionaryValue* dict = NULL;
961 if (!value->GetAsDictionary(&dict))
962 return false;
963
964 if (!dict->GetString(kTField, result))
965 return false;
966
967 return true;
968 }
969
970 // static
971 void InstalledApp::RegisterJSONConverter(
972 base::JSONValueConverter<InstalledApp>* converter) {
973 converter->RegisterRepeatedMessage(kInstalledAppIconField,
974 &InstalledApp::app_icons_);
975 converter->RegisterStringField(kInstalledAppIdField,
976 &InstalledApp::app_id_);
977 converter->RegisterStringField(kInstalledAppNameField,
978 &InstalledApp::app_name_);
979 converter->RegisterStringField(kInstalledAppObjectTypeField,
980 &InstalledApp::object_type_);
981 converter->RegisterCustomField<bool>(kInstalledAppSupportsCreateField,
982 &InstalledApp::supports_create_,
983 &GetBoolFromString);
984 converter->RegisterRepeatedCustomValue(kInstalledAppPrimaryMimeTypeField,
985 &InstalledApp::primary_mimetypes_,
986 &GetValueString);
987 converter->RegisterRepeatedCustomValue(kInstalledAppSecondaryMimeTypeField,
988 &InstalledApp::secondary_mimetypes_,
989 &GetValueString);
990 converter->RegisterRepeatedCustomValue(kInstalledAppPrimaryFileExtensionField,
991 &InstalledApp::primary_extensions_,
992 &GetValueString);
993 converter->RegisterRepeatedCustomValue(
994 kInstalledAppSecondaryFileExtensionField,
995 &InstalledApp::secondary_extensions_,
996 &GetValueString);
997 converter->RegisterRepeatedMessage(kLinkField, &InstalledApp::links_);
998 }
999
1000 ////////////////////////////////////////////////////////////////////////////////
1001 // AccountMetadataFeed implementation
1002
1003 AccountMetadataFeed::AccountMetadataFeed()
1004 : quota_bytes_total_(0),
1005 quota_bytes_used_(0),
1006 largest_changestamp_(0) {
1007 }
1008
1009 AccountMetadataFeed::~AccountMetadataFeed() {
1010 }
1011
1012 // static
1013 void AccountMetadataFeed::RegisterJSONConverter(
1014 base::JSONValueConverter<AccountMetadataFeed>* converter) {
1015 converter->RegisterCustomField<int64>(
1016 kQuotaBytesTotalField,
1017 &AccountMetadataFeed::quota_bytes_total_,
1018 &base::StringToInt64);
1019 converter->RegisterCustomField<int64>(
1020 kQuotaBytesUsedField,
1021 &AccountMetadataFeed::quota_bytes_used_,
1022 &base::StringToInt64);
1023 converter->RegisterCustomField<int>(
1024 kLargestChangestampField,
1025 &AccountMetadataFeed::largest_changestamp_,
1026 &base::StringToInt);
1027 converter->RegisterRepeatedMessage(kInstalledAppField,
1028 &AccountMetadataFeed::installed_apps_);
1029 }
1030
1031 // static
1032 scoped_ptr<AccountMetadataFeed> AccountMetadataFeed::CreateFrom(
1033 const base::Value& value) {
1034 scoped_ptr<AccountMetadataFeed> feed(new AccountMetadataFeed());
1035 const base::DictionaryValue* dictionary = NULL;
1036 base::Value* entry = NULL;
1037 if (!value.GetAsDictionary(&dictionary) ||
1038 !dictionary->Get(kEntryField, &entry) ||
1039 !feed->Parse(*entry)) {
1040 LOG(ERROR) << "Unable to create: Invalid account metadata feed!";
1041 return scoped_ptr<AccountMetadataFeed>(NULL);
1042 }
1043
1044 return feed.Pass();
1045 }
1046
1047 bool AccountMetadataFeed::Parse(const base::Value& value) {
1048 base::JSONValueConverter<AccountMetadataFeed> converter;
1049 if (!converter.Convert(value, this)) {
1050 LOG(ERROR) << "Unable to parse: Invalid account metadata feed!";
1051 return false;
1052 }
1053 return true;
1054 }
1055
1056 } // namespace gdata
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_parser.h ('k') | chrome/browser/chromeos/gdata/gdata_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698