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 kSupportsCreate[] = "supportsCreate"; 101 const char kSupportsImport[] = "supportsImport"; 102 const char kInstalled[] = "installed"; 103 const char kAuthorized[] = "authorized"; 104 const char kProductUrl[] = "productUrl"; 105 const char kPrimaryMimeTypes[] = "primaryMimeTypes"; 106 const char kSecondaryMimeTypes[] = "secondaryMimeTypes"; 107 const char kPrimaryFileExtensions[] = "primaryFileExtensions"; 108 const char kSecondaryFileExtensions[] = "secondaryFileExtensions"; 109 const char kIcons[] = "icons"; 110 111 // Apps List 112 // https://developers.google.com/drive/v2/reference/apps/list 113 const char kAppListKind[] = "drive#appList"; 114 115 // Parent Resource 116 // https://developers.google.com/drive/v2/reference/parents 117 const char kParentReferenceKind[] = "drive#parentReference"; 118 const char kParentLink[] = "parentLink"; 119 const char kIsRoot[] = "isRoot"; 120 121 // File Resource 122 // https://developers.google.com/drive/v2/reference/files 123 const char kFileKind[] = "drive#file"; 124 const char kTitle[] = "title"; 125 const char kMimeType[] = "mimeType"; 126 const char kCreatedDate[] = "createdDate"; 127 const char kModifiedDate[] = "modifiedDate"; 128 const char kModifiedByMeDate[] = "modifiedByMeDate"; 129 const char kLastViewedByMeDate[] = "lastViewedByMeDate"; 130 const char kSharedWithMeDate[] = "sharedWithMeDate"; 131 const char kDownloadUrl[] = "downloadUrl"; 132 const char kFileExtension[] = "fileExtension"; 133 const char kMd5Checksum[] = "md5Checksum"; 134 const char kFileSize[] = "fileSize"; 135 const char kAlternateLink[] = "alternateLink"; 136 const char kEmbedLink[] = "embedLink"; 137 const char kParents[] = "parents"; 138 const char kThumbnailLink[] = "thumbnailLink"; 139 const char kWebContentLink[] = "webContentLink"; 140 const char kOpenWithLinks[] = "openWithLinks"; 141 const char kLabels[] = "labels"; 142 const char kImageMediaMetadata[] = "imageMediaMetadata"; 143 const char kShared[] = "shared"; 144 // These 5 flags are defined under |labels|. 145 const char kLabelStarred[] = "starred"; 146 const char kLabelHidden[] = "hidden"; 147 const char kLabelTrashed[] = "trashed"; 148 const char kLabelRestricted[] = "restricted"; 149 const char kLabelViewed[] = "viewed"; 150 // These 3 flags are defined under |imageMediaMetadata|. 151 const char kImageMediaMetadataWidth[] = "width"; 152 const char kImageMediaMetadataHeight[] = "height"; 153 const char kImageMediaMetadataRotation[] = "rotation"; 154 155 const char kDriveFolderMimeType[] = "application/vnd.google-apps.folder"; 156 157 // Files List 158 // https://developers.google.com/drive/v2/reference/files/list 159 const char kFileListKind[] = "drive#fileList"; 160 const char kNextPageToken[] = "nextPageToken"; 161 const char kNextLink[] = "nextLink"; 162 163 // Change Resource 164 // https://developers.google.com/drive/v2/reference/changes 165 const char kChangeKind[] = "drive#change"; 166 const char kFileId[] = "fileId"; 167 const char kDeleted[] = "deleted"; 168 const char kFile[] = "file"; 169 170 // Changes List 171 // https://developers.google.com/drive/v2/reference/changes/list 172 const char kChangeListKind[] = "drive#changeList"; 173 174 // Maps category name to enum IconCategory. 175 struct AppIconCategoryMap { 176 DriveAppIcon::IconCategory category; 177 const char* category_name; 178 }; 179 180 const AppIconCategoryMap kAppIconCategoryMap[] = { 181 { DriveAppIcon::DOCUMENT, "document" }, 182 { DriveAppIcon::APPLICATION, "application" }, 183 { DriveAppIcon::SHARED_DOCUMENT, "documentShared" }, 184 }; 185 186 // Checks if the JSON is expected kind. In Drive API, JSON data structure has 187 // |kind| property which denotes the type of the structure (e.g. "drive#file"). 188 bool IsResourceKindExpected(const base::Value& value, 189 const std::string& expected_kind) { 190 const base::DictionaryValue* as_dict = NULL; 191 std::string kind; 192 return value.GetAsDictionary(&as_dict) && 193 as_dict->HasKey(kKind) && 194 as_dict->GetString(kKind, &kind) && 195 kind == expected_kind; 196 } 197 198 } // namespace 199 200 //////////////////////////////////////////////////////////////////////////////// 201 // AboutResource implementation 202 203 AboutResource::AboutResource() 204 : largest_change_id_(0), 205 quota_bytes_total_(0), 206 quota_bytes_used_(0) {} 207 208 AboutResource::~AboutResource() {} 209 210 // static 211 scoped_ptr<AboutResource> AboutResource::CreateFrom(const base::Value& value) { 212 scoped_ptr<AboutResource> resource(new AboutResource()); 213 if (!IsResourceKindExpected(value, kAboutKind) || !resource->Parse(value)) { 214 LOG(ERROR) << "Unable to create: Invalid About resource JSON!"; 215 return scoped_ptr<AboutResource>(); 216 } 217 return resource.Pass(); 218 } 219 220 // static 221 void AboutResource::RegisterJSONConverter( 222 base::JSONValueConverter<AboutResource>* converter) { 223 converter->RegisterCustomField<int64>(kLargestChangeId, 224 &AboutResource::largest_change_id_, 225 &base::StringToInt64); 226 converter->RegisterCustomField<int64>(kQuotaBytesTotal, 227 &AboutResource::quota_bytes_total_, 228 &base::StringToInt64); 229 converter->RegisterCustomField<int64>(kQuotaBytesUsed, 230 &AboutResource::quota_bytes_used_, 231 &base::StringToInt64); 232 converter->RegisterStringField(kRootFolderId, 233 &AboutResource::root_folder_id_); 234 } 235 236 bool AboutResource::Parse(const base::Value& value) { 237 base::JSONValueConverter<AboutResource> converter; 238 if (!converter.Convert(value, this)) { 239 LOG(ERROR) << "Unable to parse: Invalid About resource JSON!"; 240 return false; 241 } 242 return true; 243 } 244 245 //////////////////////////////////////////////////////////////////////////////// 246 // DriveAppIcon implementation 247 248 DriveAppIcon::DriveAppIcon() : category_(UNKNOWN), icon_side_length_(0) {} 249 250 DriveAppIcon::~DriveAppIcon() {} 251 252 // static 253 void DriveAppIcon::RegisterJSONConverter( 254 base::JSONValueConverter<DriveAppIcon>* converter) { 255 converter->RegisterCustomField<IconCategory>( 256 kCategory, 257 &DriveAppIcon::category_, 258 &DriveAppIcon::GetIconCategory); 259 converter->RegisterIntField(kSize, &DriveAppIcon::icon_side_length_); 260 converter->RegisterCustomField<GURL>(kIconUrl, 261 &DriveAppIcon::icon_url_, 262 GetGURLFromString); 263 } 264 265 // static 266 scoped_ptr<DriveAppIcon> DriveAppIcon::CreateFrom(const base::Value& value) { 267 scoped_ptr<DriveAppIcon> resource(new DriveAppIcon()); 268 if (!resource->Parse(value)) { 269 LOG(ERROR) << "Unable to create: Invalid DriveAppIcon JSON!"; 270 return scoped_ptr<DriveAppIcon>(); 271 } 272 return resource.Pass(); 273 } 274 275 bool DriveAppIcon::Parse(const base::Value& value) { 276 base::JSONValueConverter<DriveAppIcon> converter; 277 if (!converter.Convert(value, this)) { 278 LOG(ERROR) << "Unable to parse: Invalid DriveAppIcon"; 279 return false; 280 } 281 return true; 282 } 283 284 // static 285 bool DriveAppIcon::GetIconCategory(const base::StringPiece& category, 286 DriveAppIcon::IconCategory* result) { 287 for (size_t i = 0; i < arraysize(kAppIconCategoryMap); i++) { 288 if (category == kAppIconCategoryMap[i].category_name) { 289 *result = kAppIconCategoryMap[i].category; 290 return true; 291 } 292 } 293 DVLOG(1) << "Unknown icon category " << category; 294 return false; 295 } 296 297 //////////////////////////////////////////////////////////////////////////////// 298 // AppResource implementation 299 300 AppResource::AppResource() 301 : supports_create_(false), 302 supports_import_(false), 303 installed_(false), 304 authorized_(false) { 305 } 306 307 AppResource::~AppResource() {} 308 309 // static 310 void AppResource::RegisterJSONConverter( 311 base::JSONValueConverter<AppResource>* converter) { 312 converter->RegisterStringField(kId, &AppResource::application_id_); 313 converter->RegisterStringField(kName, &AppResource::name_); 314 converter->RegisterStringField(kObjectType, &AppResource::object_type_); 315 converter->RegisterBoolField(kSupportsCreate, &AppResource::supports_create_); 316 converter->RegisterBoolField(kSupportsImport, &AppResource::supports_import_); 317 converter->RegisterBoolField(kInstalled, &AppResource::installed_); 318 converter->RegisterBoolField(kAuthorized, &AppResource::authorized_); 319 converter->RegisterCustomField<GURL>(kProductUrl, 320 &AppResource::product_url_, 321 GetGURLFromString); 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 } 332 333 // static 334 scoped_ptr<AppResource> AppResource::CreateFrom(const base::Value& value) { 335 scoped_ptr<AppResource> resource(new AppResource()); 336 if (!IsResourceKindExpected(value, kAppKind) || !resource->Parse(value)) { 337 LOG(ERROR) << "Unable to create: Invalid AppResource JSON!"; 338 return scoped_ptr<AppResource>(); 339 } 340 return resource.Pass(); 341 } 342 343 bool AppResource::Parse(const base::Value& value) { 344 base::JSONValueConverter<AppResource> converter; 345 if (!converter.Convert(value, this)) { 346 LOG(ERROR) << "Unable to parse: Invalid AppResource"; 347 return false; 348 } 349 return true; 350 } 351 352 //////////////////////////////////////////////////////////////////////////////// 353 // AppList implementation 354 355 AppList::AppList() {} 356 357 AppList::~AppList() {} 358 359 // static 360 void AppList::RegisterJSONConverter( 361 base::JSONValueConverter<AppList>* converter) { 362 converter->RegisterStringField(kETag, &AppList::etag_); 363 converter->RegisterRepeatedMessage<AppResource>(kItems, 364 &AppList::items_); 365 } 366 367 // static 368 scoped_ptr<AppList> AppList::CreateFrom(const base::Value& value) { 369 scoped_ptr<AppList> resource(new AppList()); 370 if (!IsResourceKindExpected(value, kAppListKind) || !resource->Parse(value)) { 371 LOG(ERROR) << "Unable to create: Invalid AppList JSON!"; 372 return scoped_ptr<AppList>(); 373 } 374 return resource.Pass(); 375 } 376 377 bool AppList::Parse(const base::Value& value) { 378 base::JSONValueConverter<AppList> converter; 379 if (!converter.Convert(value, this)) { 380 LOG(ERROR) << "Unable to parse: Invalid AppList"; 381 return false; 382 } 383 return true; 384 } 385 386 //////////////////////////////////////////////////////////////////////////////// 387 // ParentReference implementation 388 389 ParentReference::ParentReference() : is_root_(false) {} 390 391 ParentReference::~ParentReference() {} 392 393 // static 394 void ParentReference::RegisterJSONConverter( 395 base::JSONValueConverter<ParentReference>* converter) { 396 converter->RegisterStringField(kId, &ParentReference::file_id_); 397 converter->RegisterCustomField<GURL>(kParentLink, 398 &ParentReference::parent_link_, 399 GetGURLFromString); 400 converter->RegisterBoolField(kIsRoot, &ParentReference::is_root_); 401 } 402 403 // static 404 scoped_ptr<ParentReference> 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 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 427 FileResource::FileResource() : shared_(false), file_size_(0) {} 428 429 FileResource::~FileResource() {} 430 431 // static 432 void FileResource::RegisterJSONConverter( 433 base::JSONValueConverter<FileResource>* converter) { 434 converter->RegisterStringField(kId, &FileResource::file_id_); 435 converter->RegisterStringField(kETag, &FileResource::etag_); 436 converter->RegisterCustomField<GURL>(kSelfLink, 437 &FileResource::self_link_, 438 GetGURLFromString); 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 kModifiedByMeDate, 454 &FileResource::modified_by_me_date_, 455 &util::GetTimeFromString); 456 converter->RegisterCustomField<base::Time>( 457 kLastViewedByMeDate, 458 &FileResource::last_viewed_by_me_date_, 459 &util::GetTimeFromString); 460 converter->RegisterCustomField<base::Time>( 461 kSharedWithMeDate, 462 &FileResource::shared_with_me_date_, 463 &util::GetTimeFromString); 464 converter->RegisterBoolField(kShared, &FileResource::shared_); 465 converter->RegisterCustomField<GURL>(kDownloadUrl, 466 &FileResource::download_url_, 467 GetGURLFromString); 468 converter->RegisterStringField(kFileExtension, 469 &FileResource::file_extension_); 470 converter->RegisterStringField(kMd5Checksum, &FileResource::md5_checksum_); 471 converter->RegisterCustomField<int64>(kFileSize, 472 &FileResource::file_size_, 473 &base::StringToInt64); 474 converter->RegisterCustomField<GURL>(kAlternateLink, 475 &FileResource::alternate_link_, 476 GetGURLFromString); 477 converter->RegisterCustomField<GURL>(kEmbedLink, 478 &FileResource::embed_link_, 479 GetGURLFromString); 480 converter->RegisterRepeatedMessage<ParentReference>(kParents, 481 &FileResource::parents_); 482 converter->RegisterCustomField<GURL>(kThumbnailLink, 483 &FileResource::thumbnail_link_, 484 GetGURLFromString); 485 converter->RegisterCustomField<GURL>(kWebContentLink, 486 &FileResource::web_content_link_, 487 GetGURLFromString); 488 converter->RegisterCustomValueField<std::vector<OpenWithLink> >( 489 kOpenWithLinks, 490 &FileResource::open_with_links_, 491 GetOpenWithLinksFromDictionaryValue); 492 } 493 494 // static 495 scoped_ptr<FileResource> FileResource::CreateFrom(const base::Value& value) { 496 scoped_ptr<FileResource> resource(new FileResource()); 497 if (!IsResourceKindExpected(value, kFileKind) || !resource->Parse(value)) { 498 LOG(ERROR) << "Unable to create: Invalid FileResource JSON!"; 499 return scoped_ptr<FileResource>(); 500 } 501 return resource.Pass(); 502 } 503 504 bool FileResource::IsDirectory() const { 505 return mime_type_ == kDriveFolderMimeType; 506 } 507 508 bool FileResource::Parse(const base::Value& value) { 509 base::JSONValueConverter<FileResource> converter; 510 if (!converter.Convert(value, this)) { 511 LOG(ERROR) << "Unable to parse: Invalid FileResource"; 512 return false; 513 } 514 return true; 515 } 516 517 //////////////////////////////////////////////////////////////////////////////// 518 // FileList implementation 519 520 FileList::FileList() {} 521 522 FileList::~FileList() {} 523 524 // static 525 void FileList::RegisterJSONConverter( 526 base::JSONValueConverter<FileList>* converter) { 527 converter->RegisterStringField(kETag, &FileList::etag_); 528 converter->RegisterStringField(kNextPageToken, &FileList::next_page_token_); 529 converter->RegisterCustomField<GURL>(kNextLink, 530 &FileList::next_link_, 531 GetGURLFromString); 532 converter->RegisterRepeatedMessage<FileResource>(kItems, 533 &FileList::items_); 534 } 535 536 // static 537 bool FileList::HasFileListKind(const base::Value& value) { 538 return IsResourceKindExpected(value, kFileListKind); 539 } 540 541 // static 542 scoped_ptr<FileList> FileList::CreateFrom(const base::Value& value) { 543 scoped_ptr<FileList> resource(new FileList()); 544 if (!HasFileListKind(value) || !resource->Parse(value)) { 545 LOG(ERROR) << "Unable to create: Invalid FileList JSON!"; 546 return scoped_ptr<FileList>(); 547 } 548 return resource.Pass(); 549 } 550 551 bool FileList::Parse(const base::Value& value) { 552 base::JSONValueConverter<FileList> converter; 553 if (!converter.Convert(value, this)) { 554 LOG(ERROR) << "Unable to parse: Invalid FileList"; 555 return false; 556 } 557 return true; 558 } 559 560 //////////////////////////////////////////////////////////////////////////////// 561 // ChangeResource implementation 562 563 ChangeResource::ChangeResource() : change_id_(0), deleted_(false) {} 564 565 ChangeResource::~ChangeResource() {} 566 567 // static 568 void ChangeResource::RegisterJSONConverter( 569 base::JSONValueConverter<ChangeResource>* converter) { 570 converter->RegisterCustomField<int64>(kId, 571 &ChangeResource::change_id_, 572 &base::StringToInt64); 573 converter->RegisterStringField(kFileId, &ChangeResource::file_id_); 574 converter->RegisterBoolField(kDeleted, &ChangeResource::deleted_); 575 converter->RegisterCustomValueField(kFile, &ChangeResource::file_, 576 &CreateFileResourceFromValue); 577 } 578 579 // static 580 scoped_ptr<ChangeResource> 581 ChangeResource::CreateFrom(const base::Value& value) { 582 scoped_ptr<ChangeResource> resource(new ChangeResource()); 583 if (!IsResourceKindExpected(value, kChangeKind) || !resource->Parse(value)) { 584 LOG(ERROR) << "Unable to create: Invalid ChangeResource JSON!"; 585 return scoped_ptr<ChangeResource>(); 586 } 587 return resource.Pass(); 588 } 589 590 bool ChangeResource::Parse(const base::Value& value) { 591 base::JSONValueConverter<ChangeResource> converter; 592 if (!converter.Convert(value, this)) { 593 LOG(ERROR) << "Unable to parse: Invalid ChangeResource"; 594 return false; 595 } 596 return true; 597 } 598 599 //////////////////////////////////////////////////////////////////////////////// 600 // ChangeList implementation 601 602 ChangeList::ChangeList() : largest_change_id_(0) {} 603 604 ChangeList::~ChangeList() {} 605 606 // static 607 void ChangeList::RegisterJSONConverter( 608 base::JSONValueConverter<ChangeList>* converter) { 609 converter->RegisterStringField(kETag, &ChangeList::etag_); 610 converter->RegisterStringField(kNextPageToken, &ChangeList::next_page_token_); 611 converter->RegisterCustomField<GURL>(kNextLink, 612 &ChangeList::next_link_, 613 GetGURLFromString); 614 converter->RegisterCustomField<int64>(kLargestChangeId, 615 &ChangeList::largest_change_id_, 616 &base::StringToInt64); 617 converter->RegisterRepeatedMessage<ChangeResource>(kItems, 618 &ChangeList::items_); 619 } 620 621 // static 622 bool ChangeList::HasChangeListKind(const base::Value& value) { 623 return IsResourceKindExpected(value, kChangeListKind); 624 } 625 626 // static 627 scoped_ptr<ChangeList> ChangeList::CreateFrom(const base::Value& value) { 628 scoped_ptr<ChangeList> resource(new ChangeList()); 629 if (!HasChangeListKind(value) || !resource->Parse(value)) { 630 LOG(ERROR) << "Unable to create: Invalid ChangeList JSON!"; 631 return scoped_ptr<ChangeList>(); 632 } 633 return resource.Pass(); 634 } 635 636 bool ChangeList::Parse(const base::Value& value) { 637 base::JSONValueConverter<ChangeList> converter; 638 if (!converter.Convert(value, this)) { 639 LOG(ERROR) << "Unable to parse: Invalid ChangeList"; 640 return false; 641 } 642 return true; 643 } 644 645 646 //////////////////////////////////////////////////////////////////////////////// 647 // FileLabels implementation 648 649 FileLabels::FileLabels() 650 : starred_(false), 651 hidden_(false), 652 trashed_(false), 653 restricted_(false), 654 viewed_(false) {} 655 656 FileLabels::~FileLabels() {} 657 658 // static 659 void FileLabels::RegisterJSONConverter( 660 base::JSONValueConverter<FileLabels>* converter) { 661 converter->RegisterBoolField(kLabelStarred, &FileLabels::starred_); 662 converter->RegisterBoolField(kLabelHidden, &FileLabels::hidden_); 663 converter->RegisterBoolField(kLabelTrashed, &FileLabels::trashed_); 664 converter->RegisterBoolField(kLabelRestricted, &FileLabels::restricted_); 665 converter->RegisterBoolField(kLabelViewed, &FileLabels::viewed_); 666 } 667 668 // static 669 scoped_ptr<FileLabels> FileLabels::CreateFrom(const base::Value& value) { 670 scoped_ptr<FileLabels> resource(new FileLabels()); 671 if (!resource->Parse(value)) { 672 LOG(ERROR) << "Unable to create: Invalid FileLabels JSON!"; 673 return scoped_ptr<FileLabels>(); 674 } 675 return resource.Pass(); 676 } 677 678 bool FileLabels::Parse(const base::Value& value) { 679 base::JSONValueConverter<FileLabels> converter; 680 if (!converter.Convert(value, this)) { 681 LOG(ERROR) << "Unable to parse: Invalid FileLabels."; 682 return false; 683 } 684 return true; 685 } 686 687 //////////////////////////////////////////////////////////////////////////////// 688 // ImageMediaMetadata implementation 689 690 ImageMediaMetadata::ImageMediaMetadata() 691 : width_(-1), 692 height_(-1), 693 rotation_(-1) {} 694 695 ImageMediaMetadata::~ImageMediaMetadata() {} 696 697 // static 698 void ImageMediaMetadata::RegisterJSONConverter( 699 base::JSONValueConverter<ImageMediaMetadata>* converter) { 700 converter->RegisterIntField(kImageMediaMetadataWidth, 701 &ImageMediaMetadata::width_); 702 converter->RegisterIntField(kImageMediaMetadataHeight, 703 &ImageMediaMetadata::height_); 704 converter->RegisterIntField(kImageMediaMetadataRotation, 705 &ImageMediaMetadata::rotation_); 706 } 707 708 // static 709 scoped_ptr<ImageMediaMetadata> ImageMediaMetadata::CreateFrom( 710 const base::Value& value) { 711 scoped_ptr<ImageMediaMetadata> resource(new ImageMediaMetadata()); 712 if (!resource->Parse(value)) { 713 LOG(ERROR) << "Unable to create: Invalid ImageMediaMetadata JSON!"; 714 return scoped_ptr<ImageMediaMetadata>(); 715 } 716 return resource.Pass(); 717 } 718 719 bool ImageMediaMetadata::Parse(const base::Value& value) { 720 return true; 721 base::JSONValueConverter<ImageMediaMetadata> converter; 722 if (!converter.Convert(value, this)) { 723 LOG(ERROR) << "Unable to parse: Invalid ImageMediaMetadata."; 724 return false; 725 } 726 return true; 727 } 728 729 } // namespace google_apis 730