Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: chrome/browser/chromeos/gdata/gdata_parser.cc

Issue 9147060: Rewrite the gdata_parser by using JSONValueConverter. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Put names for internal structs because arraysize may not work with anonymous types Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/gdata/gdata_parser.h" 5 #include "chrome/browser/chromeos/gdata/gdata_parser.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/scoped_ptr.h" 8 #include "base/json/json_value_converter.h"
9 #include "base/memory/scoped_ptr.h"
9 #include "base/string_number_conversions.h" 10 #include "base/string_number_conversions.h"
11 #include "base/string_piece.h"
10 #include "base/string_util.h" 12 #include "base/string_util.h"
11 #include "base/values.h" 13 #include "base/values.h"
12 14
13 using base::Value; 15 using base::Value;
14 using base::DictionaryValue; 16 using base::DictionaryValue;
15 using base::ListValue; 17 using base::ListValue;
16 18
17 namespace gdata { 19 namespace gdata {
18 20
19 namespace { 21 namespace {
20 22
21 // Term values for kSchemeKind category: 23 // Term values for kSchemeKind category:
22 const char kSchemeKind[] = "http://schemas.google.com/g/2005#kind"; 24 const char kSchemeKind[] = "http://schemas.google.com/g/2005#kind";
23 const char kTermPrefix[] = "http://schemas.google.com/docs/2007#"; 25 const char kTermPrefix[] = "http://schemas.google.com/docs/2007#";
24 const char kFileTerm[] = "file"; 26 const char kFileTerm[] = "file";
25 const char kFolderTerm[] = "folder"; 27 const char kFolderTerm[] = "folder";
26 const char kItemTerm[] = "item"; 28 const char kItemTerm[] = "item";
27 const char kPdfTerm[] = "pdf"; 29 const char kPdfTerm[] = "pdf";
28 const char kDocumentTerm[] = "document"; 30 const char kDocumentTerm[] = "document";
29 const char kSpreadSheetTerm[] = "spreadsheet"; 31 const char kSpreadSheetTerm[] = "spreadsheet";
30 const char kPresentationTerm[] = "presentation"; 32 const char kPresentationTerm[] = "presentation";
31 33
32 const char kSchemeLabels[] = "http://schemas.google.com/g/2005/labels"; 34 const char kSchemeLabels[] = "http://schemas.google.com/g/2005/labels";
33 35
34 const struct { 36 struct EntryKindMap {
35 DocumentEntry::EntryKind kind; 37 DocumentEntry::EntryKind kind;
36 const char* entry; 38 const char* entry;
37 } kEntryKindMap[] = { 39 };
40
41 const EntryKindMap kEntryKindMap[] = {
38 { DocumentEntry::ITEM, "item" }, 42 { DocumentEntry::ITEM, "item" },
39 { DocumentEntry::DOCUMENT, "document"}, 43 { DocumentEntry::DOCUMENT, "document"},
40 { DocumentEntry::SPREADSHEET, "spreadsheet" }, 44 { DocumentEntry::SPREADSHEET, "spreadsheet" },
41 { DocumentEntry::PRESENTATION, "presentation" }, 45 { DocumentEntry::PRESENTATION, "presentation" },
42 { DocumentEntry::FOLDER, "folder"}, 46 { DocumentEntry::FOLDER, "folder"},
43 { DocumentEntry::FILE, "file"}, 47 { DocumentEntry::FILE, "file"},
44 { DocumentEntry::PDF, "pdf"}, 48 { DocumentEntry::PDF, "pdf"},
45 { DocumentEntry::UNKNOWN, NULL}
46 }; 49 };
47 50
48 const struct { 51 struct LinkTypeMap {
49 Link::LinkType type; 52 Link::LinkType type;
50 const char* rel; 53 const char* rel;
51 } kLinkTypeMap[] = { 54 };
55
56 const LinkTypeMap kLinkTypeMap[] = {
52 { Link::SELF, 57 { Link::SELF,
53 "self" }, 58 "self" },
54 { Link::NEXT, 59 { Link::NEXT,
55 "next" }, 60 "next" },
56 { Link::PARENT, 61 { Link::PARENT,
57 "http://schemas.google.com/docs/2007#parent" }, 62 "http://schemas.google.com/docs/2007#parent" },
58 { Link::ALTERNATE, 63 { Link::ALTERNATE,
59 "alternate"}, 64 "alternate"},
60 { Link::EDIT, 65 { Link::EDIT,
61 "edit" }, 66 "edit" },
62 { Link::EDIT_MEDIA, 67 { Link::EDIT_MEDIA,
63 "edit-media" }, 68 "edit-media" },
64 { Link::FEED, 69 { Link::FEED,
65 "http://schemas.google.com/g/2005#feed"}, 70 "http://schemas.google.com/g/2005#feed"},
66 { Link::POST, 71 { Link::POST,
67 "http://schemas.google.com/g/2005#post"}, 72 "http://schemas.google.com/g/2005#post"},
68 { Link::BATCH, 73 { Link::BATCH,
69 "http://schemas.google.com/g/2005#batch"}, 74 "http://schemas.google.com/g/2005#batch"},
70 { Link::THUMBNAIL, 75 { Link::THUMBNAIL,
71 "http://schemas.google.com/docs/2007/thumbnail"}, 76 "http://schemas.google.com/docs/2007/thumbnail"},
72 { Link::RESUMABLE_EDIT_MEDIA, 77 { Link::RESUMABLE_EDIT_MEDIA,
73 "http://schemas.google.com/g/2005#resumable-edit-media"}, 78 "http://schemas.google.com/g/2005#resumable-edit-media"},
74 { Link::RESUMABLE_CREATE_MEDIA, 79 { Link::RESUMABLE_CREATE_MEDIA,
75 "http://schemas.google.com/g/2005#resumable-create-media"}, 80 "http://schemas.google.com/g/2005#resumable-create-media"},
76 { Link::TABLES_FEED, 81 { Link::TABLES_FEED,
77 "http://schemas.google.com/spreadsheets/2006#tablesfeed"}, 82 "http://schemas.google.com/spreadsheets/2006#tablesfeed"},
78 { Link::WORKSHEET_FEED, 83 { Link::WORKSHEET_FEED,
79 "http://schemas.google.com/spreadsheets/2006#worksheetsfeed"}, 84 "http://schemas.google.com/spreadsheets/2006#worksheetsfeed"},
80 { Link::UNKNOWN,
81 NULL}
82 }; 85 };
83 86
84 const struct { 87 struct FeedLinkTypeMap {
85 FeedLink::FeedLinkType type; 88 FeedLink::FeedLinkType type;
86 const char* rel; 89 const char* rel;
87 } kFeedLinkTypeMap[] = { 90 };
91
92 const FeedLinkTypeMap kFeedLinkTypeMap[] = {
88 { FeedLink::ACL, 93 { FeedLink::ACL,
89 "http://schemas.google.com/acl/2007#accessControlList" }, 94 "http://schemas.google.com/acl/2007#accessControlList" },
90 { FeedLink::REVISIONS, 95 { FeedLink::REVISIONS,
91 "http://schemas.google.com/docs/2007/revisions" }, 96 "http://schemas.google.com/docs/2007/revisions" },
92 { FeedLink::UNKNOWN,
93 NULL}
94 }; 97 };
95 98
96 const struct { 99 struct CategoryTypeMap {
97 Category::CategoryType type; 100 Category::CategoryType type;
98 const char* scheme; 101 const char* scheme;
99 } kCategoryTypeMap[] = { 102 };
103
104 const CategoryTypeMap kCategoryTypeMap[] = {
100 { Category::KIND, 105 { Category::KIND,
101 "http://schemas.google.com/g/2005#kind" }, 106 "http://schemas.google.com/g/2005#kind" },
102 { Category::LABEL, 107 { Category::LABEL,
103 "http://schemas.google.com/g/2005/labels" }, 108 "http://schemas.google.com/g/2005/labels" },
104 { Category::UNKNOWN,
105 NULL}
106 }; 109 };
107 110
111 // Converts |url_string| to |result|. Always returns true to be used
112 // for JSONValueConverter::RegisterCustomField method.
113 // TODO(mukai): make it return false in case of invalid |url_string|.
114 bool GetGURLFromString(const base::StringPiece& url_string, GURL* result) {
115 *result = GURL(url_string.as_string());
116 return true;
117 }
118
108 } // namespace 119 } // namespace
109 120
110 const char Author::kNameField[] = "name.$t"; 121 const char Author::kNameField[] = "name.$t";
111 const char Author::kEmailField[] = "email.$t"; 122 const char Author::kEmailField[] = "email.$t";
112 123
113 Author::Author() { 124 Author::Author() {
114 } 125 }
115 126
116 bool Author::Parse(const DictionaryValue* dictionary) { 127 // static
117 if (dictionary->GetString(kNameField, &name_) && 128 void Author::RegisterJSONConverter(
118 dictionary->GetString(kEmailField, &email_)) { 129 base::JSONValueConverter<Author>* converter) {
119 return true; 130 converter->RegisterStringField(kNameField, &Author::name_);
120 } 131 converter->RegisterStringField(kEmailField, &Author::email_);
121 return false;
122 } 132 }
123 133
124 const char Link::kHrefField[] = "href"; 134 const char Link::kHrefField[] = "href";
125 const char Link::kRelField[] = "rel"; 135 const char Link::kRelField[] = "rel";
126 const char Link::kTitleField[] = "title"; 136 const char Link::kTitleField[] = "title";
127 const char Link::kTypeField[] = "type"; 137 const char Link::kTypeField[] = "type";
128 138
129 Link::Link() : type_(Link::UNKNOWN) { 139 Link::Link() : type_(Link::UNKNOWN) {
130 } 140 }
131 141
132 bool Link::Parse(const DictionaryValue* dictionary) { 142 // static.
133 std::string rel; 143 bool Link::GetLinkType(const base::StringPiece& rel, Link::LinkType* result) {
134 std::string href; 144 for (size_t i = 0; i < arraysize(kLinkTypeMap); i++) {
135 if (dictionary->GetString(kRelField, &rel) && 145 if (rel == kLinkTypeMap[i].rel) {
136 dictionary->GetString(kHrefField, &href) && 146 *result = kLinkTypeMap[i].type;
137 dictionary->GetString(kTypeField, &mime_type_)) {
138 href_ = GURL(href);
139 type_ = GetLinkType(rel);
140 if (type_ == Link::PARENT)
141 dictionary->GetString(kTitleField, &title_);
142
143 if (type_ != Link::UNKNOWN)
144 return true; 147 return true;
148 }
145 } 149 }
150 DVLOG(1) << "Unknown link type for rel " << rel;
146 return false; 151 return false;
147 } 152 }
148 153
149 // static. 154 // static
150 Link::LinkType Link::GetLinkType(const std::string& rel) { 155 void Link::RegisterJSONConverter(base::JSONValueConverter<Link>* converter) {
151 for (size_t i = 0; kLinkTypeMap[i].rel; i++) { 156 converter->RegisterCustomField<Link::LinkType>(
152 if (rel == kLinkTypeMap[i].rel) 157 kRelField, &Link::type_, &Link::GetLinkType);
153 return kLinkTypeMap[i].type; 158 converter->RegisterCustomField(kHrefField, &Link::href_, &GetGURLFromString);
154 } 159 converter->RegisterStringField(kTitleField, &Link::title_);
155 DVLOG(1) << "Unknown link type for rel " << rel; 160 converter->RegisterStringField(kTypeField, &Link::mime_type_);
156 return Link::UNKNOWN;
157 } 161 }
158 162
159 const char FeedLink::kHrefField[] = "href"; 163 const char FeedLink::kHrefField[] = "href";
160 const char FeedLink::kRelField[] = "rel"; 164 const char FeedLink::kRelField[] = "rel";
161 165
162 FeedLink::FeedLink() : type_(FeedLink::UNKNOWN) { 166 FeedLink::FeedLink() : type_(FeedLink::UNKNOWN) {
163 } 167 }
164 168
165 bool FeedLink::Parse(const DictionaryValue* dictionary) { 169 // static.
166 std::string rel; 170 bool FeedLink::GetFeedLinkType(
167 std::string href; 171 const base::StringPiece& rel, FeedLink::FeedLinkType* result) {
168 if (dictionary->GetString(kRelField, &rel) && 172 for (size_t i = 0; i < arraysize(kFeedLinkTypeMap); i++) {
169 dictionary->GetString(kHrefField, &href)) { 173 if (rel == kFeedLinkTypeMap[i].rel) {
170 href_ = GURL(href); 174 *result = kFeedLinkTypeMap[i].type;
171 type_ = GetFeedLinkType(rel);
172 if (type_ != FeedLink::UNKNOWN)
173 return true; 175 return true;
176 }
174 } 177 }
178 DVLOG(1) << "Unknown feed link type for rel " << rel;
175 return false; 179 return false;
176 } 180 }
177 181
178 // static. 182 // static
179 FeedLink::FeedLinkType FeedLink::GetFeedLinkType(const std::string& rel) { 183 void FeedLink::RegisterJSONConverter(
180 for (size_t i = 0; kFeedLinkTypeMap[i].rel; i++) { 184 base::JSONValueConverter<FeedLink>* converter) {
181 if (rel == kFeedLinkTypeMap[i].rel) 185 converter->RegisterCustomField<FeedLink::FeedLinkType>(
182 return kFeedLinkTypeMap[i].type; 186 kRelField, &FeedLink::type_, &FeedLink::GetFeedLinkType);
183 } 187 converter->RegisterCustomField(
184 DVLOG(1) << "Unknown feed link type for rel " << rel; 188 kHrefField, &FeedLink::href_, &GetGURLFromString);
185 return FeedLink::UNKNOWN;
186 } 189 }
187 190
188 const char Category::kLabelField[] = "label"; 191 const char Category::kLabelField[] = "label";
189 const char Category::kSchemeField[] = "scheme"; 192 const char Category::kSchemeField[] = "scheme";
190 const char Category::kTermField[] = "term"; 193 const char Category::kTermField[] = "term";
191 194
192 Category::Category() { 195 Category::Category() : type_(UNKNOWN) {
193 } 196 }
194 197
195 bool Category::Parse(const DictionaryValue* dictionary) { 198 // Converts category.scheme into CategoryType enum.
196 std::string scheme; 199 bool Category::GetCategoryTypeFromScheme(
197 if (dictionary->GetString(kLabelField, &label_) && 200 const base::StringPiece& scheme, Category::CategoryType* result) {
198 dictionary->GetString(kSchemeField, &scheme) && 201 for (size_t i = 0; i < arraysize(kCategoryTypeMap); i++) {
199 dictionary->GetString(kTermField, &term_)) { 202 if (scheme == kCategoryTypeMap[i].scheme) {
200 type_ = GetCategoryTypeFromScheme(scheme); 203 *result = kCategoryTypeMap[i].type;
201 if (type_ != Category::UNKNOWN)
202 return true; 204 return true;
203 205 }
204 DVLOG(1) << "Unknown category:"
205 << "\n label = " << label_
206 << "\n scheme = " << scheme
207 << "\n term = " << term_;
208 } 206 }
207 DVLOG(1) << "Unknown feed link type for scheme " << scheme;
209 return false; 208 return false;
210 } 209 }
211 210
212 // Converts category.scheme into CategoryType enum. 211 // static
213 Category::CategoryType Category::GetCategoryTypeFromScheme( 212 void Category::RegisterJSONConverter(
214 const std::string& scheme) { 213 base::JSONValueConverter<Category>* converter) {
215 for (size_t i = 0; kCategoryTypeMap[i].scheme; i++) { 214 converter->RegisterStringField(kLabelField, &Category::label_);
216 if (scheme == kCategoryTypeMap[i].scheme) 215 converter->RegisterCustomField<Category::CategoryType>(
217 return kCategoryTypeMap[i].type; 216 kSchemeField, &Category::type_, &Category::GetCategoryTypeFromScheme);
218 } 217 converter->RegisterStringField(kTermField, &Category::term_);
219 DVLOG(1) << "Unknown feed link type for scheme " << scheme;
220 return Category::UNKNOWN;
221 } 218 }
222 219
223
224 const Link* GDataEntry::GetLinkByType(Link::LinkType type) const { 220 const Link* GDataEntry::GetLinkByType(Link::LinkType type) const {
225 for (ScopedVector<Link>::const_iterator iter = links_.begin(); 221 for (size_t i = 0; i < links_.size(); ++i) {
226 iter != links_.end(); ++iter) { 222 if (links_[i]->type() == type)
227 if ((*iter)->type() == type) 223 return links_[i];
228 return (*iter);
229 } 224 }
230 return NULL; 225 return NULL;
231 } 226 }
232 227
228 const char Content::kSrcField[] = "src";
229 const char Content::kTypeField[] = "type";
230
231 Content::Content() {
232 }
233
234 // static
235 void Content::RegisterJSONConverter(
236 base::JSONValueConverter<Content>* converter) {
237 converter->RegisterCustomField(kSrcField, &Content::url_, &GetGURLFromString);
238 converter->RegisterStringField(kTypeField, &Content::mime_type_);
239 }
240
233 const char GDataEntry::kTimeParsingDelimiters[] = "-:.TZ"; 241 const char GDataEntry::kTimeParsingDelimiters[] = "-:.TZ";
234 const char GDataEntry::kAuthorField[] = "author"; 242 const char GDataEntry::kAuthorField[] = "author";
235 const char GDataEntry::kLinkField[] = "link"; 243 const char GDataEntry::kLinkField[] = "link";
236 const char GDataEntry::kCategoryField[] = "category"; 244 const char GDataEntry::kCategoryField[] = "category";
245 const char GDataEntry::kETagField[] = "gd$etag";
246 const char GDataEntry::kUpdatedField[] = "updated.$t";
237 247
238 GDataEntry::GDataEntry() { 248 GDataEntry::GDataEntry() {
239 } 249 }
240 250
241 GDataEntry::~GDataEntry() { 251 GDataEntry::~GDataEntry() {
242 } 252 }
243 253
244 bool GDataEntry::ParseAuthors(const DictionaryValue* value_dict) { 254 // static
245 ListValue* authors = NULL; 255 void GDataEntry::RegisterJSONConverter(
246 if (value_dict->GetList(kAuthorField, &authors)) { 256 base::JSONValueConverter<GDataEntry>* converter) {
247 for (ListValue::iterator iter = authors->begin(); 257 converter->RegisterStringField(kETagField, &GDataEntry::etag_);
248 iter != authors->end(); 258 converter->RegisterRepeatedMessage(kAuthorField, &GDataEntry::authors_);
249 ++iter) { 259 converter->RegisterRepeatedMessage(kLinkField, &GDataEntry::links_);
250 if ((*iter)->GetType() != Value::TYPE_DICTIONARY) { 260 converter->RegisterRepeatedMessage(kCategoryField, &GDataEntry::categories_);
251 DVLOG(1) << "Invalid author list element"; 261 converter->RegisterCustomField<base::Time>(
252 return false; 262 kUpdatedField,
253 } 263 &GDataEntry::updated_time_,
254 DictionaryValue* author_dict = 264 &GDataEntry::GetTimeFromString);
255 reinterpret_cast<DictionaryValue*>(*iter);
256 scoped_ptr<Author> author(new Author());
257 if (author->Parse(author_dict)) {
258 authors_.push_back(author.release());
259 } else {
260 DVLOG(1) << "Invalid author etag = " << etag_;
261 }
262 }
263 }
264 return true;
265 } 265 }
266 266
267 bool GDataEntry::ParseLinks(const DictionaryValue* value_dict) { 267 // static
268 ListValue* links = NULL; 268 bool GDataEntry::GetTimeFromString(const base::StringPiece& raw_value,
269 if (value_dict->GetList(kLinkField, &links)) {
270 for (ListValue::iterator iter = links->begin();
271 iter != links->end();
272 ++iter) {
273 if ((*iter)->GetType() != Value::TYPE_DICTIONARY) {
274 DVLOG(1) << "Invalid link list element";
275 return false;
276 }
277 DictionaryValue* link_dict =
278 reinterpret_cast<DictionaryValue*>(*iter);
279 scoped_ptr<Link> link(new Link());
280 if (link->Parse(link_dict))
281 links_.push_back(link.release());
282 else
283 DVLOG(1) << "Invalid link etag = " << etag_;
284 }
285 }
286 return true;
287 }
288
289 // static.
290 bool GDataEntry::GetTimeFromString(const std::string& raw_value,
291 base::Time* time) { 269 base::Time* time) {
292 std::vector<std::string> parts; 270 std::vector<base::StringPiece> parts;
293 if (Tokenize(raw_value, kTimeParsingDelimiters, &parts) != 7) 271 if (Tokenize(raw_value, kTimeParsingDelimiters, &parts) != 7)
294 return false; 272 return false;
295 273
296 base::Time::Exploded exploded; 274 base::Time::Exploded exploded;
297 if (!base::StringToInt(parts[0], &exploded.year) || 275 if (!base::StringToInt(parts[0], &exploded.year) ||
298 !base::StringToInt(parts[1], &exploded.month) || 276 !base::StringToInt(parts[1], &exploded.month) ||
299 !base::StringToInt(parts[2], &exploded.day_of_month) || 277 !base::StringToInt(parts[2], &exploded.day_of_month) ||
300 !base::StringToInt(parts[3], &exploded.hour) || 278 !base::StringToInt(parts[3], &exploded.hour) ||
301 !base::StringToInt(parts[4], &exploded.minute) || 279 !base::StringToInt(parts[4], &exploded.minute) ||
302 !base::StringToInt(parts[5], &exploded.second) || 280 !base::StringToInt(parts[5], &exploded.second) ||
303 !base::StringToInt(parts[6], &exploded.millisecond)) { 281 !base::StringToInt(parts[6], &exploded.millisecond)) {
304 return false; 282 return false;
305 } 283 }
306 284
307 exploded.day_of_week = 0; 285 exploded.day_of_week = 0;
308 if (!exploded.HasValidValues()) 286 if (!exploded.HasValidValues())
309 return false; 287 return false;
310 288
311 *time = base::Time::FromLocalExploded(exploded); 289 *time = base::Time::FromLocalExploded(exploded);
312 return true; 290 return true;
313 } 291 }
314 292
315 bool GDataEntry::ParseCategories(const DictionaryValue* value_dict) {
316 ListValue* categories = NULL;
317 if (value_dict->GetList(kCategoryField, &categories)) {
318 for (ListValue::iterator iter = categories->begin();
319 iter != categories->end();
320 ++iter) {
321 if ((*iter)->GetType() != Value::TYPE_DICTIONARY) {
322 DVLOG(1) << "Invalid category list element";
323 return false;
324 }
325 DictionaryValue* category_dict =
326 reinterpret_cast<DictionaryValue*>(*iter);
327 scoped_ptr<Category> category(new Category());
328 if (category->Parse(category_dict)) {
329 OnAddCategory(category.get());
330 categories_->push_back(category.release());
331 } else {
332 DVLOG(1) << "Invalid category etag = " << etag_;
333 }
334 }
335 }
336 return true;
337 }
338
339 // static.
340 bool GDataEntry::ParseDateTime(const DictionaryValue* dict,
341 const std::string& field,
342 base::Time* time) {
343 std::string raw_value;
344 if (!dict->GetString(field, &raw_value))
345 return false;
346
347 return GetTimeFromString(raw_value, time);
348 }
349
350 const char DocumentEntry::kFeedLinkField[] = "gd$feedLink"; 293 const char DocumentEntry::kFeedLinkField[] = "gd$feedLink";
351 const char DocumentEntry::kContentField[] = "content"; 294 const char DocumentEntry::kContentField[] = "content";
352 const char DocumentEntry::kSrcField[] = "src";
353 const char DocumentEntry::kTypeField[] = "type";
354 const char DocumentEntry::kFileNameField[] = "docs$filename.$t"; 295 const char DocumentEntry::kFileNameField[] = "docs$filename.$t";
355 const char DocumentEntry::kMD5Field[] = "docs$md5Checksum.$t"; 296 const char DocumentEntry::kMD5Field[] = "docs$md5Checksum.$t";
356 const char DocumentEntry::kSizeField[] = "docs$size.$t"; 297 const char DocumentEntry::kSizeField[] = "docs$size.$t";
357 const char DocumentEntry::kSuggestedFileNameField[] = 298 const char DocumentEntry::kSuggestedFileNameField[] =
358 "docs$suggestedFilename.$t"; 299 "docs$suggestedFilename.$t";
359 const char DocumentEntry::kETagField[] = "gd$etag";
360 const char DocumentEntry::kResourceIdField[] = "gd$resourceId.$t"; 300 const char DocumentEntry::kResourceIdField[] = "gd$resourceId.$t";
361 const char DocumentEntry::kIDField[] = "id.$t"; 301 const char DocumentEntry::kIDField[] = "id.$t";
362 const char DocumentEntry::kTitleField[] = "title.$t"; 302 const char DocumentEntry::kTitleField[] = "title.$t";
363 const char DocumentEntry::kUpdatedField[] = "updated.$t";
364 const char DocumentEntry::kPublishedField[] = "published.$t"; 303 const char DocumentEntry::kPublishedField[] = "published.$t";
365 304
366 DocumentEntry::DocumentEntry() : kind_(DocumentEntry::UNKNOWN), file_size_(0) { 305 DocumentEntry::DocumentEntry() : kind_(DocumentEntry::UNKNOWN), file_size_(0) {
367 } 306 }
368 307
369 DocumentEntry::~DocumentEntry() { 308 DocumentEntry::~DocumentEntry() {
370 } 309 }
371 310
372 bool DocumentEntry::ParseFeedLinks(const DictionaryValue* value_dict) { 311 // static
373 ListValue* links = NULL; 312 void DocumentEntry::RegisterJSONConverter(
374 if (value_dict->GetList(kFeedLinkField, &links)) { 313 base::JSONValueConverter<DocumentEntry>* converter) {
375 for (ListValue::iterator iter = links->begin(); 314 // inheritant the parent registrations.
376 iter != links->end(); 315 GDataEntry::RegisterJSONConverter(
377 ++iter) { 316 reinterpret_cast<base::JSONValueConverter<GDataEntry>*>(converter));
378 if ((*iter)->GetType() != Value::TYPE_DICTIONARY) { 317 converter->RegisterStringField(
379 DVLOG(1) << "Invalid feed link list element"; 318 kResourceIdField, &DocumentEntry::resource_id_);
380 return false; 319 converter->RegisterStringField(kIDField, &DocumentEntry::id_);
381 } 320 converter->RegisterStringField(kTitleField, &DocumentEntry::title_);
382 DictionaryValue* link_dict = 321 converter->RegisterCustomField<base::Time>(
383 reinterpret_cast<DictionaryValue*>(*iter); 322 kPublishedField, &DocumentEntry::published_time_,
384 scoped_ptr<FeedLink> link(new FeedLink()); 323 &GDataEntry::GetTimeFromString);
385 if (link->Parse(link_dict)) { 324 converter->RegisterRepeatedMessage(
386 feed_links_.push_back(link.release()); 325 kFeedLinkField, &DocumentEntry::feed_links_);
387 } else { 326 converter->RegisterNestedField(kContentField, &DocumentEntry::content_);
388 DVLOG(1) << "Invalid feed link etag = " << etag_; 327
389 } 328 // File properties. If the document type is not a normal file, then
390 } 329 // that's no problem because those feed must not have these fields
391 } 330 // themselves, which does not report errors.
392 return true; 331 converter->RegisterStringField(kFileNameField, &DocumentEntry::filename_);
332 converter->RegisterStringField(kMD5Field, &DocumentEntry::file_md5_);
333 converter->RegisterCustomField<int64>(
334 kSizeField, &DocumentEntry::file_size_, &base::StringToInt64);
335 converter->RegisterStringField(
336 kSuggestedFileNameField, &DocumentEntry::suggested_filename_);
393 } 337 }
394 338
395 bool DocumentEntry::ParseContent(const DictionaryValue* value_dict) { 339 // static
396 base::DictionaryValue* content = NULL;
397 if (value_dict->GetDictionary(kContentField, &content)) {
398 std::string src;
399 if (content->GetString(kSrcField, &src) &&
400 content->GetString(kTypeField, &content_mime_type_)) {
401 content_url_ = GURL(src);
402 return true;
403 }
404 }
405 DVLOG(1) << "Invalid item content etag = " << etag_;
406 return false;
407 }
408
409 bool DocumentEntry::ParseFileProperties(const DictionaryValue* value_dict) {
410 if (!value_dict->GetString(kFileNameField, &filename_)) {
411 DVLOG(1) << "File item with no name! " << etag_;
412 return false;
413 }
414
415 if (!value_dict->GetString(kMD5Field, &file_md5_)) {
416 DVLOG(1) << "File item with no md5! " << etag_;
417 return false;
418 }
419
420 std::string file_size;
421 if (!value_dict->GetString(kSizeField, &file_size) ||
422 !file_size.length()) {
423 DVLOG(1) << "File item with no size! " << etag_;
424 return false;
425 }
426
427 if (!base::StringToInt64(file_size, &file_size_)) {
428 DVLOG(1) << "Invalid file size '" << file_size << "' for " << etag_;
429 return false;
430 }
431
432 if (!value_dict->GetString(kSuggestedFileNameField, &suggested_filename_))
433 DVLOG(1) << "File item with no docs$suggestedFilename! " << etag_;
434
435 return true;
436 }
437
438 bool DocumentEntry::Parse(const DictionaryValue* value_dict) {
439 if (!value_dict->GetString(kETagField, &etag_)) {
440 DVLOG(1) << "Item with no etag!";
441 return false;
442 }
443
444 if (!value_dict->GetString(kResourceIdField, &resource_id_)) {
445 DVLOG(1) << "Item with no resource id! " << etag_;
446 return false;
447 }
448
449 if (!value_dict->GetString(kIDField, &id_)) {
450 DVLOG(1) << "Item with no id! " << etag_;
451 return false;
452 }
453
454 if (!value_dict->GetString(kTitleField, &title_)) {
455 DVLOG(1) << "Item with no title! " << etag_;
456 return false;
457 }
458
459 if (!ParseDateTime(value_dict, kUpdatedField, &updated_time_)) {
460 DVLOG(1) << "Item with no updated date! " << etag_;
461 return false;
462 }
463
464 if (!ParseDateTime(value_dict, kPublishedField, &published_time_)) {
465 DVLOG(1) << "Item with no published date! " << etag_;
466 return false;
467 }
468
469 // Parse categories, will set up entry->kind as well.
470 if (!ParseCategories(value_dict))
471 return false;
472
473 if (kind_ == DocumentEntry::FILE || kind_ == DocumentEntry::PDF) {
474 if (!ParseFileProperties(value_dict))
475 return false;
476 }
477
478 if (!ParseAuthors(value_dict))
479 return false;
480
481 if (!ParseContent(value_dict))
482 return false;
483
484 if (!ParseLinks(value_dict))
485 return false;
486
487 if (!ParseFeedLinks(value_dict))
488 return false;
489
490 return true;
491 }
492
493 // static.
494 DocumentEntry::EntryKind DocumentEntry::GetEntryKindFromTerm( 340 DocumentEntry::EntryKind DocumentEntry::GetEntryKindFromTerm(
495 const std::string& term) { 341 const std::string& term) {
496 if (!StartsWithASCII(term, kTermPrefix, false)) { 342 if (!StartsWithASCII(term, kTermPrefix, false)) {
497 DVLOG(1) << "Unexpected term prefix term " << term; 343 DVLOG(1) << "Unexpected term prefix term " << term;
498 return DocumentEntry::UNKNOWN; 344 return DocumentEntry::UNKNOWN;
499 } 345 }
500 346
501 std::string type = term.substr(strlen(kTermPrefix)); 347 std::string type = term.substr(strlen(kTermPrefix));
502 for (size_t i = 0; kEntryKindMap[i].entry; i++) { 348 for (size_t i = 0; i < arraysize(kEntryKindMap); i++) {
503 if (type == kEntryKindMap[i].entry) 349 if (type == kEntryKindMap[i].entry)
504 return kEntryKindMap[i].kind; 350 return kEntryKindMap[i].kind;
505 } 351 }
506 DVLOG(1) << "Unknown entry type for term " << term << ", type " << type; 352 DVLOG(1) << "Unknown entry type for term " << term << ", type " << type;
507 return DocumentEntry::UNKNOWN; 353 return DocumentEntry::UNKNOWN;
508 } 354 }
509 355
510 void DocumentEntry::OnAddCategory(Category* category) { 356 void DocumentEntry::FillRemainingFields() {
511 if (category->type() == Category::KIND) 357 // Set |kind_| and |labels_| based on the |categories_| in the class.
512 kind_ = GetEntryKindFromTerm(category->term()); 358 // JSONValueConverter does not have the ability to catch an element in a list
513 else if (category->type() == Category::LABEL) 359 // based on a predicate. Thus we need to iterate over |categories_| and
514 labels_.push_back(category->label()); 360 // find the elements to set these fields as a post-process.
361 for (size_t i = 0; i < categories_.size(); ++i) {
362 const Category* category = categories_[i];
363 if (category->type() == Category::KIND)
364 kind_ = GetEntryKindFromTerm(category->term());
365 else if (category->type() == Category::LABEL)
366 labels_.push_back(category->label());
367 }
515 } 368 }
516 369
517
518 const char DocumentFeed::kETagField[] = "gd$etag";
519 const char DocumentFeed::kStartIndexField[] = "openSearch$startIndex.$t"; 370 const char DocumentFeed::kStartIndexField[] = "openSearch$startIndex.$t";
520 const char DocumentFeed::kItemsPerPageField[] = 371 const char DocumentFeed::kItemsPerPageField[] =
521 "openSearch$itemsPerPage.$t"; 372 "openSearch$itemsPerPage.$t";
522 const char DocumentFeed::kUpdatedField[] = "updated.$t";
523 const char DocumentFeed::kTitleField[] = "title.$t"; 373 const char DocumentFeed::kTitleField[] = "title.$t";
524 const char DocumentFeed::kEntryField[] = "entry"; 374 const char DocumentFeed::kEntryField[] = "entry";
525 375
526 DocumentFeed::DocumentFeed() : start_index_(0), items_per_page_(0) { 376 DocumentFeed::DocumentFeed() : start_index_(0), items_per_page_(0) {
527 } 377 }
528 378
529 DocumentFeed::~DocumentFeed() { 379 DocumentFeed::~DocumentFeed() {
530 } 380 }
531 381
532 bool DocumentFeed::Parse(const DictionaryValue* value_dict) { 382 // static
533 if (!value_dict->GetString(kETagField, &etag_)) { 383 void DocumentFeed::RegisterJSONConverter(
534 DVLOG(1) << "Feed with no etag!"; 384 base::JSONValueConverter<DocumentFeed>* converter) {
535 return false; 385 // inheritance
536 } 386 GDataEntry::RegisterJSONConverter(
537 387 reinterpret_cast<base::JSONValueConverter<GDataEntry>*>(converter));
538 // TODO(zelidrag): Once we figure out where these will be used, we should 388 // TODO(zelidrag): Once we figure out where these will be used, we should
539 // check for valid start_index_ and items_per_page_ values. 389 // check for valid start_index_ and items_per_page_ values.
540 std::string start_index; 390 converter->RegisterCustomField<int>(
541 if (!value_dict->GetString(kStartIndexField, &start_index) || 391 kStartIndexField, &DocumentFeed::start_index_, &base::StringToInt);
542 !base::StringToInt(start_index, &start_index_)) { 392 converter->RegisterCustomField<int>(
543 DVLOG(1) << "Feed with no startIndex! " << etag_; 393 kItemsPerPageField, &DocumentFeed::items_per_page_, &base::StringToInt);
544 return false; 394 converter->RegisterStringField(kTitleField, &DocumentFeed::title_);
545 } 395 converter->RegisterRepeatedMessage(kEntryField, &DocumentFeed::entries_);
546
547 std::string items_per_page;
548 if (!value_dict->GetString(kItemsPerPageField, &items_per_page) ||
549 !base::StringToInt(items_per_page, &items_per_page_)) {
550 DVLOG(1) << "Feed with no itemsPerPage! " << etag_;
551 return false;
552 }
553
554 if (!ParseDateTime(value_dict, kUpdatedField, &updated_time_)) {
555 DVLOG(1) << "Feed with no updated date! " << etag_;
556 return false;
557 }
558
559 if (!value_dict->GetString(kTitleField, &title_)) {
560 DVLOG(1) << "Feed with no title!";
561 return false;
562 }
563
564 ListValue* entries = NULL;
565 if (value_dict->GetList(kEntryField, &entries)) {
566 for (ListValue::iterator iter = entries->begin();
567 iter != entries->end();
568 ++iter) {
569 DocumentEntry* entry = DocumentEntry::CreateFrom(*iter);
570 if (entry)
571 entries_.push_back(entry);
572 }
573 }
574
575 // Parse categories.
576 if (!ParseCategories(value_dict))
577 return false;
578
579 // Parse author list.
580 if (!ParseAuthors(value_dict))
581 return false;
582
583 if (!ParseLinks(value_dict))
584 return false;
585
586 return true;
587 } 396 }
588 397
589 // static. 398 // static
590 DocumentEntry* DocumentEntry::CreateFrom(base::Value* value) { 399 DocumentEntry* DocumentEntry::CreateFrom(base::Value* value) {
591 if (!value || value->GetType() != Value::TYPE_DICTIONARY) 400 base::JSONValueConverter<DocumentEntry> converter;
592 return NULL;
593
594 DictionaryValue* root = reinterpret_cast<DictionaryValue*>(value);
595 scoped_ptr<DocumentEntry> entry(new DocumentEntry()); 401 scoped_ptr<DocumentEntry> entry(new DocumentEntry());
596 if (!entry->Parse(root)) { 402 if (!converter.Convert(*value, entry.get())) {
597 DVLOG(1) << "Invalid document entry!"; 403 DVLOG(1) << "Invalid document entry!";
598 return NULL; 404 return NULL;
599 } 405 }
600 406
407 entry->FillRemainingFields();
601 return entry.release(); 408 return entry.release();
602 } 409 }
603 410
604 411
605 // static. 412 bool DocumentFeed::Parse(base::Value* value) {
413 base::JSONValueConverter<DocumentFeed> converter;
414 if (!converter.Convert(*value, this)) {
415 DVLOG(1) << "Invalid document feed!";
416 return false;
417 }
418
419 for (size_t i = 0; i < entries_.size(); ++i) {
420 entries_[i]->FillRemainingFields();
421 }
422 return true;
423 }
424
425 // static
606 DocumentFeed* DocumentFeed::CreateFrom(base::Value* value) { 426 DocumentFeed* DocumentFeed::CreateFrom(base::Value* value) {
607 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
608 return NULL;
609
610 DictionaryValue* root_entry_dict =
611 reinterpret_cast<DictionaryValue*>(value);
612 scoped_ptr<DocumentFeed> feed(new DocumentFeed()); 427 scoped_ptr<DocumentFeed> feed(new DocumentFeed());
613 if (!feed->Parse(root_entry_dict)) { 428 if (!feed->Parse(value)) {
614 DVLOG(1) << "Invalid document feed!"; 429 DVLOG(1) << "Invalid document feed!";
615 return NULL; 430 return NULL;
616 } 431 }
617 432
618 return feed.release(); 433 return feed.release();
619 } 434 }
620 435
621 bool DocumentFeed::GetNextFeedURL(GURL* url) { 436 bool DocumentFeed::GetNextFeedURL(GURL* url) {
622 DCHECK(url); 437 DCHECK(url);
623 for (ScopedVector<Link>::iterator iter = links_.begin(); 438 for (size_t i = 0; i < links_.size(); ++i) {
624 iter != links_.end(); ++iter) { 439 if (links_[i]->type() == Link::NEXT) {
625 if ((*iter)->type() == Link::NEXT) { 440 *url = links_[i]->href();
626 *url = (*iter)->href();
627 return true; 441 return true;
628 } 442 }
629 } 443 }
630 return false; 444 return false;
631 } 445 }
632 446
633 } // namespace gdata 447 } // namespace gdata
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_parser.h ('k') | chrome/browser/chromeos/gdata/gdata_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698