Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / google_apis / drive / drive_api_parser.cc
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 "google_apis/drive/drive_api_parser.h"
6
7 #include <algorithm>
8
9 #include "base/basictypes.h"
10 #include "base/files/file_path.h"
11 #include "base/json/json_value_converter.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_piece.h"
15 #include "base/strings/string_util.h"
16 #include "base/values.h"
17 #include "google_apis/drive/time_util.h"
18
19 using base::Value;
20 using base::DictionaryValue;
21 using base::ListValue;
22
23 namespace google_apis {
24
25 namespace {
26
27 bool CreateFileResourceFromValue(const base::Value* value,
28                                  scoped_ptr<FileResource>* file) {
29   *file = FileResource::CreateFrom(*value);
30   return !!*file;
31 }
32
33 // Converts |url_string| to |result|.  Always returns true to be used
34 // for JSONValueConverter::RegisterCustomField method.
35 // TODO(mukai): make it return false in case of invalid |url_string|.
36 bool GetGURLFromString(const base::StringPiece& url_string, GURL* result) {
37   *result = GURL(url_string.as_string());
38   return true;
39 }
40
41 // Converts |value| to |result|. The key of |value| is app_id, and its value
42 // is URL to open the resource on the web app.
43 bool GetOpenWithLinksFromDictionaryValue(
44     const base::Value* value,
45     std::vector<FileResource::OpenWithLink>* result) {
46   DCHECK(value);
47   DCHECK(result);
48
49   const base::DictionaryValue* dictionary_value;
50   if (!value->GetAsDictionary(&dictionary_value))
51     return false;
52
53   result->reserve(dictionary_value->size());
54   for (DictionaryValue::Iterator iter(*dictionary_value);
55        !iter.IsAtEnd(); iter.Advance()) {
56     std::string string_value;
57     if (!iter.value().GetAsString(&string_value))
58       return false;
59
60     FileResource::OpenWithLink open_with_link;
61     open_with_link.app_id = iter.key();
62     open_with_link.open_url = GURL(string_value);
63     result->push_back(open_with_link);
64   }
65
66   return true;
67 }
68
69 // Drive v2 API JSON names.
70
71 // Definition order follows the order of documentation in
72 // https://developers.google.com/drive/v2/reference/
73
74 // Common
75 const char kKind[] = "kind";
76 const char kId[] = "id";
77 const char kETag[] = "etag";
78 const char kSelfLink[] = "selfLink";
79 const char kItems[] = "items";
80 const char kLargestChangeId[] = "largestChangeId";
81
82 // About Resource
83 // https://developers.google.com/drive/v2/reference/about
84 const char kAboutKind[] = "drive#about";
85 const char kQuotaBytesTotal[] = "quotaBytesTotal";
86 const char kQuotaBytesUsed[] = "quotaBytesUsed";
87 const char kRootFolderId[] = "rootFolderId";
88
89 // App Icon
90 // https://developers.google.com/drive/v2/reference/apps
91 const char kCategory[] = "category";
92 const char kSize[] = "size";
93 const char kIconUrl[] = "iconUrl";
94
95 // Apps Resource
96 // https://developers.google.com/drive/v2/reference/apps
97 const char kAppKind[] = "drive#app";
98 const char kName[] = "name";
99 const char kObjectType[] = "objectType";
100 const char kProductId[] = "productId";
101 const char kSupportsCreate[] = "supportsCreate";
102 const char kSupportsImport[] = "supportsImport";
103 const char kInstalled[] = "installed";
104 const char kAuthorized[] = "authorized";
105 const char kRemovable[] = "removable";
106 const char kPrimaryMimeTypes[] = "primaryMimeTypes";
107 const char kSecondaryMimeTypes[] = "secondaryMimeTypes";
108 const char kPrimaryFileExtensions[] = "primaryFileExtensions";
109 const char kSecondaryFileExtensions[] = "secondaryFileExtensions";
110 const char kIcons[] = "icons";
111 const char kCreateUrl[] = "createUrl";
112
113 // Apps List
114 // https://developers.google.com/drive/v2/reference/apps/list
115 const char kAppListKind[] = "drive#appList";
116
117 // Parent Resource
118 // https://developers.google.com/drive/v2/reference/parents
119 const char kParentReferenceKind[] = "drive#parentReference";
120 const char kParentLink[] = "parentLink";
121 const char kIsRoot[] = "isRoot";
122
123 // File Resource
124 // https://developers.google.com/drive/v2/reference/files
125 const char kFileKind[] = "drive#file";
126 const char kTitle[] = "title";
127 const char kMimeType[] = "mimeType";
128 const char kCreatedDate[] = "createdDate";
129 const char kModifiedDate[] = "modifiedDate";
130 const char kModifiedByMeDate[] = "modifiedByMeDate";
131 const char kLastViewedByMeDate[] = "lastViewedByMeDate";
132 const char kSharedWithMeDate[] = "sharedWithMeDate";
133 const char kDownloadUrl[] = "downloadUrl";
134 const char kFileExtension[] = "fileExtension";
135 const char kMd5Checksum[] = "md5Checksum";
136 const char kFileSize[] = "fileSize";
137 const char kAlternateLink[] = "alternateLink";
138 const char kEmbedLink[] = "embedLink";
139 const char kParents[] = "parents";
140 const char kThumbnailLink[] = "thumbnailLink";
141 const char kWebContentLink[] = "webContentLink";
142 const char kOpenWithLinks[] = "openWithLinks";
143 const char kLabels[] = "labels";
144 const char kImageMediaMetadata[] = "imageMediaMetadata";
145 const char kShared[] = "shared";
146 // These 5 flags are defined under |labels|.
147 const char kLabelStarred[] = "starred";
148 const char kLabelHidden[] = "hidden";
149 const char kLabelTrashed[] = "trashed";
150 const char kLabelRestricted[] = "restricted";
151 const char kLabelViewed[] = "viewed";
152 // These 3 flags are defined under |imageMediaMetadata|.
153 const char kImageMediaMetadataWidth[] = "width";
154 const char kImageMediaMetadataHeight[] = "height";
155 const char kImageMediaMetadataRotation[] = "rotation";
156
157 const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder";
158
159 // Files List
160 // https://developers.google.com/drive/v2/reference/files/list
161 const char kFileListKind[] = "drive#fileList";
162 const char kNextPageToken[] = "nextPageToken";
163 const char kNextLink[] = "nextLink";
164
165 // Change Resource
166 // https://developers.google.com/drive/v2/reference/changes
167 const char kChangeKind[] = "drive#change";
168 const char kFileId[] = "fileId";
169 const char kDeleted[] = "deleted";
170 const char kFile[] = "file";
171
172 // Changes List
173 // https://developers.google.com/drive/v2/reference/changes/list
174 const char kChangeListKind[] = "drive#changeList";
175
176 // Maps category name to enum IconCategory.
177 struct AppIconCategoryMap {
178   DriveAppIcon::IconCategory category;
179   const char* category_name;
180 };
181
182 const AppIconCategoryMap kAppIconCategoryMap[] = {
183   { DriveAppIcon::DOCUMENT, "document" },
184   { DriveAppIcon::APPLICATION, "application" },
185   { DriveAppIcon::SHARED_DOCUMENT, "documentShared" },
186 };
187
188 // Checks if the JSON is expected kind.  In Drive API, JSON data structure has
189 // |kind| property which denotes the type of the structure (e.g. "drive#file").
190 bool IsResourceKindExpected(const base::Value& value,
191                             const std::string& expected_kind) {
192   const base::DictionaryValue* as_dict = NULL;
193   std::string kind;
194   return value.GetAsDictionary(&as_dict) &&
195       as_dict->HasKey(kKind) &&
196       as_dict->GetString(kKind, &kind) &&
197       kind == expected_kind;
198 }
199
200 }  // namespace
201
202 ////////////////////////////////////////////////////////////////////////////////
203 // AboutResource implementation
204
205 AboutResource::AboutResource()
206     : largest_change_id_(0),
207       quota_bytes_total_(0),
208       quota_bytes_used_(0) {}
209
210 AboutResource::~AboutResource() {}
211
212 // static
213 scoped_ptr<AboutResource> AboutResource::CreateFrom(const base::Value& value) {
214   scoped_ptr<AboutResource> resource(new AboutResource());
215   if (!IsResourceKindExpected(value, kAboutKind) || !resource->Parse(value)) {
216     LOG(ERROR) << "Unable to create: Invalid About resource JSON!";
217     return scoped_ptr<AboutResource>();
218   }
219   return resource.Pass();
220 }
221
222 // static
223 void AboutResource::RegisterJSONConverter(
224     base::JSONValueConverter<AboutResource>* converter) {
225   converter->RegisterCustomField<int64>(kLargestChangeId,
226                                         &AboutResource::largest_change_id_,
227                                         &base::StringToInt64);
228   converter->RegisterCustomField<int64>(kQuotaBytesTotal,
229                                         &AboutResource::quota_bytes_total_,
230                                         &base::StringToInt64);
231   converter->RegisterCustomField<int64>(kQuotaBytesUsed,
232                                         &AboutResource::quota_bytes_used_,
233                                         &base::StringToInt64);
234   converter->RegisterStringField(kRootFolderId,
235                                  &AboutResource::root_folder_id_);
236 }
237
238 bool AboutResource::Parse(const base::Value& value) {
239   base::JSONValueConverter<AboutResource> converter;
240   if (!converter.Convert(value, this)) {
241     LOG(ERROR) << "Unable to parse: Invalid About resource JSON!";
242     return false;
243   }
244   return true;
245 }
246
247 ////////////////////////////////////////////////////////////////////////////////
248 // DriveAppIcon implementation
249
250 DriveAppIcon::DriveAppIcon() : category_(UNKNOWN), icon_side_length_(0) {}
251
252 DriveAppIcon::~DriveAppIcon() {}
253
254 // static
255 void DriveAppIcon::RegisterJSONConverter(
256     base::JSONValueConverter<DriveAppIcon>* converter) {
257   converter->RegisterCustomField<IconCategory>(
258       kCategory,
259       &DriveAppIcon::category_,
260       &DriveAppIcon::GetIconCategory);
261   converter->RegisterIntField(kSize, &DriveAppIcon::icon_side_length_);
262   converter->RegisterCustomField<GURL>(kIconUrl,
263                                        &DriveAppIcon::icon_url_,
264                                        GetGURLFromString);
265 }
266
267 // static
268 scoped_ptr<DriveAppIcon> DriveAppIcon::CreateFrom(const base::Value& value) {
269   scoped_ptr<DriveAppIcon> resource(new DriveAppIcon());
270   if (!resource->Parse(value)) {
271     LOG(ERROR) << "Unable to create: Invalid DriveAppIcon JSON!";
272     return scoped_ptr<DriveAppIcon>();
273   }
274   return resource.Pass();
275 }
276
277 bool DriveAppIcon::Parse(const base::Value& value) {
278   base::JSONValueConverter<DriveAppIcon> converter;
279   if (!converter.Convert(value, this)) {
280     LOG(ERROR) << "Unable to parse: Invalid DriveAppIcon";
281     return false;
282   }
283   return true;
284 }
285
286 // static
287 bool DriveAppIcon::GetIconCategory(const base::StringPiece& category,
288                                    DriveAppIcon::IconCategory* result) {
289   for (size_t i = 0; i < arraysize(kAppIconCategoryMap); i++) {
290     if (category == kAppIconCategoryMap[i].category_name) {
291       *result = kAppIconCategoryMap[i].category;
292       return true;
293     }
294   }
295   DVLOG(1) << "Unknown icon category " << category;
296   return false;
297 }
298
299 ////////////////////////////////////////////////////////////////////////////////
300 // AppResource implementation
301
302 AppResource::AppResource()
303     : supports_create_(false),
304       supports_import_(false),
305       installed_(false),
306       authorized_(false),
307       removable_(false) {
308 }
309
310 AppResource::~AppResource() {}
311
312 // static
313 void AppResource::RegisterJSONConverter(
314     base::JSONValueConverter<AppResource>* converter) {
315   converter->RegisterStringField(kId, &AppResource::application_id_);
316   converter->RegisterStringField(kName, &AppResource::name_);
317   converter->RegisterStringField(kObjectType, &AppResource::object_type_);
318   converter->RegisterStringField(kProductId, &AppResource::product_id_);
319   converter->RegisterBoolField(kSupportsCreate, &AppResource::supports_create_);
320   converter->RegisterBoolField(kSupportsImport, &AppResource::supports_import_);
321   converter->RegisterBoolField(kInstalled, &AppResource::installed_);
322   converter->RegisterBoolField(kAuthorized, &AppResource::authorized_);
323   converter->RegisterBoolField(kRemovable, &AppResource::removable_);
324   converter->RegisterRepeatedString(kPrimaryMimeTypes,
325                                     &AppResource::primary_mimetypes_);
326   converter->RegisterRepeatedString(kSecondaryMimeTypes,
327                                     &AppResource::secondary_mimetypes_);
328   converter->RegisterRepeatedString(kPrimaryFileExtensions,
329                                     &AppResource::primary_file_extensions_);
330   converter->RegisterRepeatedString(kSecondaryFileExtensions,
331                                     &AppResource::secondary_file_extensions_);
332   converter->RegisterRepeatedMessage(kIcons, &AppResource::icons_);
333   converter->RegisterCustomField<GURL>(kCreateUrl,
334                                        &AppResource::create_url_,
335                                        GetGURLFromString);
336 }
337
338 // static
339 scoped_ptr<AppResource> AppResource::CreateFrom(const base::Value& value) {
340   scoped_ptr<AppResource> resource(new AppResource());
341   if (!IsResourceKindExpected(value, kAppKind) || !resource->Parse(value)) {
342     LOG(ERROR) << "Unable to create: Invalid AppResource JSON!";
343     return scoped_ptr<AppResource>();
344   }
345   return resource.Pass();
346 }
347
348 bool AppResource::Parse(const base::Value& value) {
349   base::JSONValueConverter<AppResource> converter;
350   if (!converter.Convert(value, this)) {
351     LOG(ERROR) << "Unable to parse: Invalid AppResource";
352     return false;
353   }
354   return true;
355 }
356
357 ////////////////////////////////////////////////////////////////////////////////
358 // AppList implementation
359
360 AppList::AppList() {}
361
362 AppList::~AppList() {}
363
364 // static
365 void AppList::RegisterJSONConverter(
366     base::JSONValueConverter<AppList>* converter) {
367   converter->RegisterStringField(kETag, &AppList::etag_);
368   converter->RegisterRepeatedMessage<AppResource>(kItems,
369                                                    &AppList::items_);
370 }
371
372 // static
373 scoped_ptr<AppList> AppList::CreateFrom(const base::Value& value) {
374   scoped_ptr<AppList> resource(new AppList());
375   if (!IsResourceKindExpected(value, kAppListKind) || !resource->Parse(value)) {
376     LOG(ERROR) << "Unable to create: Invalid AppList JSON!";
377     return scoped_ptr<AppList>();
378   }
379   return resource.Pass();
380 }
381
382 bool AppList::Parse(const base::Value& value) {
383   base::JSONValueConverter<AppList> converter;
384   if (!converter.Convert(value, this)) {
385     LOG(ERROR) << "Unable to parse: Invalid AppList";
386     return false;
387   }
388   return true;
389 }
390
391 ////////////////////////////////////////////////////////////////////////////////
392 // ParentReference implementation
393
394 ParentReference::ParentReference() : is_root_(false) {}
395
396 ParentReference::~ParentReference() {}
397
398 // static
399 void ParentReference::RegisterJSONConverter(
400     base::JSONValueConverter<ParentReference>* converter) {
401   converter->RegisterStringField(kId, &ParentReference::file_id_);
402   converter->RegisterCustomField<GURL>(kParentLink,
403                                        &ParentReference::parent_link_,
404                                        GetGURLFromString);
405   converter->RegisterBoolField(kIsRoot, &ParentReference::is_root_);
406 }
407
408 // static
409 scoped_ptr<ParentReference>
410 ParentReference::CreateFrom(const base::Value& value) {
411   scoped_ptr<ParentReference> reference(new ParentReference());
412   if (!IsResourceKindExpected(value, kParentReferenceKind) ||
413       !reference->Parse(value)) {
414     LOG(ERROR) << "Unable to create: Invalid ParentRefernce JSON!";
415     return scoped_ptr<ParentReference>();
416   }
417   return reference.Pass();
418 }
419
420 bool ParentReference::Parse(const base::Value& value) {
421   base::JSONValueConverter<ParentReference> converter;
422   if (!converter.Convert(value, this)) {
423     LOG(ERROR) << "Unable to parse: Invalid ParentReference";
424     return false;
425   }
426   return true;
427 }
428
429 ////////////////////////////////////////////////////////////////////////////////
430 // FileResource implementation
431
432 FileResource::FileResource() : shared_(false), file_size_(0) {}
433
434 FileResource::~FileResource() {}
435
436 // static
437 void FileResource::RegisterJSONConverter(
438     base::JSONValueConverter<FileResource>* converter) {
439   converter->RegisterStringField(kId, &FileResource::file_id_);
440   converter->RegisterStringField(kETag, &FileResource::etag_);
441   converter->RegisterCustomField<GURL>(kSelfLink,
442                                        &FileResource::self_link_,
443                                        GetGURLFromString);
444   converter->RegisterStringField(kTitle, &FileResource::title_);
445   converter->RegisterStringField(kMimeType, &FileResource::mime_type_);
446   converter->RegisterNestedField(kLabels, &FileResource::labels_);
447   converter->RegisterNestedField(kImageMediaMetadata,
448                                  &FileResource::image_media_metadata_);
449   converter->RegisterCustomField<base::Time>(
450       kCreatedDate,
451       &FileResource::created_date_,
452       &util::GetTimeFromString);
453   converter->RegisterCustomField<base::Time>(
454       kModifiedDate,
455       &FileResource::modified_date_,
456       &util::GetTimeFromString);
457   converter->RegisterCustomField<base::Time>(
458       kModifiedByMeDate,
459       &FileResource::modified_by_me_date_,
460       &util::GetTimeFromString);
461   converter->RegisterCustomField<base::Time>(
462       kLastViewedByMeDate,
463       &FileResource::last_viewed_by_me_date_,
464       &util::GetTimeFromString);
465   converter->RegisterCustomField<base::Time>(
466       kSharedWithMeDate,
467       &FileResource::shared_with_me_date_,
468       &util::GetTimeFromString);
469   converter->RegisterBoolField(kShared, &FileResource::shared_);
470   converter->RegisterCustomField<GURL>(kDownloadUrl,
471                                        &FileResource::download_url_,
472                                        GetGURLFromString);
473   converter->RegisterStringField(kFileExtension,
474                                  &FileResource::file_extension_);
475   converter->RegisterStringField(kMd5Checksum, &FileResource::md5_checksum_);
476   converter->RegisterCustomField<int64>(kFileSize,
477                                         &FileResource::file_size_,
478                                         &base::StringToInt64);
479   converter->RegisterCustomField<GURL>(kAlternateLink,
480                                        &FileResource::alternate_link_,
481                                        GetGURLFromString);
482   converter->RegisterCustomField<GURL>(kEmbedLink,
483                                        &FileResource::embed_link_,
484                                        GetGURLFromString);
485   converter->RegisterRepeatedMessage<ParentReference>(kParents,
486                                                       &FileResource::parents_);
487   converter->RegisterCustomField<GURL>(kThumbnailLink,
488                                        &FileResource::thumbnail_link_,
489                                        GetGURLFromString);
490   converter->RegisterCustomField<GURL>(kWebContentLink,
491                                        &FileResource::web_content_link_,
492                                        GetGURLFromString);
493   converter->RegisterCustomValueField<std::vector<OpenWithLink> >(
494       kOpenWithLinks,
495       &FileResource::open_with_links_,
496       GetOpenWithLinksFromDictionaryValue);
497 }
498
499 // static
500 scoped_ptr<FileResource> FileResource::CreateFrom(const base::Value& value) {
501   scoped_ptr<FileResource> resource(new FileResource());
502   if (!IsResourceKindExpected(value, kFileKind) || !resource->Parse(value)) {
503     LOG(ERROR) << "Unable to create: Invalid FileResource JSON!";
504     return scoped_ptr<FileResource>();
505   }
506   return resource.Pass();
507 }
508
509 bool FileResource::IsDirectory() const {
510   return mime_type_ == kDriveFolderMimeType;
511 }
512
513 bool FileResource::Parse(const base::Value& value) {
514   base::JSONValueConverter<FileResource> converter;
515   if (!converter.Convert(value, this)) {
516     LOG(ERROR) << "Unable to parse: Invalid FileResource";
517     return false;
518   }
519   return true;
520 }
521
522 ////////////////////////////////////////////////////////////////////////////////
523 // FileList implementation
524
525 FileList::FileList() {}
526
527 FileList::~FileList() {}
528
529 // static
530 void FileList::RegisterJSONConverter(
531     base::JSONValueConverter<FileList>* converter) {
532   converter->RegisterStringField(kETag, &FileList::etag_);
533   converter->RegisterStringField(kNextPageToken, &FileList::next_page_token_);
534   converter->RegisterCustomField<GURL>(kNextLink,
535                                        &FileList::next_link_,
536                                        GetGURLFromString);
537   converter->RegisterRepeatedMessage<FileResource>(kItems,
538                                                    &FileList::items_);
539 }
540
541 // static
542 bool FileList::HasFileListKind(const base::Value& value) {
543   return IsResourceKindExpected(value, kFileListKind);
544 }
545
546 // static
547 scoped_ptr<FileList> FileList::CreateFrom(const base::Value& value) {
548   scoped_ptr<FileList> resource(new FileList());
549   if (!HasFileListKind(value) || !resource->Parse(value)) {
550     LOG(ERROR) << "Unable to create: Invalid FileList JSON!";
551     return scoped_ptr<FileList>();
552   }
553   return resource.Pass();
554 }
555
556 bool FileList::Parse(const base::Value& value) {
557   base::JSONValueConverter<FileList> converter;
558   if (!converter.Convert(value, this)) {
559     LOG(ERROR) << "Unable to parse: Invalid FileList";
560     return false;
561   }
562   return true;
563 }
564
565 ////////////////////////////////////////////////////////////////////////////////
566 // ChangeResource implementation
567
568 ChangeResource::ChangeResource() : change_id_(0), deleted_(false) {}
569
570 ChangeResource::~ChangeResource() {}
571
572 // static
573 void ChangeResource::RegisterJSONConverter(
574     base::JSONValueConverter<ChangeResource>* converter) {
575   converter->RegisterCustomField<int64>(kId,
576                                         &ChangeResource::change_id_,
577                                         &base::StringToInt64);
578   converter->RegisterStringField(kFileId, &ChangeResource::file_id_);
579   converter->RegisterBoolField(kDeleted, &ChangeResource::deleted_);
580   converter->RegisterCustomValueField(kFile, &ChangeResource::file_,
581                                       &CreateFileResourceFromValue);
582 }
583
584 // static
585 scoped_ptr<ChangeResource>
586 ChangeResource::CreateFrom(const base::Value& value) {
587   scoped_ptr<ChangeResource> resource(new ChangeResource());
588   if (!IsResourceKindExpected(value, kChangeKind) || !resource->Parse(value)) {
589     LOG(ERROR) << "Unable to create: Invalid ChangeResource JSON!";
590     return scoped_ptr<ChangeResource>();
591   }
592   return resource.Pass();
593 }
594
595 bool ChangeResource::Parse(const base::Value& value) {
596   base::JSONValueConverter<ChangeResource> converter;
597   if (!converter.Convert(value, this)) {
598     LOG(ERROR) << "Unable to parse: Invalid ChangeResource";
599     return false;
600   }
601   return true;
602 }
603
604 ////////////////////////////////////////////////////////////////////////////////
605 // ChangeList implementation
606
607 ChangeList::ChangeList() : largest_change_id_(0) {}
608
609 ChangeList::~ChangeList() {}
610
611 // static
612 void ChangeList::RegisterJSONConverter(
613     base::JSONValueConverter<ChangeList>* converter) {
614   converter->RegisterStringField(kETag, &ChangeList::etag_);
615   converter->RegisterStringField(kNextPageToken, &ChangeList::next_page_token_);
616   converter->RegisterCustomField<GURL>(kNextLink,
617                                        &ChangeList::next_link_,
618                                        GetGURLFromString);
619   converter->RegisterCustomField<int64>(kLargestChangeId,
620                                         &ChangeList::largest_change_id_,
621                                         &base::StringToInt64);
622   converter->RegisterRepeatedMessage<ChangeResource>(kItems,
623                                                      &ChangeList::items_);
624 }
625
626 // static
627 bool ChangeList::HasChangeListKind(const base::Value& value) {
628   return IsResourceKindExpected(value, kChangeListKind);
629 }
630
631 // static
632 scoped_ptr<ChangeList> ChangeList::CreateFrom(const base::Value& value) {
633   scoped_ptr<ChangeList> resource(new ChangeList());
634   if (!HasChangeListKind(value) || !resource->Parse(value)) {
635     LOG(ERROR) << "Unable to create: Invalid ChangeList JSON!";
636     return scoped_ptr<ChangeList>();
637   }
638   return resource.Pass();
639 }
640
641 bool ChangeList::Parse(const base::Value& value) {
642   base::JSONValueConverter<ChangeList> converter;
643   if (!converter.Convert(value, this)) {
644     LOG(ERROR) << "Unable to parse: Invalid ChangeList";
645     return false;
646   }
647   return true;
648 }
649
650
651 ////////////////////////////////////////////////////////////////////////////////
652 // FileLabels implementation
653
654 FileLabels::FileLabels()
655     : starred_(false),
656       hidden_(false),
657       trashed_(false),
658       restricted_(false),
659       viewed_(false) {}
660
661 FileLabels::~FileLabels() {}
662
663 // static
664 void FileLabels::RegisterJSONConverter(
665     base::JSONValueConverter<FileLabels>* converter) {
666   converter->RegisterBoolField(kLabelStarred, &FileLabels::starred_);
667   converter->RegisterBoolField(kLabelHidden, &FileLabels::hidden_);
668   converter->RegisterBoolField(kLabelTrashed, &FileLabels::trashed_);
669   converter->RegisterBoolField(kLabelRestricted, &FileLabels::restricted_);
670   converter->RegisterBoolField(kLabelViewed, &FileLabels::viewed_);
671 }
672
673 // static
674 scoped_ptr<FileLabels> FileLabels::CreateFrom(const base::Value& value) {
675   scoped_ptr<FileLabels> resource(new FileLabels());
676   if (!resource->Parse(value)) {
677     LOG(ERROR) << "Unable to create: Invalid FileLabels JSON!";
678     return scoped_ptr<FileLabels>();
679   }
680   return resource.Pass();
681 }
682
683 bool FileLabels::Parse(const base::Value& value) {
684   base::JSONValueConverter<FileLabels> converter;
685   if (!converter.Convert(value, this)) {
686     LOG(ERROR) << "Unable to parse: Invalid FileLabels.";
687     return false;
688   }
689   return true;
690 }
691
692 ////////////////////////////////////////////////////////////////////////////////
693 // ImageMediaMetadata implementation
694
695 ImageMediaMetadata::ImageMediaMetadata()
696     : width_(-1),
697       height_(-1),
698       rotation_(-1) {}
699
700 ImageMediaMetadata::~ImageMediaMetadata() {}
701
702 // static
703 void ImageMediaMetadata::RegisterJSONConverter(
704     base::JSONValueConverter<ImageMediaMetadata>* converter) {
705   converter->RegisterIntField(kImageMediaMetadataWidth,
706                               &ImageMediaMetadata::width_);
707   converter->RegisterIntField(kImageMediaMetadataHeight,
708                               &ImageMediaMetadata::height_);
709   converter->RegisterIntField(kImageMediaMetadataRotation,
710                               &ImageMediaMetadata::rotation_);
711 }
712
713 // static
714 scoped_ptr<ImageMediaMetadata> ImageMediaMetadata::CreateFrom(
715     const base::Value& value) {
716   scoped_ptr<ImageMediaMetadata> resource(new ImageMediaMetadata());
717   if (!resource->Parse(value)) {
718     LOG(ERROR) << "Unable to create: Invalid ImageMediaMetadata JSON!";
719     return scoped_ptr<ImageMediaMetadata>();
720   }
721   return resource.Pass();
722 }
723
724 bool ImageMediaMetadata::Parse(const base::Value& value) {
725   return true;
726   base::JSONValueConverter<ImageMediaMetadata> converter;
727   if (!converter.Convert(value, this)) {
728     LOG(ERROR) << "Unable to parse: Invalid ImageMediaMetadata.";
729     return false;
730   }
731   return true;
732 }
733
734 }  // namespace google_apis