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