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