Add ICU message format support
[chromium-blink-merge.git] / google_apis / drive / drive_api_parser.cc
blob9eb00d25d5dd5b139563e8378402f14844e41877
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.
5 #include "google_apis/drive/drive_api_parser.h"
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"
16 namespace google_apis {
18 namespace {
20 const int64 kUnsetFileSize = -1;
22 bool CreateFileResourceFromValue(const base::Value* value,
23 scoped_ptr<FileResource>* file) {
24 *file = FileResource::CreateFrom(*value);
25 return !!*file;
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|.
31 bool GetGURLFromString(const base::StringPiece& url_string, GURL* result) {
32 *result = GURL(url_string.as_string());
33 return true;
36 // Converts |value| to |result|.
37 bool GetParentsFromValue(const base::Value* value,
38 std::vector<ParentReference>* result) {
39 DCHECK(value);
40 DCHECK(result);
42 const base::ListValue* list_value = NULL;
43 if (!value->GetAsList(&list_value))
44 return false;
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;
55 return true;
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.
60 bool GetOpenWithLinksFromDictionaryValue(
61 const base::Value* value,
62 std::vector<FileResource::OpenWithLink>* result) {
63 DCHECK(value);
64 DCHECK(result);
66 const base::DictionaryValue* dictionary_value;
67 if (!value->GetAsDictionary(&dictionary_value))
68 return false;
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;
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);
83 return true;
86 // Drive v2 API JSON names.
88 // Definition order follows the order of documentation in
89 // https://developers.google.com/drive/v2/reference/
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";
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 kQuotaBytesUsedAggregate[] = "quotaBytesUsedAggregate";
103 const char kRootFolderId[] = "rootFolderId";
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";
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";
126 // Apps List
127 // https://developers.google.com/drive/v2/reference/apps/list
128 const char kAppListKind[] = "drive#appList";
130 // Parent Resource
131 // https://developers.google.com/drive/v2/reference/parents
132 const char kParentReferenceKind[] = "drive#parentReference";
133 const char kParentLink[] = "parentLink";
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 // URL to the share dialog UI, which is provided only in v2internal.
160 const char kShareLink[] = "shareLink";
162 const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder";
164 // Files List
165 // https://developers.google.com/drive/v2/reference/files/list
166 const char kFileListKind[] = "drive#fileList";
167 const char kNextLink[] = "nextLink";
169 // Change Resource
170 // https://developers.google.com/drive/v2/reference/changes
171 const char kChangeKind[] = "drive#change";
172 const char kFileId[] = "fileId";
173 const char kDeleted[] = "deleted";
174 const char kFile[] = "file";
176 // Changes List
177 // https://developers.google.com/drive/v2/reference/changes/list
178 const char kChangeListKind[] = "drive#changeList";
180 // Maps category name to enum IconCategory.
181 struct AppIconCategoryMap {
182 DriveAppIcon::IconCategory category;
183 const char* category_name;
186 const AppIconCategoryMap kAppIconCategoryMap[] = {
187 { DriveAppIcon::DOCUMENT, "document" },
188 { DriveAppIcon::APPLICATION, "application" },
189 { DriveAppIcon::SHARED_DOCUMENT, "documentShared" },
192 // Checks if the JSON is expected kind. In Drive API, JSON data structure has
193 // |kind| property which denotes the type of the structure (e.g. "drive#file").
194 bool IsResourceKindExpected(const base::Value& value,
195 const std::string& expected_kind) {
196 const base::DictionaryValue* as_dict = NULL;
197 std::string kind;
198 return value.GetAsDictionary(&as_dict) &&
199 as_dict->HasKey(kKind) &&
200 as_dict->GetString(kKind, &kind) &&
201 kind == expected_kind;
204 } // namespace
206 ////////////////////////////////////////////////////////////////////////////////
207 // AboutResource implementation
209 AboutResource::AboutResource()
210 : largest_change_id_(0),
211 quota_bytes_total_(0),
212 quota_bytes_used_aggregate_(0) {}
214 AboutResource::~AboutResource() {}
216 // static
217 scoped_ptr<AboutResource> AboutResource::CreateFrom(const base::Value& value) {
218 scoped_ptr<AboutResource> resource(new AboutResource());
219 if (!IsResourceKindExpected(value, kAboutKind) || !resource->Parse(value)) {
220 LOG(ERROR) << "Unable to create: Invalid About resource JSON!";
221 return scoped_ptr<AboutResource>();
223 return resource.Pass();
226 // static
227 void AboutResource::RegisterJSONConverter(
228 base::JSONValueConverter<AboutResource>* converter) {
229 converter->RegisterCustomField<int64>(kLargestChangeId,
230 &AboutResource::largest_change_id_,
231 &base::StringToInt64);
232 converter->RegisterCustomField<int64>(kQuotaBytesTotal,
233 &AboutResource::quota_bytes_total_,
234 &base::StringToInt64);
235 converter->RegisterCustomField<int64>(
236 kQuotaBytesUsedAggregate,
237 &AboutResource::quota_bytes_used_aggregate_,
238 &base::StringToInt64);
239 converter->RegisterStringField(kRootFolderId,
240 &AboutResource::root_folder_id_);
243 bool AboutResource::Parse(const base::Value& value) {
244 base::JSONValueConverter<AboutResource> converter;
245 if (!converter.Convert(value, this)) {
246 LOG(ERROR) << "Unable to parse: Invalid About resource JSON!";
247 return false;
249 return true;
252 ////////////////////////////////////////////////////////////////////////////////
253 // DriveAppIcon implementation
255 DriveAppIcon::DriveAppIcon() : category_(UNKNOWN), icon_side_length_(0) {}
257 DriveAppIcon::~DriveAppIcon() {}
259 // static
260 void DriveAppIcon::RegisterJSONConverter(
261 base::JSONValueConverter<DriveAppIcon>* converter) {
262 converter->RegisterCustomField<IconCategory>(
263 kCategory,
264 &DriveAppIcon::category_,
265 &DriveAppIcon::GetIconCategory);
266 converter->RegisterIntField(kSize, &DriveAppIcon::icon_side_length_);
267 converter->RegisterCustomField<GURL>(kIconUrl,
268 &DriveAppIcon::icon_url_,
269 GetGURLFromString);
272 // static
273 scoped_ptr<DriveAppIcon> DriveAppIcon::CreateFrom(const base::Value& value) {
274 scoped_ptr<DriveAppIcon> resource(new DriveAppIcon());
275 if (!resource->Parse(value)) {
276 LOG(ERROR) << "Unable to create: Invalid DriveAppIcon JSON!";
277 return scoped_ptr<DriveAppIcon>();
279 return resource.Pass();
282 bool DriveAppIcon::Parse(const base::Value& value) {
283 base::JSONValueConverter<DriveAppIcon> converter;
284 if (!converter.Convert(value, this)) {
285 LOG(ERROR) << "Unable to parse: Invalid DriveAppIcon";
286 return false;
288 return true;
291 // static
292 bool DriveAppIcon::GetIconCategory(const base::StringPiece& category,
293 DriveAppIcon::IconCategory* result) {
294 for (size_t i = 0; i < arraysize(kAppIconCategoryMap); i++) {
295 if (category == kAppIconCategoryMap[i].category_name) {
296 *result = kAppIconCategoryMap[i].category;
297 return true;
300 DVLOG(1) << "Unknown icon category " << category;
301 return false;
304 ////////////////////////////////////////////////////////////////////////////////
305 // AppResource implementation
307 AppResource::AppResource()
308 : supports_create_(false),
309 removable_(false) {
312 AppResource::~AppResource() {}
314 // static
315 void AppResource::RegisterJSONConverter(
316 base::JSONValueConverter<AppResource>* converter) {
317 converter->RegisterStringField(kId, &AppResource::application_id_);
318 converter->RegisterStringField(kName, &AppResource::name_);
319 converter->RegisterStringField(kObjectType, &AppResource::object_type_);
320 converter->RegisterStringField(kProductId, &AppResource::product_id_);
321 converter->RegisterBoolField(kSupportsCreate, &AppResource::supports_create_);
322 converter->RegisterBoolField(kRemovable, &AppResource::removable_);
323 converter->RegisterRepeatedString(kPrimaryMimeTypes,
324 &AppResource::primary_mimetypes_);
325 converter->RegisterRepeatedString(kSecondaryMimeTypes,
326 &AppResource::secondary_mimetypes_);
327 converter->RegisterRepeatedString(kPrimaryFileExtensions,
328 &AppResource::primary_file_extensions_);
329 converter->RegisterRepeatedString(kSecondaryFileExtensions,
330 &AppResource::secondary_file_extensions_);
331 converter->RegisterRepeatedMessage(kIcons, &AppResource::icons_);
332 converter->RegisterCustomField<GURL>(kCreateUrl,
333 &AppResource::create_url_,
334 GetGURLFromString);
337 // static
338 scoped_ptr<AppResource> AppResource::CreateFrom(const base::Value& value) {
339 scoped_ptr<AppResource> resource(new AppResource());
340 if (!IsResourceKindExpected(value, kAppKind) || !resource->Parse(value)) {
341 LOG(ERROR) << "Unable to create: Invalid AppResource JSON!";
342 return scoped_ptr<AppResource>();
344 return resource.Pass();
347 bool AppResource::Parse(const base::Value& value) {
348 base::JSONValueConverter<AppResource> converter;
349 if (!converter.Convert(value, this)) {
350 LOG(ERROR) << "Unable to parse: Invalid AppResource";
351 return false;
353 return true;
356 ////////////////////////////////////////////////////////////////////////////////
357 // AppList implementation
359 AppList::AppList() {}
361 AppList::~AppList() {}
363 // static
364 void AppList::RegisterJSONConverter(
365 base::JSONValueConverter<AppList>* converter) {
366 converter->RegisterStringField(kETag, &AppList::etag_);
367 converter->RegisterRepeatedMessage<AppResource>(kItems,
368 &AppList::items_);
371 // static
372 scoped_ptr<AppList> AppList::CreateFrom(const base::Value& value) {
373 scoped_ptr<AppList> resource(new AppList());
374 if (!IsResourceKindExpected(value, kAppListKind) || !resource->Parse(value)) {
375 LOG(ERROR) << "Unable to create: Invalid AppList JSON!";
376 return scoped_ptr<AppList>();
378 return resource.Pass();
381 bool AppList::Parse(const base::Value& value) {
382 base::JSONValueConverter<AppList> converter;
383 if (!converter.Convert(value, this)) {
384 LOG(ERROR) << "Unable to parse: Invalid AppList";
385 return false;
387 return true;
390 ////////////////////////////////////////////////////////////////////////////////
391 // ParentReference implementation
393 ParentReference::ParentReference() {}
395 ParentReference::~ParentReference() {}
397 // static
398 void ParentReference::RegisterJSONConverter(
399 base::JSONValueConverter<ParentReference>* converter) {
400 converter->RegisterStringField(kId, &ParentReference::file_id_);
401 converter->RegisterCustomField<GURL>(kParentLink,
402 &ParentReference::parent_link_,
403 GetGURLFromString);
406 // static
407 scoped_ptr<ParentReference>
408 ParentReference::CreateFrom(const base::Value& value) {
409 scoped_ptr<ParentReference> reference(new ParentReference());
410 if (!IsResourceKindExpected(value, kParentReferenceKind) ||
411 !reference->Parse(value)) {
412 LOG(ERROR) << "Unable to create: Invalid ParentRefernce JSON!";
413 return scoped_ptr<ParentReference>();
415 return reference.Pass();
418 bool ParentReference::Parse(const base::Value& value) {
419 base::JSONValueConverter<ParentReference> converter;
420 if (!converter.Convert(value, this)) {
421 LOG(ERROR) << "Unable to parse: Invalid ParentReference";
422 return false;
424 return true;
427 ////////////////////////////////////////////////////////////////////////////////
428 // FileResource implementation
430 FileResource::FileResource() : shared_(false), file_size_(kUnsetFileSize) {}
432 FileResource::~FileResource() {}
434 // static
435 void FileResource::RegisterJSONConverter(
436 base::JSONValueConverter<FileResource>* converter) {
437 converter->RegisterStringField(kId, &FileResource::file_id_);
438 converter->RegisterStringField(kETag, &FileResource::etag_);
439 converter->RegisterStringField(kTitle, &FileResource::title_);
440 converter->RegisterStringField(kMimeType, &FileResource::mime_type_);
441 converter->RegisterNestedField(kLabels, &FileResource::labels_);
442 converter->RegisterNestedField(kImageMediaMetadata,
443 &FileResource::image_media_metadata_);
444 converter->RegisterCustomField<base::Time>(
445 kCreatedDate,
446 &FileResource::created_date_,
447 &util::GetTimeFromString);
448 converter->RegisterCustomField<base::Time>(
449 kModifiedDate,
450 &FileResource::modified_date_,
451 &util::GetTimeFromString);
452 converter->RegisterCustomField<base::Time>(
453 kLastViewedByMeDate,
454 &FileResource::last_viewed_by_me_date_,
455 &util::GetTimeFromString);
456 converter->RegisterCustomField<base::Time>(
457 kSharedWithMeDate,
458 &FileResource::shared_with_me_date_,
459 &util::GetTimeFromString);
460 converter->RegisterBoolField(kShared, &FileResource::shared_);
461 converter->RegisterStringField(kMd5Checksum, &FileResource::md5_checksum_);
462 converter->RegisterCustomField<int64>(kFileSize,
463 &FileResource::file_size_,
464 &base::StringToInt64);
465 converter->RegisterCustomField<GURL>(kAlternateLink,
466 &FileResource::alternate_link_,
467 GetGURLFromString);
468 converter->RegisterCustomField<GURL>(kShareLink,
469 &FileResource::share_link_,
470 GetGURLFromString);
471 converter->RegisterCustomValueField<std::vector<ParentReference> >(
472 kParents,
473 &FileResource::parents_,
474 GetParentsFromValue);
475 converter->RegisterCustomValueField<std::vector<OpenWithLink> >(
476 kOpenWithLinks,
477 &FileResource::open_with_links_,
478 GetOpenWithLinksFromDictionaryValue);
481 // static
482 scoped_ptr<FileResource> FileResource::CreateFrom(const base::Value& value) {
483 scoped_ptr<FileResource> resource(new FileResource());
484 if (!IsResourceKindExpected(value, kFileKind) || !resource->Parse(value)) {
485 LOG(ERROR) << "Unable to create: Invalid FileResource JSON!";
486 return scoped_ptr<FileResource>();
488 return resource.Pass();
491 bool FileResource::IsDirectory() const {
492 return mime_type_ == kDriveFolderMimeType;
495 bool FileResource::IsHostedDocument() const {
496 // Hosted documents don't have fileSize field set:
497 // https://developers.google.com/drive/v2/reference/files
498 return !IsDirectory() && file_size_ == kUnsetFileSize;
501 bool FileResource::Parse(const base::Value& value) {
502 base::JSONValueConverter<FileResource> converter;
503 if (!converter.Convert(value, this)) {
504 LOG(ERROR) << "Unable to parse: Invalid FileResource";
505 return false;
507 return true;
510 ////////////////////////////////////////////////////////////////////////////////
511 // FileList implementation
513 FileList::FileList() {}
515 FileList::~FileList() {}
517 // static
518 void FileList::RegisterJSONConverter(
519 base::JSONValueConverter<FileList>* converter) {
520 converter->RegisterCustomField<GURL>(kNextLink,
521 &FileList::next_link_,
522 GetGURLFromString);
523 converter->RegisterRepeatedMessage<FileResource>(kItems,
524 &FileList::items_);
527 // static
528 bool FileList::HasFileListKind(const base::Value& value) {
529 return IsResourceKindExpected(value, kFileListKind);
532 // static
533 scoped_ptr<FileList> FileList::CreateFrom(const base::Value& value) {
534 scoped_ptr<FileList> resource(new FileList());
535 if (!HasFileListKind(value) || !resource->Parse(value)) {
536 LOG(ERROR) << "Unable to create: Invalid FileList JSON!";
537 return scoped_ptr<FileList>();
539 return resource.Pass();
542 bool FileList::Parse(const base::Value& value) {
543 base::JSONValueConverter<FileList> converter;
544 if (!converter.Convert(value, this)) {
545 LOG(ERROR) << "Unable to parse: Invalid FileList";
546 return false;
548 return true;
551 ////////////////////////////////////////////////////////////////////////////////
552 // ChangeResource implementation
554 ChangeResource::ChangeResource() : change_id_(0), deleted_(false) {}
556 ChangeResource::~ChangeResource() {}
558 // static
559 void ChangeResource::RegisterJSONConverter(
560 base::JSONValueConverter<ChangeResource>* converter) {
561 converter->RegisterCustomField<int64>(kId,
562 &ChangeResource::change_id_,
563 &base::StringToInt64);
564 converter->RegisterStringField(kFileId, &ChangeResource::file_id_);
565 converter->RegisterBoolField(kDeleted, &ChangeResource::deleted_);
566 converter->RegisterCustomValueField(kFile, &ChangeResource::file_,
567 &CreateFileResourceFromValue);
568 converter->RegisterCustomField<base::Time>(
569 kModificationDate, &ChangeResource::modification_date_,
570 &util::GetTimeFromString);
573 // static
574 scoped_ptr<ChangeResource>
575 ChangeResource::CreateFrom(const base::Value& value) {
576 scoped_ptr<ChangeResource> resource(new ChangeResource());
577 if (!IsResourceKindExpected(value, kChangeKind) || !resource->Parse(value)) {
578 LOG(ERROR) << "Unable to create: Invalid ChangeResource JSON!";
579 return scoped_ptr<ChangeResource>();
581 return resource.Pass();
584 bool ChangeResource::Parse(const base::Value& value) {
585 base::JSONValueConverter<ChangeResource> converter;
586 if (!converter.Convert(value, this)) {
587 LOG(ERROR) << "Unable to parse: Invalid ChangeResource";
588 return false;
590 return true;
593 ////////////////////////////////////////////////////////////////////////////////
594 // ChangeList implementation
596 ChangeList::ChangeList() : largest_change_id_(0) {}
598 ChangeList::~ChangeList() {}
600 // static
601 void ChangeList::RegisterJSONConverter(
602 base::JSONValueConverter<ChangeList>* converter) {
603 converter->RegisterCustomField<GURL>(kNextLink,
604 &ChangeList::next_link_,
605 GetGURLFromString);
606 converter->RegisterCustomField<int64>(kLargestChangeId,
607 &ChangeList::largest_change_id_,
608 &base::StringToInt64);
609 converter->RegisterRepeatedMessage<ChangeResource>(kItems,
610 &ChangeList::items_);
613 // static
614 bool ChangeList::HasChangeListKind(const base::Value& value) {
615 return IsResourceKindExpected(value, kChangeListKind);
618 // static
619 scoped_ptr<ChangeList> ChangeList::CreateFrom(const base::Value& value) {
620 scoped_ptr<ChangeList> resource(new ChangeList());
621 if (!HasChangeListKind(value) || !resource->Parse(value)) {
622 LOG(ERROR) << "Unable to create: Invalid ChangeList JSON!";
623 return scoped_ptr<ChangeList>();
625 return resource.Pass();
628 bool ChangeList::Parse(const base::Value& value) {
629 base::JSONValueConverter<ChangeList> converter;
630 if (!converter.Convert(value, this)) {
631 LOG(ERROR) << "Unable to parse: Invalid ChangeList";
632 return false;
634 return true;
638 ////////////////////////////////////////////////////////////////////////////////
639 // FileLabels implementation
641 FileLabels::FileLabels() : trashed_(false) {}
643 FileLabels::~FileLabels() {}
645 // static
646 void FileLabels::RegisterJSONConverter(
647 base::JSONValueConverter<FileLabels>* converter) {
648 converter->RegisterBoolField(kLabelTrashed, &FileLabels::trashed_);
651 // static
652 scoped_ptr<FileLabels> FileLabels::CreateFrom(const base::Value& value) {
653 scoped_ptr<FileLabels> resource(new FileLabels());
654 if (!resource->Parse(value)) {
655 LOG(ERROR) << "Unable to create: Invalid FileLabels JSON!";
656 return scoped_ptr<FileLabels>();
658 return resource.Pass();
661 bool FileLabels::Parse(const base::Value& value) {
662 base::JSONValueConverter<FileLabels> converter;
663 if (!converter.Convert(value, this)) {
664 LOG(ERROR) << "Unable to parse: Invalid FileLabels.";
665 return false;
667 return true;
670 ////////////////////////////////////////////////////////////////////////////////
671 // ImageMediaMetadata implementation
673 ImageMediaMetadata::ImageMediaMetadata()
674 : width_(-1),
675 height_(-1),
676 rotation_(-1) {}
678 ImageMediaMetadata::~ImageMediaMetadata() {}
680 // static
681 void ImageMediaMetadata::RegisterJSONConverter(
682 base::JSONValueConverter<ImageMediaMetadata>* converter) {
683 converter->RegisterIntField(kImageMediaMetadataWidth,
684 &ImageMediaMetadata::width_);
685 converter->RegisterIntField(kImageMediaMetadataHeight,
686 &ImageMediaMetadata::height_);
687 converter->RegisterIntField(kImageMediaMetadataRotation,
688 &ImageMediaMetadata::rotation_);
691 // static
692 scoped_ptr<ImageMediaMetadata> ImageMediaMetadata::CreateFrom(
693 const base::Value& value) {
694 scoped_ptr<ImageMediaMetadata> resource(new ImageMediaMetadata());
695 if (!resource->Parse(value)) {
696 LOG(ERROR) << "Unable to create: Invalid ImageMediaMetadata JSON!";
697 return scoped_ptr<ImageMediaMetadata>();
699 return resource.Pass();
702 bool ImageMediaMetadata::Parse(const base::Value& value) {
703 base::JSONValueConverter<ImageMediaMetadata> converter;
704 if (!converter.Convert(value, this)) {
705 LOG(ERROR) << "Unable to parse: Invalid ImageMediaMetadata.";
706 return false;
708 return true;
711 } // namespace google_apis