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 #ifndef GOOGLE_APIS_DRIVE_GDATA_WAPI_PARSER_H_ 6 #define GOOGLE_APIS_DRIVE_GDATA_WAPI_PARSER_H_ 7 8 #include <string> 9 #include <utility> 10 #include <vector> 11 12 #include "base/compiler_specific.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/scoped_vector.h" 15 #include "base/strings/string_piece.h" 16 #include "base/time/time.h" 17 #include "url/gurl.h" 18 19 namespace base { 20 class FilePath; 21 class DictionaryValue; 22 class Value; 23 24 template <class StructType> 25 class JSONValueConverter; 26 27 namespace internal { 28 template <class NestedType> 29 class RepeatedMessageConverter; 30 } // namespace internal 31 32 } // namespace base 33 34 // Defines data elements of Google Documents API as described in 35 // http://code.google.com/apis/documents/. 36 namespace google_apis { 37 38 // Defines link (URL) of an entity (document, file, feed...). Each entity could 39 // have more than one link representing it. 40 class Link { 41 public: 42 enum LinkType { 43 LINK_UNKNOWN, 44 LINK_SELF, 45 LINK_NEXT, 46 LINK_PARENT, 47 LINK_ALTERNATE, 48 LINK_EDIT, 49 LINK_EDIT_MEDIA, 50 LINK_ALT_EDIT_MEDIA, 51 LINK_ALT_POST, 52 LINK_FEED, 53 LINK_POST, 54 LINK_BATCH, 55 LINK_RESUMABLE_EDIT_MEDIA, 56 LINK_RESUMABLE_CREATE_MEDIA, 57 LINK_TABLES_FEED, 58 LINK_WORKSHEET_FEED, 59 LINK_THUMBNAIL, 60 LINK_EMBED, 61 LINK_PRODUCT, 62 LINK_ICON, 63 LINK_OPEN_WITH, 64 LINK_SHARE, 65 }; 66 Link(); 67 ~Link(); 68 69 // Registers the mapping between JSON field names and the members in 70 // this class. 71 static void RegisterJSONConverter(base::JSONValueConverter<Link>* converter); 72 73 // Type of the link. type()74 LinkType type() const { return type_; } 75 76 // URL of the link. href()77 const GURL& href() const { return href_; } 78 79 // Title of the link. title()80 const std::string& title() const { return title_; } 81 82 // For OPEN_WITH links, this contains the application ID. For all other link 83 // types, it is the empty string. app_id()84 const std::string& app_id() const { return app_id_; } 85 86 // Link MIME type. mime_type()87 const std::string& mime_type() const { return mime_type_; } 88 set_type(LinkType type)89 void set_type(LinkType type) { type_ = type; } set_href(const GURL & href)90 void set_href(const GURL& href) { href_ = href; } set_title(const std::string & title)91 void set_title(const std::string& title) { title_ = title; } set_app_id(const std::string & app_id)92 void set_app_id(const std::string& app_id) { app_id_ = app_id; } set_mime_type(const std::string & mime_type)93 void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; } 94 95 private: 96 friend class ResourceEntry; 97 // Converts value of link.rel into LinkType. Outputs to |type| and returns 98 // true when |rel| has a valid value. Otherwise does nothing and returns 99 // false. 100 static bool GetLinkType(const base::StringPiece& rel, LinkType* type); 101 102 // Converts value of link.rel to application ID, if there is one embedded in 103 // the link.rel field. Outputs to |app_id| and returns true when |rel| has a 104 // valid value. Otherwise does nothing and returns false. 105 static bool GetAppID(const base::StringPiece& rel, std::string* app_id); 106 107 LinkType type_; 108 GURL href_; 109 std::string title_; 110 std::string app_id_; 111 std::string mime_type_; 112 113 DISALLOW_COPY_AND_ASSIGN(Link); 114 }; 115 116 // Feed links define links (URLs) to special list of entries (i.e. list of 117 // previous document revisions). 118 class ResourceLink { 119 public: 120 enum ResourceLinkType { 121 FEED_LINK_UNKNOWN, 122 FEED_LINK_ACL, 123 FEED_LINK_REVISIONS, 124 }; 125 ResourceLink(); 126 127 // Registers the mapping between JSON field names and the members in 128 // this class. 129 static void RegisterJSONConverter( 130 base::JSONValueConverter<ResourceLink>* converter); 131 132 // MIME type of the feed. type()133 ResourceLinkType type() const { return type_; } 134 135 // URL of the feed. href()136 const GURL& href() const { return href_; } 137 set_type(ResourceLinkType type)138 void set_type(ResourceLinkType type) { type_ = type; } set_href(const GURL & href)139 void set_href(const GURL& href) { href_ = href; } 140 141 private: 142 friend class ResourceEntry; 143 // Converts value of gd$feedLink.rel into ResourceLinkType enum. 144 // Outputs to |result| and returns true when |rel| has a valid 145 // value. Otherwise does nothing and returns false. 146 static bool GetFeedLinkType( 147 const base::StringPiece& rel, ResourceLinkType* result); 148 149 ResourceLinkType type_; 150 GURL href_; 151 152 DISALLOW_COPY_AND_ASSIGN(ResourceLink); 153 }; 154 155 // Author represents an author of an entity. 156 class Author { 157 public: 158 Author(); 159 160 // Registers the mapping between JSON field names and the members in 161 // this class. 162 static void RegisterJSONConverter( 163 base::JSONValueConverter<Author>* converter); 164 165 // Getters. name()166 const std::string& name() const { return name_; } email()167 const std::string& email() const { return email_; } 168 set_name(const std::string & name)169 void set_name(const std::string& name) { name_ = name; } set_email(const std::string & email)170 void set_email(const std::string& email) { email_ = email; } 171 172 private: 173 friend class ResourceEntry; 174 175 std::string name_; 176 std::string email_; 177 178 DISALLOW_COPY_AND_ASSIGN(Author); 179 }; 180 181 // Entry category. 182 class Category { 183 public: 184 enum CategoryType { 185 CATEGORY_UNKNOWN, 186 CATEGORY_ITEM, 187 CATEGORY_KIND, 188 CATEGORY_LABEL, 189 }; 190 191 Category(); 192 193 // Registers the mapping between JSON field names and the members in 194 // this class. 195 static void RegisterJSONConverter( 196 base::JSONValueConverter<Category>* converter); 197 198 // Category label. label()199 const std::string& label() const { return label_; } 200 201 // Category type. type()202 CategoryType type() const { return type_; } 203 204 // Category term. term()205 const std::string& term() const { return term_; } 206 set_label(const std::string & label)207 void set_label(const std::string& label) { label_ = label; } set_type(CategoryType type)208 void set_type(CategoryType type) { type_ = type; } set_term(const std::string & term)209 void set_term(const std::string& term) { term_ = term; } 210 211 private: 212 friend class ResourceEntry; 213 // Converts category scheme into CategoryType enum. For example, 214 // http://schemas.google.com/g/2005#kind => Category::CATEGORY_KIND 215 // Returns false and does not change |result| when |scheme| has an 216 // unrecognizable value. 217 static bool GetCategoryTypeFromScheme( 218 const base::StringPiece& scheme, CategoryType* result); 219 220 std::string label_; 221 CategoryType type_; 222 std::string term_; 223 224 DISALLOW_COPY_AND_ASSIGN(Category); 225 }; 226 227 // Content details of a resource: mime-type, url, and so on. 228 class Content { 229 public: 230 Content(); 231 232 // Registers the mapping between JSON field names and the members in 233 // this class. 234 static void RegisterJSONConverter( 235 base::JSONValueConverter<Content>* converter); 236 237 // The URL to download the file content. 238 // Note that the url can expire, so we'll fetch the latest resource 239 // entry before starting a download to get the download URL. url()240 const GURL& url() const { return url_; } mime_type()241 const std::string& mime_type() const { return mime_type_; } 242 set_url(const GURL & url)243 void set_url(const GURL& url) { url_ = url; } set_mime_type(const std::string & mime_type)244 void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; } 245 246 private: 247 friend class ResourceEntry; 248 249 GURL url_; 250 std::string mime_type_; 251 }; 252 253 // Base class for feed entries. This class defines fields commonly used by 254 // various feeds. 255 class CommonMetadata { 256 public: 257 CommonMetadata(); 258 virtual ~CommonMetadata(); 259 260 // Returns a link of a given |type| for this entry. If not found, it returns 261 // NULL. 262 const Link* GetLinkByType(Link::LinkType type) const; 263 264 // Entry update time. updated_time()265 base::Time updated_time() const { return updated_time_; } 266 267 // Entry ETag. etag()268 const std::string& etag() const { return etag_; } 269 270 // List of entry authors. authors()271 const ScopedVector<Author>& authors() const { return authors_; } 272 273 // List of entry links. links()274 const ScopedVector<Link>& links() const { return links_; } mutable_links()275 ScopedVector<Link>* mutable_links() { return &links_; } 276 277 // List of entry categories. categories()278 const ScopedVector<Category>& categories() const { return categories_; } 279 set_etag(const std::string & etag)280 void set_etag(const std::string& etag) { etag_ = etag; } set_authors(ScopedVector<Author> authors)281 void set_authors(ScopedVector<Author> authors) { 282 authors_ = authors.Pass(); 283 } set_links(ScopedVector<Link> links)284 void set_links(ScopedVector<Link> links) { 285 links_ = links.Pass(); 286 } set_categories(ScopedVector<Category> categories)287 void set_categories(ScopedVector<Category> categories) { 288 categories_ = categories.Pass(); 289 } set_updated_time(const base::Time & updated_time)290 void set_updated_time(const base::Time& updated_time) { 291 updated_time_ = updated_time; 292 } 293 294 protected: 295 // Registers the mapping between JSON field names and the members in 296 // this class. 297 template<typename CommonMetadataDescendant> 298 static void RegisterJSONConverter( 299 base::JSONValueConverter<CommonMetadataDescendant>* converter); 300 301 std::string etag_; 302 ScopedVector<Author> authors_; 303 ScopedVector<Link> links_; 304 ScopedVector<Category> categories_; 305 base::Time updated_time_; 306 307 DISALLOW_COPY_AND_ASSIGN(CommonMetadata); 308 }; 309 310 // This class represents a resource entry. A resource is a generic term which 311 // refers to a file and a directory. 312 class ResourceEntry : public CommonMetadata { 313 public: 314 enum ResourceEntryKind { 315 ENTRY_KIND_UNKNOWN, 316 ENTRY_KIND_FOLDER, 317 ENTRY_KIND_FILE 318 }; 319 ResourceEntry(); 320 virtual ~ResourceEntry(); 321 322 // Extracts "entry" dictionary from the JSON value, and parse the contents, 323 // using CreateFrom(). Returns NULL on failure. The input JSON data, coming 324 // from the gdata server, looks like: 325 // 326 // { 327 // "encoding": "UTF-8", 328 // "entry": { ... }, // This function will extract this and parse. 329 // "version": "1.0" 330 // } 331 // 332 // The caller should delete the returned object. 333 static scoped_ptr<ResourceEntry> ExtractAndParse(const base::Value& value); 334 335 // Creates resource entry from parsed JSON Value. You should call 336 // this instead of instantiating JSONValueConverter by yourself 337 // because this method does some post-process for some fields. See 338 // FillRemainingFields comment and implementation for the details. 339 static scoped_ptr<ResourceEntry> CreateFrom(const base::Value& value); 340 341 // Returns name of entry node. 342 static std::string GetEntryNodeName(); 343 344 // Registers the mapping between JSON field names and the members in 345 // this class. 346 static void RegisterJSONConverter( 347 base::JSONValueConverter<ResourceEntry>* converter); 348 349 // Sets true to |result| if the field exists. 350 // Always returns true even when the field does not exist. 351 static bool HasFieldPresent(const base::Value* value, bool* result); 352 353 // Parses |value| as int64 and sets it to |result|. If the field does not 354 // exist, sets 0 to |result| as default value. 355 // Returns true if |value| is NULL or it is parsed as int64 successfully. 356 static bool ParseChangestamp(const base::Value* value, int64* result); 357 358 // The resource ID is used to identify a resource, which looks like: 359 // file:d41d8cd98f00b204e9800998ecf8 resource_id()360 const std::string& resource_id() const { return resource_id_; } 361 362 // This is a URL looks like: 363 // https://docs.google.com/feeds/id/file%3Ad41d8cd98f00b204e9800998ecf8. 364 // The URL is currently not used. id()365 const std::string& id() const { return id_; } 366 kind()367 ResourceEntryKind kind() const { return kind_; } title()368 const std::string& title() const { return title_; } published_time()369 base::Time published_time() const { return published_time_; } last_viewed_time()370 base::Time last_viewed_time() const { return last_viewed_time_; } labels()371 const std::vector<std::string>& labels() const { return labels_; } 372 373 // The URL to download a file content. 374 // Search for 'download_url' in gdata_wapi_requests.h for details. download_url()375 const GURL& download_url() const { return content_.url(); } 376 content_mime_type()377 const std::string& content_mime_type() const { return content_.mime_type(); } 378 379 // The resource links contain extra links for revisions and access control, 380 // etc. Note that links() contain more basic links like edit URL, 381 // alternative URL, etc. resource_links()382 const ScopedVector<ResourceLink>& resource_links() const { 383 return resource_links_; 384 } 385 386 // File name (exists only for kinds FILE and PDF). filename()387 const std::string& filename() const { return filename_; } 388 389 // Suggested file name (exists only for kinds FILE and PDF). suggested_filename()390 const std::string& suggested_filename() const { return suggested_filename_; } 391 392 // File content MD5 (exists only for kinds FILE and PDF). file_md5()393 const std::string& file_md5() const { return file_md5_; } 394 395 // File size (exists only for kinds FILE and PDF). file_size()396 int64 file_size() const { return file_size_; } 397 398 // True if the file or directory is deleted (applicable to change list only). deleted()399 bool deleted() const { return deleted_ || removed_; } 400 401 // Changestamp (exists only for change query results). 402 // If not exists, defaults to 0. changestamp()403 int64 changestamp() const { return changestamp_; } 404 405 // Image width (exists only for images). 406 // If doesn't exist, then equals -1. image_width()407 int64 image_width() const { return image_width_; } 408 409 // Image height (exists only for images). 410 // If doesn't exist, then equals -1. image_height()411 int64 image_height() const { return image_height_; } 412 413 // Image rotation in clockwise degrees (exists only for images). 414 // If doesn't exist, then equals -1. image_rotation()415 int64 image_rotation() const { return image_rotation_; } 416 417 // The time of this modification. 418 // Note: This property is filled only when converted from ChangeResource. modification_date()419 const base::Time& modification_date() const { return modification_date_; } 420 421 // Text version of resource entry kind. Returns an empty string for 422 // unknown entry kind. 423 std::string GetEntryKindText() const; 424 425 // True if resource entry is a folder (collection). is_folder()426 bool is_folder() const { 427 return kind_ == ENTRY_KIND_FOLDER; 428 } 429 // True if resource entry is regular file. is_file()430 bool is_file() const { 431 return kind_ == ENTRY_KIND_FILE; 432 } 433 set_resource_id(const std::string & resource_id)434 void set_resource_id(const std::string& resource_id) { 435 resource_id_ = resource_id; 436 } set_id(const std::string & id)437 void set_id(const std::string& id) { id_ = id; } set_kind(ResourceEntryKind kind)438 void set_kind(ResourceEntryKind kind) { kind_ = kind; } set_title(const std::string & title)439 void set_title(const std::string& title) { title_ = title; } set_published_time(const base::Time & published_time)440 void set_published_time(const base::Time& published_time) { 441 published_time_ = published_time; 442 } set_last_viewed_time(const base::Time & last_viewed_time)443 void set_last_viewed_time(const base::Time& last_viewed_time) { 444 last_viewed_time_ = last_viewed_time; 445 } set_labels(const std::vector<std::string> & labels)446 void set_labels(const std::vector<std::string>& labels) { 447 labels_ = labels; 448 } set_content(const Content & content)449 void set_content(const Content& content) { 450 content_ = content; 451 } set_resource_links(ScopedVector<ResourceLink> resource_links)452 void set_resource_links(ScopedVector<ResourceLink> resource_links) { 453 resource_links_ = resource_links.Pass(); 454 } set_filename(const std::string & filename)455 void set_filename(const std::string& filename) { filename_ = filename; } set_suggested_filename(const std::string & suggested_filename)456 void set_suggested_filename(const std::string& suggested_filename) { 457 suggested_filename_ = suggested_filename; 458 } set_file_md5(const std::string & file_md5)459 void set_file_md5(const std::string& file_md5) { file_md5_ = file_md5; } set_file_size(int64 file_size)460 void set_file_size(int64 file_size) { file_size_ = file_size; } set_deleted(bool deleted)461 void set_deleted(bool deleted) { deleted_ = deleted; } set_removed(bool removed)462 void set_removed(bool removed) { removed_ = removed; } set_changestamp(int64 changestamp)463 void set_changestamp(int64 changestamp) { changestamp_ = changestamp; } set_image_width(int64 image_width)464 void set_image_width(int64 image_width) { image_width_ = image_width; } set_image_height(int64 image_height)465 void set_image_height(int64 image_height) { image_height_ = image_height; } set_image_rotation(int64 image_rotation)466 void set_image_rotation(int64 image_rotation) { 467 image_rotation_ = image_rotation; 468 } set_modification_date(const base::Time & modification_date)469 void set_modification_date(const base::Time& modification_date) { 470 modification_date_ = modification_date; 471 } 472 473 // Fills the remaining fields where JSONValueConverter cannot catch. 474 // Currently, sets |kind_| and |labels_| based on the |categories_| in the 475 // class. 476 void FillRemainingFields(); 477 478 private: 479 friend class base::internal::RepeatedMessageConverter<ResourceEntry>; 480 friend class ResourceList; 481 friend class ResumeUploadRequest; 482 483 // Converts categories.term into ResourceEntryKind enum. 484 static ResourceEntryKind GetEntryKindFromTerm(const std::string& term); 485 486 std::string resource_id_; 487 std::string id_; 488 ResourceEntryKind kind_; 489 std::string title_; 490 base::Time published_time_; 491 // Last viewed value may be unreliable. See: crbug.com/152628. 492 base::Time last_viewed_time_; 493 std::vector<std::string> labels_; 494 Content content_; 495 ScopedVector<ResourceLink> resource_links_; 496 // Optional fields for files only. 497 std::string filename_; 498 std::string suggested_filename_; 499 std::string file_md5_; 500 int64 file_size_; 501 bool deleted_; 502 bool removed_; 503 int64 changestamp_; 504 int64 image_width_; 505 int64 image_height_; 506 int64 image_rotation_; 507 508 base::Time modification_date_; 509 510 DISALLOW_COPY_AND_ASSIGN(ResourceEntry); 511 }; 512 513 // This class represents a list of resource entries with some extra metadata 514 // such as the root upload URL. The feed is paginated and the rest of the 515 // feed can be fetched by retrieving the remaining parts of the feed from 516 // URLs provided by GetNextFeedURL() method. 517 class ResourceList : public CommonMetadata { 518 public: 519 ResourceList(); 520 virtual ~ResourceList(); 521 522 // Extracts "feed" dictionary from the JSON value, and parse the contents, 523 // using CreateFrom(). Returns NULL on failure. The input JSON data, coming 524 // from the gdata server, looks like: 525 // 526 // { 527 // "encoding": "UTF-8", 528 // "feed": { ... }, // This function will extract this and parse. 529 // "version": "1.0" 530 // } 531 static scoped_ptr<ResourceList> ExtractAndParse(const base::Value& value); 532 533 // Creates feed from parsed JSON Value. You should call this 534 // instead of instantiating JSONValueConverter by yourself because 535 // this method does some post-process for some fields. See 536 // FillRemainingFields comment and implementation in ResourceEntry 537 // class for the details. 538 static scoped_ptr<ResourceList> CreateFrom(const base::Value& value); 539 540 // Registers the mapping between JSON field names and the members in 541 // this class. 542 static void RegisterJSONConverter( 543 base::JSONValueConverter<ResourceList>* converter); 544 545 // Returns true and passes|url| of the next feed if the current entry list 546 // does not completed this feed. 547 bool GetNextFeedURL(GURL* url) const; 548 549 // List of resource entries. entries()550 const ScopedVector<ResourceEntry>& entries() const { return entries_; } mutable_entries()551 ScopedVector<ResourceEntry>* mutable_entries() { return &entries_; } 552 553 // Releases entries_ into |entries|. This is a transfer of ownership, so the 554 // caller is responsible for deleting the elements of |entries|. 555 void ReleaseEntries(std::vector<ResourceEntry*>* entries); 556 557 // Start index of the resource entry list. start_index()558 int start_index() const { return start_index_; } 559 560 // Number of items per feed of the resource entry list. items_per_page()561 int items_per_page() const { return items_per_page_; } 562 563 // The largest changestamp. Next time the resource list should be fetched 564 // from this changestamp. largest_changestamp()565 int64 largest_changestamp() const { return largest_changestamp_; } 566 567 // Resource entry list title. title()568 const std::string& title() { return title_; } 569 set_entries(ScopedVector<ResourceEntry> entries)570 void set_entries(ScopedVector<ResourceEntry> entries) { 571 entries_ = entries.Pass(); 572 } set_start_index(int start_index)573 void set_start_index(int start_index) { 574 start_index_ = start_index; 575 } set_items_per_page(int items_per_page)576 void set_items_per_page(int items_per_page) { 577 items_per_page_ = items_per_page; 578 } set_title(const std::string & title)579 void set_title(const std::string& title) { 580 title_ = title; 581 } set_largest_changestamp(int64 largest_changestamp)582 void set_largest_changestamp(int64 largest_changestamp) { 583 largest_changestamp_ = largest_changestamp; 584 } 585 586 private: 587 // Parses and initializes data members from content of |value|. 588 // Return false if parsing fails. 589 bool Parse(const base::Value& value); 590 591 ScopedVector<ResourceEntry> entries_; 592 int start_index_; 593 int items_per_page_; 594 std::string title_; 595 int64 largest_changestamp_; 596 597 DISALLOW_COPY_AND_ASSIGN(ResourceList); 598 }; 599 600 } // namespace google_apis 601 602 #endif // GOOGLE_APIS_DRIVE_GDATA_WAPI_PARSER_H_ 603