• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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