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