Set Origin header to "null" for cross origin redirects.
[chromium-blink-merge.git] / google_apis / drive / drive_api_parser.cc
blob9a586c34e88628049e823c884e9ce575a98a26b8
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 kQuotaBytesUsed[] = "quotaBytesUsed";
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_(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>(kQuotaBytesUsed,
236 &AboutResource::quota_bytes_used_,
237 &base::StringToInt64);
238 converter->RegisterStringField(kRootFolderId,
239 &AboutResource::root_folder_id_);
242 bool AboutResource::Parse(const base::Value& value) {
243 base::JSONValueConverter<AboutResource> converter;
244 if (!converter.Convert(value, this)) {
245 LOG(ERROR) << "Unable to parse: Invalid About resource JSON!";
246 return false;
248 return true;
251 ////////////////////////////////////////////////////////////////////////////////
252 // DriveAppIcon implementation
254 DriveAppIcon::DriveAppIcon() : category_(UNKNOWN), icon_side_length_(0) {}
256 DriveAppIcon::~DriveAppIcon() {}
258 // static
259 void DriveAppIcon::RegisterJSONConverter(
260 base::JSONValueConverter<DriveAppIcon>* converter) {
261 converter->RegisterCustomField<IconCategory>(
262 kCategory,
263 &DriveAppIcon::category_,
264 &DriveAppIcon::GetIconCategory);
265 converter->RegisterIntField(kSize, &DriveAppIcon::icon_side_length_);
266 converter->RegisterCustomField<GURL>(kIconUrl,
267 &DriveAppIcon::icon_url_,
268 GetGURLFromString);
271 // static
272 scoped_ptr<DriveAppIcon> DriveAppIcon::CreateFrom(const base::Value& value) {
273 scoped_ptr<DriveAppIcon> resource(new DriveAppIcon());
274 if (!resource->Parse(value)) {
275 LOG(ERROR) << "Unable to create: Invalid DriveAppIcon JSON!";
276 return scoped_ptr<DriveAppIcon>();
278 return resource.Pass();
281 bool DriveAppIcon::Parse(const base::Value& value) {
282 base::JSONValueConverter<DriveAppIcon> converter;
283 if (!converter.Convert(value, this)) {
284 LOG(ERROR) << "Unable to parse: Invalid DriveAppIcon";
285 return false;
287 return true;
290 // static
291 bool DriveAppIcon::GetIconCategory(const base::StringPiece& category,
292 DriveAppIcon::IconCategory* result) {
293 for (size_t i = 0; i < arraysize(kAppIconCategoryMap); i++) {
294 if (category == kAppIconCategoryMap[i].category_name) {
295 *result = kAppIconCategoryMap[i].category;
296 return true;
299 DVLOG(1) << "Unknown icon category " << category;
300 return false;
303 ////////////////////////////////////////////////////////////////////////////////
304 // AppResource implementation
306 AppResource::AppResource()
307 : supports_create_(false),
308 removable_(false) {
311 AppResource::~AppResource() {}
313 // static
314 void AppResource::RegisterJSONConverter(
315 base::JSONValueConverter<AppResource>* converter) {
316 converter->RegisterStringField(kId, &AppResource::application_id_);
317 converter->RegisterStringField(kName, &AppResource::name_);
318 converter->RegisterStringField(kObjectType, &AppResource::object_type_);
319 converter->RegisterStringField(kProductId, &AppResource::product_id_);
320 converter->RegisterBoolField(kSupportsCreate, &AppResource::supports_create_);
321 converter->RegisterBoolField(kRemovable, &AppResource::removable_);
322 converter->RegisterRepeatedString(kPrimaryMimeTypes,
323 &AppResource::primary_mimetypes_);
324 converter->RegisterRepeatedString(kSecondaryMimeTypes,
325 &AppResource::secondary_mimetypes_);
326 converter->RegisterRepeatedString(kPrimaryFileExtensions,
327 &AppResource::primary_file_extensions_);
328 converter->RegisterRepeatedString(kSecondaryFileExtensions,
329 &AppResource::secondary_file_extensions_);
330 converter->RegisterRepeatedMessage(kIcons, &AppResource::icons_);
331 converter->RegisterCustomField<GURL>(kCreateUrl,
332 &AppResource::create_url_,
333 GetGURLFromString);
336 // static
337 scoped_ptr<AppResource> AppResource::CreateFrom(const base::Value& value) {
338 scoped_ptr<AppResource> resource(new AppResource());
339 if (!IsResourceKindExpected(value, kAppKind) || !resource->Parse(value)) {
340 LOG(ERROR) << "Unable to create: Invalid AppResource JSON!";
341 return scoped_ptr<AppResource>();
343 return resource.Pass();
346 bool AppResource::Parse(const base::Value& value) {
347 base::JSONValueConverter<AppResource> converter;
348 if (!converter.Convert(value, this)) {
349 LOG(ERROR) << "Unable to parse: Invalid AppResource";
350 return false;
352 return true;
355 ////////////////////////////////////////////////////////////////////////////////
356 // AppList implementation
358 AppList::AppList() {}
360 AppList::~AppList() {}
362 // static
363 void AppList::RegisterJSONConverter(
364 base::JSONValueConverter<AppList>* converter) {
365 converter->RegisterStringField(kETag, &AppList::etag_);
366 converter->RegisterRepeatedMessage<AppResource>(kItems,
367 &AppList::items_);
370 // static
371 scoped_ptr<AppList> AppList::CreateFrom(const base::Value& value) {
372 scoped_ptr<AppList> resource(new AppList());
373 if (!IsResourceKindExpected(value, kAppListKind) || !resource->Parse(value)) {
374 LOG(ERROR) << "Unable to create: Invalid AppList JSON!";
375 return scoped_ptr<AppList>();
377 return resource.Pass();
380 bool AppList::Parse(const base::Value& value) {
381 base::JSONValueConverter<AppList> converter;
382 if (!converter.Convert(value, this)) {
383 LOG(ERROR) << "Unable to parse: Invalid AppList";
384 return false;
386 return true;
389 ////////////////////////////////////////////////////////////////////////////////
390 // ParentReference implementation
392 ParentReference::ParentReference() {}
394 ParentReference::~ParentReference() {}
396 // static
397 void ParentReference::RegisterJSONConverter(
398 base::JSONValueConverter<ParentReference>* converter) {
399 converter->RegisterStringField(kId, &ParentReference::file_id_);
400 converter->RegisterCustomField<GURL>(kParentLink,
401 &ParentReference::parent_link_,
402 GetGURLFromString);
405 // static
406 scoped_ptr<ParentReference>
407 ParentReference::CreateFrom(const base::Value& value) {
408 scoped_ptr<ParentReference> reference(new ParentReference());
409 if (!IsResourceKindExpected(value, kParentReferenceKind) ||
410 !reference->Parse(value)) {
411 LOG(ERROR) << "Unable to create: Invalid ParentRefernce JSON!";
412 return scoped_ptr<ParentReference>();
414 return reference.Pass();
417 bool ParentReference::Parse(const base::Value& value) {
418 base::JSONValueConverter<ParentReference> converter;
419 if (!converter.Convert(value, this)) {
420 LOG(ERROR) << "Unable to parse: Invalid ParentReference";
421 return false;
423 return true;
426 ////////////////////////////////////////////////////////////////////////////////
427 // FileResource implementation
429 FileResource::FileResource() : shared_(false), file_size_(kUnsetFileSize) {}
431 FileResource::~FileResource() {}
433 // static
434 void FileResource::RegisterJSONConverter(
435 base::JSONValueConverter<FileResource>* converter) {
436 converter->RegisterStringField(kId, &FileResource::file_id_);
437 converter->RegisterStringField(kETag, &FileResource::etag_);
438 converter->RegisterStringField(kTitle, &FileResource::title_);
439 converter->RegisterStringField(kMimeType, &FileResource::mime_type_);
440 converter->RegisterNestedField(kLabels, &FileResource::labels_);
441 converter->RegisterNestedField(kImageMediaMetadata,
442 &FileResource::image_media_metadata_);
443 converter->RegisterCustomField<base::Time>(
444 kCreatedDate,
445 &FileResource::created_date_,
446 &util::GetTimeFromString);
447 converter->RegisterCustomField<base::Time>(
448 kModifiedDate,
449 &FileResource::modified_date_,
450 &util::GetTimeFromString);
451 converter->RegisterCustomField<base::Time>(
452 kLastViewedByMeDate,
453 &FileResource::last_viewed_by_me_date_,
454 &util::GetTimeFromString);
455 converter->RegisterCustomField<base::Time>(
456 kSharedWithMeDate,
457 &FileResource::shared_with_me_date_,
458 &util::GetTimeFromString);
459 converter->RegisterBoolField(kShared, &FileResource::shared_);
460 converter->RegisterStringField(kMd5Checksum, &FileResource::md5_checksum_);
461 converter->RegisterCustomField<int64>(kFileSize,
462 &FileResource::file_size_,
463 &base::StringToInt64);
464 converter->RegisterCustomField<GURL>(kAlternateLink,
465 &FileResource::alternate_link_,
466 GetGURLFromString);
467 converter->RegisterCustomField<GURL>(kShareLink,
468 &FileResource::share_link_,
469 GetGURLFromString);
470 converter->RegisterCustomValueField<std::vector<ParentReference> >(
471 kParents,
472 &FileResource::parents_,
473 GetParentsFromValue);
474 converter->RegisterCustomValueField<std::vector<OpenWithLink> >(
475 kOpenWithLinks,
476 &FileResource::open_with_links_,
477 GetOpenWithLinksFromDictionaryValue);
480 // static
481 scoped_ptr<FileResource> FileResource::CreateFrom(const base::Value& value) {
482 scoped_ptr<FileResource> resource(new FileResource());
483 if (!IsResourceKindExpected(value, kFileKind) || !resource->Parse(value)) {
484 LOG(ERROR) << "Unable to create: Invalid FileResource JSON!";
485 return scoped_ptr<FileResource>();
487 return resource.Pass();
490 bool FileResource::IsDirectory() const {
491 return mime_type_ == kDriveFolderMimeType;
494 bool FileResource::IsHostedDocument() const {
495 // Hosted documents don't have fileSize field set:
496 // https://developers.google.com/drive/v2/reference/files
497 return !IsDirectory() && file_size_ == kUnsetFileSize;
500 bool FileResource::Parse(const base::Value& value) {
501 base::JSONValueConverter<FileResource> converter;
502 if (!converter.Convert(value, this)) {
503 LOG(ERROR) << "Unable to parse: Invalid FileResource";
504 return false;
506 return true;
509 ////////////////////////////////////////////////////////////////////////////////
510 // FileList implementation
512 FileList::FileList() {}
514 FileList::~FileList() {}
516 // static
517 void FileList::RegisterJSONConverter(
518 base::JSONValueConverter<FileList>* converter) {
519 converter->RegisterCustomField<GURL>(kNextLink,
520 &FileList::next_link_,
521 GetGURLFromString);
522 converter->RegisterRepeatedMessage<FileResource>(kItems,
523 &FileList::items_);
526 // static
527 bool FileList::HasFileListKind(const base::Value& value) {
528 return IsResourceKindExpected(value, kFileListKind);
531 // static
532 scoped_ptr<FileList> FileList::CreateFrom(const base::Value& value) {
533 scoped_ptr<FileList> resource(new FileList());
534 if (!HasFileListKind(value) || !resource->Parse(value)) {
535 LOG(ERROR) << "Unable to create: Invalid FileList JSON!";
536 return scoped_ptr<FileList>();
538 return resource.Pass();
541 bool FileList::Parse(const base::Value& value) {
542 base::JSONValueConverter<FileList> converter;
543 if (!converter.Convert(value, this)) {
544 LOG(ERROR) << "Unable to parse: Invalid FileList";
545 return false;
547 return true;
550 ////////////////////////////////////////////////////////////////////////////////
551 // ChangeResource implementation
553 ChangeResource::ChangeResource() : change_id_(0), deleted_(false) {}
555 ChangeResource::~ChangeResource() {}
557 // static
558 void ChangeResource::RegisterJSONConverter(
559 base::JSONValueConverter<ChangeResource>* converter) {
560 converter->RegisterCustomField<int64>(kId,
561 &ChangeResource::change_id_,
562 &base::StringToInt64);
563 converter->RegisterStringField(kFileId, &ChangeResource::file_id_);
564 converter->RegisterBoolField(kDeleted, &ChangeResource::deleted_);
565 converter->RegisterCustomValueField(kFile, &ChangeResource::file_,
566 &CreateFileResourceFromValue);
567 converter->RegisterCustomField<base::Time>(
568 kModificationDate, &ChangeResource::modification_date_,
569 &util::GetTimeFromString);
572 // static
573 scoped_ptr<ChangeResource>
574 ChangeResource::CreateFrom(const base::Value& value) {
575 scoped_ptr<ChangeResource> resource(new ChangeResource());
576 if (!IsResourceKindExpected(value, kChangeKind) || !resource->Parse(value)) {
577 LOG(ERROR) << "Unable to create: Invalid ChangeResource JSON!";
578 return scoped_ptr<ChangeResource>();
580 return resource.Pass();
583 bool ChangeResource::Parse(const base::Value& value) {
584 base::JSONValueConverter<ChangeResource> converter;
585 if (!converter.Convert(value, this)) {
586 LOG(ERROR) << "Unable to parse: Invalid ChangeResource";
587 return false;
589 return true;
592 ////////////////////////////////////////////////////////////////////////////////
593 // ChangeList implementation
595 ChangeList::ChangeList() : largest_change_id_(0) {}
597 ChangeList::~ChangeList() {}
599 // static
600 void ChangeList::RegisterJSONConverter(
601 base::JSONValueConverter<ChangeList>* converter) {
602 converter->RegisterCustomField<GURL>(kNextLink,
603 &ChangeList::next_link_,
604 GetGURLFromString);
605 converter->RegisterCustomField<int64>(kLargestChangeId,
606 &ChangeList::largest_change_id_,
607 &base::StringToInt64);
608 converter->RegisterRepeatedMessage<ChangeResource>(kItems,
609 &ChangeList::items_);
612 // static
613 bool ChangeList::HasChangeListKind(const base::Value& value) {
614 return IsResourceKindExpected(value, kChangeListKind);
617 // static
618 scoped_ptr<ChangeList> ChangeList::CreateFrom(const base::Value& value) {
619 scoped_ptr<ChangeList> resource(new ChangeList());
620 if (!HasChangeListKind(value) || !resource->Parse(value)) {
621 LOG(ERROR) << "Unable to create: Invalid ChangeList JSON!";
622 return scoped_ptr<ChangeList>();
624 return resource.Pass();
627 bool ChangeList::Parse(const base::Value& value) {
628 base::JSONValueConverter<ChangeList> converter;
629 if (!converter.Convert(value, this)) {
630 LOG(ERROR) << "Unable to parse: Invalid ChangeList";
631 return false;
633 return true;
637 ////////////////////////////////////////////////////////////////////////////////
638 // FileLabels implementation
640 FileLabels::FileLabels() : trashed_(false) {}
642 FileLabels::~FileLabels() {}
644 // static
645 void FileLabels::RegisterJSONConverter(
646 base::JSONValueConverter<FileLabels>* converter) {
647 converter->RegisterBoolField(kLabelTrashed, &FileLabels::trashed_);
650 // static
651 scoped_ptr<FileLabels> FileLabels::CreateFrom(const base::Value& value) {
652 scoped_ptr<FileLabels> resource(new FileLabels());
653 if (!resource->Parse(value)) {
654 LOG(ERROR) << "Unable to create: Invalid FileLabels JSON!";
655 return scoped_ptr<FileLabels>();
657 return resource.Pass();
660 bool FileLabels::Parse(const base::Value& value) {
661 base::JSONValueConverter<FileLabels> converter;
662 if (!converter.Convert(value, this)) {
663 LOG(ERROR) << "Unable to parse: Invalid FileLabels.";
664 return false;
666 return true;
669 ////////////////////////////////////////////////////////////////////////////////
670 // ImageMediaMetadata implementation
672 ImageMediaMetadata::ImageMediaMetadata()
673 : width_(-1),
674 height_(-1),
675 rotation_(-1) {}
677 ImageMediaMetadata::~ImageMediaMetadata() {}
679 // static
680 void ImageMediaMetadata::RegisterJSONConverter(
681 base::JSONValueConverter<ImageMediaMetadata>* converter) {
682 converter->RegisterIntField(kImageMediaMetadataWidth,
683 &ImageMediaMetadata::width_);
684 converter->RegisterIntField(kImageMediaMetadataHeight,
685 &ImageMediaMetadata::height_);
686 converter->RegisterIntField(kImageMediaMetadataRotation,
687 &ImageMediaMetadata::rotation_);
690 // static
691 scoped_ptr<ImageMediaMetadata> ImageMediaMetadata::CreateFrom(
692 const base::Value& value) {
693 scoped_ptr<ImageMediaMetadata> resource(new ImageMediaMetadata());
694 if (!resource->Parse(value)) {
695 LOG(ERROR) << "Unable to create: Invalid ImageMediaMetadata JSON!";
696 return scoped_ptr<ImageMediaMetadata>();
698 return resource.Pass();
701 bool ImageMediaMetadata::Parse(const base::Value& value) {
702 base::JSONValueConverter<ImageMediaMetadata> converter;
703 if (!converter.Convert(value, this)) {
704 LOG(ERROR) << "Unable to parse: Invalid ImageMediaMetadata.";
705 return false;
707 return true;
710 } // namespace google_apis