Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / sync / syncable / model_type.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sync/internal_api/public/base/model_type.h"
6
7 #include "base/strings/string_split.h"
8 #include "base/values.h"
9 #include "sync/protocol/app_notification_specifics.pb.h"
10 #include "sync/protocol/app_setting_specifics.pb.h"
11 #include "sync/protocol/app_specifics.pb.h"
12 #include "sync/protocol/autofill_specifics.pb.h"
13 #include "sync/protocol/bookmark_specifics.pb.h"
14 #include "sync/protocol/extension_setting_specifics.pb.h"
15 #include "sync/protocol/extension_specifics.pb.h"
16 #include "sync/protocol/nigori_specifics.pb.h"
17 #include "sync/protocol/password_specifics.pb.h"
18 #include "sync/protocol/preference_specifics.pb.h"
19 #include "sync/protocol/search_engine_specifics.pb.h"
20 #include "sync/protocol/session_specifics.pb.h"
21 #include "sync/protocol/sync.pb.h"
22 #include "sync/protocol/theme_specifics.pb.h"
23 #include "sync/protocol/typed_url_specifics.pb.h"
24 #include "sync/syncable/syncable_proto_util.h"
25
26 namespace syncer {
27
28 void AddDefaultFieldValue(ModelType datatype,
29                           sync_pb::EntitySpecifics* specifics) {
30   if (!ProtocolTypes().Has(datatype)) {
31     NOTREACHED() << "Only protocol types have field values.";
32     return;
33   }
34   switch (datatype) {
35     case BOOKMARKS:
36       specifics->mutable_bookmark();
37       break;
38     case PASSWORDS:
39       specifics->mutable_password();
40       break;
41     case PREFERENCES:
42       specifics->mutable_preference();
43       break;
44     case AUTOFILL:
45       specifics->mutable_autofill();
46       break;
47     case AUTOFILL_PROFILE:
48       specifics->mutable_autofill_profile();
49       break;
50     case THEMES:
51       specifics->mutable_theme();
52       break;
53     case TYPED_URLS:
54       specifics->mutable_typed_url();
55       break;
56     case EXTENSIONS:
57       specifics->mutable_extension();
58       break;
59     case NIGORI:
60       specifics->mutable_nigori();
61       break;
62     case SEARCH_ENGINES:
63       specifics->mutable_search_engine();
64       break;
65     case SESSIONS:
66       specifics->mutable_session();
67       break;
68     case APPS:
69       specifics->mutable_app();
70       break;
71     case APP_LIST:
72       specifics->mutable_app_list();
73       break;
74     case APP_SETTINGS:
75       specifics->mutable_app_setting();
76       break;
77     case EXTENSION_SETTINGS:
78       specifics->mutable_extension_setting();
79       break;
80     case APP_NOTIFICATIONS:
81       specifics->mutable_app_notification();
82       break;
83     case HISTORY_DELETE_DIRECTIVES:
84       specifics->mutable_history_delete_directive();
85       break;
86     case SYNCED_NOTIFICATIONS:
87       specifics->mutable_synced_notification();
88       break;
89     case SYNCED_NOTIFICATION_APP_INFO:
90       specifics->mutable_synced_notification_app_info();
91       break;
92     case DEVICE_INFO:
93       specifics->mutable_device_info();
94       break;
95     case EXPERIMENTS:
96       specifics->mutable_experiments();
97       break;
98     case PRIORITY_PREFERENCES:
99       specifics->mutable_priority_preference();
100       break;
101     case DICTIONARY:
102       specifics->mutable_dictionary();
103       break;
104     case FAVICON_IMAGES:
105       specifics->mutable_favicon_image();
106       break;
107     case FAVICON_TRACKING:
108       specifics->mutable_favicon_tracking();
109       break;
110     case SUPERVISED_USER_SETTINGS:
111       specifics->mutable_managed_user_setting();
112       break;
113     case SUPERVISED_USERS:
114       specifics->mutable_managed_user();
115       break;
116     case SUPERVISED_USER_SHARED_SETTINGS:
117       specifics->mutable_managed_user_shared_setting();
118       break;
119     case ARTICLES:
120       specifics->mutable_article();
121       break;
122     default:
123       NOTREACHED() << "No known extension for model type.";
124   }
125 }
126
127 ModelType GetModelTypeFromSpecificsFieldNumber(int field_number) {
128   ModelTypeSet protocol_types = ProtocolTypes();
129   for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
130        iter.Inc()) {
131     if (GetSpecificsFieldNumberFromModelType(iter.Get()) == field_number)
132       return iter.Get();
133   }
134   return UNSPECIFIED;
135 }
136
137 int GetSpecificsFieldNumberFromModelType(ModelType model_type) {
138   DCHECK(ProtocolTypes().Has(model_type))
139       << "Only protocol types have field values.";
140   switch (model_type) {
141     case BOOKMARKS:
142       return sync_pb::EntitySpecifics::kBookmarkFieldNumber;
143     case PASSWORDS:
144       return sync_pb::EntitySpecifics::kPasswordFieldNumber;
145     case PREFERENCES:
146       return sync_pb::EntitySpecifics::kPreferenceFieldNumber;
147     case AUTOFILL:
148       return sync_pb::EntitySpecifics::kAutofillFieldNumber;
149     case AUTOFILL_PROFILE:
150       return sync_pb::EntitySpecifics::kAutofillProfileFieldNumber;
151     case THEMES:
152       return sync_pb::EntitySpecifics::kThemeFieldNumber;
153     case TYPED_URLS:
154       return sync_pb::EntitySpecifics::kTypedUrlFieldNumber;
155     case EXTENSIONS:
156       return sync_pb::EntitySpecifics::kExtensionFieldNumber;
157     case NIGORI:
158       return sync_pb::EntitySpecifics::kNigoriFieldNumber;
159     case SEARCH_ENGINES:
160       return sync_pb::EntitySpecifics::kSearchEngineFieldNumber;
161     case SESSIONS:
162       return sync_pb::EntitySpecifics::kSessionFieldNumber;
163     case APPS:
164       return sync_pb::EntitySpecifics::kAppFieldNumber;
165     case APP_LIST:
166       return sync_pb::EntitySpecifics::kAppListFieldNumber;
167     case APP_SETTINGS:
168       return sync_pb::EntitySpecifics::kAppSettingFieldNumber;
169     case EXTENSION_SETTINGS:
170       return sync_pb::EntitySpecifics::kExtensionSettingFieldNumber;
171     case APP_NOTIFICATIONS:
172       return sync_pb::EntitySpecifics::kAppNotificationFieldNumber;
173     case HISTORY_DELETE_DIRECTIVES:
174       return sync_pb::EntitySpecifics::kHistoryDeleteDirectiveFieldNumber;
175     case SYNCED_NOTIFICATIONS:
176       return sync_pb::EntitySpecifics::kSyncedNotificationFieldNumber;
177     case SYNCED_NOTIFICATION_APP_INFO:
178       return sync_pb::EntitySpecifics::kSyncedNotificationAppInfoFieldNumber;
179     case DEVICE_INFO:
180       return sync_pb::EntitySpecifics::kDeviceInfoFieldNumber;
181     case EXPERIMENTS:
182       return sync_pb::EntitySpecifics::kExperimentsFieldNumber;
183     case PRIORITY_PREFERENCES:
184       return sync_pb::EntitySpecifics::kPriorityPreferenceFieldNumber;
185     case DICTIONARY:
186       return sync_pb::EntitySpecifics::kDictionaryFieldNumber;
187     case FAVICON_IMAGES:
188       return sync_pb::EntitySpecifics::kFaviconImageFieldNumber;
189     case FAVICON_TRACKING:
190       return sync_pb::EntitySpecifics::kFaviconTrackingFieldNumber;
191     case SUPERVISED_USER_SETTINGS:
192       return sync_pb::EntitySpecifics::kManagedUserSettingFieldNumber;
193     case SUPERVISED_USERS:
194       return sync_pb::EntitySpecifics::kManagedUserFieldNumber;
195     case SUPERVISED_USER_SHARED_SETTINGS:
196       return sync_pb::EntitySpecifics::kManagedUserSharedSettingFieldNumber;
197     case ARTICLES:
198       return sync_pb::EntitySpecifics::kArticleFieldNumber;
199     default:
200       NOTREACHED() << "No known extension for model type.";
201       return 0;
202   }
203 }
204
205 FullModelTypeSet ToFullModelTypeSet(ModelTypeSet in) {
206   FullModelTypeSet out;
207   for (ModelTypeSet::Iterator i = in.First(); i.Good(); i.Inc()) {
208     out.Put(i.Get());
209   }
210   return out;
211 }
212
213 // Note: keep this consistent with GetModelType in entry.cc!
214 ModelType GetModelType(const sync_pb::SyncEntity& sync_entity) {
215   DCHECK(!IsRoot(sync_entity));  // Root shouldn't ever go over the wire.
216
217   // Backwards compatibility with old (pre-specifics) protocol.
218   if (sync_entity.has_bookmarkdata())
219     return BOOKMARKS;
220
221   ModelType specifics_type = GetModelTypeFromSpecifics(sync_entity.specifics());
222   if (specifics_type != UNSPECIFIED)
223     return specifics_type;
224
225   // Loose check for server-created top-level folders that aren't
226   // bound to a particular model type.
227   if (!sync_entity.server_defined_unique_tag().empty() &&
228       IsFolder(sync_entity)) {
229     return TOP_LEVEL_FOLDER;
230   }
231
232   // This is an item of a datatype we can't understand. Maybe it's
233   // from the future?  Either we mis-encoded the object, or the
234   // server sent us entries it shouldn't have.
235   NOTREACHED() << "Unknown datatype in sync proto.";
236   return UNSPECIFIED;
237 }
238
239 ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
240   if (specifics.has_bookmark())
241     return BOOKMARKS;
242
243   if (specifics.has_password())
244     return PASSWORDS;
245
246   if (specifics.has_preference())
247     return PREFERENCES;
248
249   if (specifics.has_autofill())
250     return AUTOFILL;
251
252   if (specifics.has_autofill_profile())
253     return AUTOFILL_PROFILE;
254
255   if (specifics.has_theme())
256     return THEMES;
257
258   if (specifics.has_typed_url())
259     return TYPED_URLS;
260
261   if (specifics.has_extension())
262     return EXTENSIONS;
263
264   if (specifics.has_nigori())
265     return NIGORI;
266
267   if (specifics.has_app())
268     return APPS;
269
270   if (specifics.has_app_list())
271     return APP_LIST;
272
273   if (specifics.has_search_engine())
274     return SEARCH_ENGINES;
275
276   if (specifics.has_session())
277     return SESSIONS;
278
279   if (specifics.has_app_setting())
280     return APP_SETTINGS;
281
282   if (specifics.has_extension_setting())
283     return EXTENSION_SETTINGS;
284
285   if (specifics.has_app_notification())
286     return APP_NOTIFICATIONS;
287
288   if (specifics.has_history_delete_directive())
289     return HISTORY_DELETE_DIRECTIVES;
290
291   if (specifics.has_synced_notification())
292     return SYNCED_NOTIFICATIONS;
293
294   if (specifics.has_synced_notification_app_info())
295     return SYNCED_NOTIFICATION_APP_INFO;
296
297   if (specifics.has_device_info())
298     return DEVICE_INFO;
299
300   if (specifics.has_experiments())
301     return EXPERIMENTS;
302
303   if (specifics.has_priority_preference())
304     return PRIORITY_PREFERENCES;
305
306   if (specifics.has_dictionary())
307     return DICTIONARY;
308
309   if (specifics.has_favicon_image())
310     return FAVICON_IMAGES;
311
312   if (specifics.has_favicon_tracking())
313     return FAVICON_TRACKING;
314
315   if (specifics.has_managed_user_setting())
316     return SUPERVISED_USER_SETTINGS;
317
318   if (specifics.has_managed_user())
319     return SUPERVISED_USERS;
320
321   if (specifics.has_managed_user_shared_setting())
322     return SUPERVISED_USER_SHARED_SETTINGS;
323
324   if (specifics.has_article())
325     return ARTICLES;
326
327   return UNSPECIFIED;
328 }
329
330 ModelTypeSet ProtocolTypes() {
331   ModelTypeSet set = ModelTypeSet::All();
332   set.RemoveAll(ProxyTypes());
333   return set;
334 }
335
336 ModelTypeSet UserTypes() {
337   ModelTypeSet set;
338   // TODO(sync): We should be able to build the actual enumset's internal
339   // bitset value here at compile time, rather than performing an iteration
340   // every time.
341   for (int i = FIRST_USER_MODEL_TYPE; i <= LAST_USER_MODEL_TYPE; ++i) {
342     set.Put(ModelTypeFromInt(i));
343   }
344   return set;
345 }
346
347 ModelTypeSet UserSelectableTypes() {
348   ModelTypeSet set;
349   // Although the order doesn't technically matter here, it's clearer to keep
350   // these in the same order as their definition in the ModelType enum.
351   set.Put(BOOKMARKS);
352   set.Put(PREFERENCES);
353   set.Put(PASSWORDS);
354   set.Put(AUTOFILL);
355   set.Put(THEMES);
356   set.Put(TYPED_URLS);
357   set.Put(EXTENSIONS);
358   set.Put(APPS);
359   set.Put(PROXY_TABS);
360   return set;
361 }
362
363 bool IsUserSelectableType(ModelType model_type) {
364   return UserSelectableTypes().Has(model_type);
365 }
366
367 ModelTypeSet EncryptableUserTypes() {
368   ModelTypeSet encryptable_user_types = UserTypes();
369   // We never encrypt history delete directives.
370   encryptable_user_types.Remove(HISTORY_DELETE_DIRECTIVES);
371   // Synced notifications are not encrypted since the server must see changes.
372   encryptable_user_types.Remove(SYNCED_NOTIFICATIONS);
373   // Synced Notification App Info does not have private data, so it is not
374   // encrypted.
375   encryptable_user_types.Remove(SYNCED_NOTIFICATION_APP_INFO);
376   // Priority preferences are not encrypted because they might be synced before
377   // encryption is ready.
378   encryptable_user_types.Remove(PRIORITY_PREFERENCES);
379   // Supervised user settings are not encrypted since they are set server-side.
380   encryptable_user_types.Remove(SUPERVISED_USER_SETTINGS);
381   // Supervised users are not encrypted since they are managed server-side.
382   encryptable_user_types.Remove(SUPERVISED_USERS);
383   // Supervised user shared settings are not encrypted since they are managed
384   // server-side and shared between manager and supervised user.
385   encryptable_user_types.Remove(SUPERVISED_USER_SHARED_SETTINGS);
386   // Proxy types have no sync representation and are therefore not encrypted.
387   // Note however that proxy types map to one or more protocol types, which
388   // may or may not be encrypted themselves.
389   encryptable_user_types.RemoveAll(ProxyTypes());
390   return encryptable_user_types;
391 }
392
393 ModelTypeSet PriorityUserTypes() {
394   return ModelTypeSet(PRIORITY_PREFERENCES);
395 }
396
397 ModelTypeSet ControlTypes() {
398   ModelTypeSet set;
399   // TODO(sync): We should be able to build the actual enumset's internal
400   // bitset value here at compile time, rather than performing an iteration
401   // every time.
402   for (int i = FIRST_CONTROL_MODEL_TYPE; i <= LAST_CONTROL_MODEL_TYPE; ++i) {
403     set.Put(ModelTypeFromInt(i));
404   }
405
406   return set;
407 }
408
409 ModelTypeSet ProxyTypes() {
410   ModelTypeSet set;
411   set.Put(PROXY_TABS);
412   return set;
413 }
414
415 bool IsControlType(ModelType model_type) {
416   return ControlTypes().Has(model_type);
417 }
418
419 ModelTypeSet CoreTypes() {
420   syncer::ModelTypeSet result;
421   result.PutAll(PriorityCoreTypes());
422
423   // The following are low priority core types.
424   result.Put(SYNCED_NOTIFICATIONS);
425   result.Put(SYNCED_NOTIFICATION_APP_INFO);
426   result.Put(SUPERVISED_USER_SHARED_SETTINGS);
427
428   return result;
429 }
430
431 ModelTypeSet PriorityCoreTypes() {
432   syncer::ModelTypeSet result;
433   result.PutAll(ControlTypes());
434
435   // The following are non-control core types.
436   result.Put(SUPERVISED_USERS);
437   result.Put(SUPERVISED_USER_SETTINGS);
438
439   return result;
440 }
441
442 ModelTypeSet BackupTypes() {
443   ModelTypeSet result;
444   result.Put(BOOKMARKS);
445   result.Put(PREFERENCES);
446   result.Put(THEMES);
447   result.Put(EXTENSIONS);
448   result.Put(SEARCH_ENGINES);
449   result.Put(APPS);
450   result.Put(APP_LIST);
451   result.Put(APP_SETTINGS);
452   result.Put(EXTENSION_SETTINGS);
453   result.Put(PRIORITY_PREFERENCES);
454   return result;
455 }
456
457 const char* ModelTypeToString(ModelType model_type) {
458   // This is used in serialization routines as well as for displaying debug
459   // information.  Do not attempt to change these string values unless you know
460   // what you're doing.
461   switch (model_type) {
462     case TOP_LEVEL_FOLDER:
463       return "Top Level Folder";
464     case UNSPECIFIED:
465       return "Unspecified";
466     case BOOKMARKS:
467       return "Bookmarks";
468     case PREFERENCES:
469       return "Preferences";
470     case PASSWORDS:
471       return "Passwords";
472     case AUTOFILL:
473       return "Autofill";
474     case THEMES:
475       return "Themes";
476     case TYPED_URLS:
477       return "Typed URLs";
478     case EXTENSIONS:
479       return "Extensions";
480     case NIGORI:
481       return "Encryption keys";
482     case SEARCH_ENGINES:
483       return "Search Engines";
484     case SESSIONS:
485       return "Sessions";
486     case APPS:
487       return "Apps";
488     case APP_LIST:
489       return "App List";
490     case AUTOFILL_PROFILE:
491       return "Autofill Profiles";
492     case APP_SETTINGS:
493       return "App settings";
494     case EXTENSION_SETTINGS:
495       return "Extension settings";
496     case APP_NOTIFICATIONS:
497       return "App Notifications";
498     case HISTORY_DELETE_DIRECTIVES:
499       return "History Delete Directives";
500     case SYNCED_NOTIFICATIONS:
501       return "Synced Notifications";
502     case SYNCED_NOTIFICATION_APP_INFO:
503       return "Synced Notification App Info";
504     case DEVICE_INFO:
505       return "Device Info";
506     case EXPERIMENTS:
507       return "Experiments";
508     case PRIORITY_PREFERENCES:
509       return "Priority Preferences";
510     case DICTIONARY:
511       return "Dictionary";
512     case FAVICON_IMAGES:
513       return "Favicon Images";
514     case FAVICON_TRACKING:
515       return "Favicon Tracking";
516     case SUPERVISED_USER_SETTINGS:
517       return "Managed User Settings";
518     case SUPERVISED_USERS:
519       return "Managed Users";
520     case SUPERVISED_USER_SHARED_SETTINGS:
521       return "Managed User Shared Settings";
522     case ARTICLES:
523       return "Articles";
524     case PROXY_TABS:
525       return "Tabs";
526     default:
527       break;
528   }
529   NOTREACHED() << "No known extension for model type.";
530   return "INVALID";
531 }
532
533 // The normal rules about histograms apply here.  Always append to the bottom of
534 // the list, and be careful to not reuse integer values that have already been
535 // assigned.  Don't forget to update histograms.xml when you make changes to
536 // this list.
537 int ModelTypeToHistogramInt(ModelType model_type) {
538   switch (model_type) {
539     case UNSPECIFIED:
540       return 0;
541     case TOP_LEVEL_FOLDER:
542       return 1;
543     case BOOKMARKS:
544       return 2;
545     case PREFERENCES:
546       return 3;
547     case PASSWORDS:
548       return 4;
549     case AUTOFILL_PROFILE:
550       return 5;
551     case AUTOFILL:
552       return 6;
553     case THEMES:
554       return 7;
555     case TYPED_URLS:
556       return 8;
557     case EXTENSIONS:
558       return 9;
559     case SEARCH_ENGINES:
560       return 10;
561     case SESSIONS:
562       return 11;
563     case APPS:
564       return 12;
565     case APP_SETTINGS:
566       return 13;
567     case EXTENSION_SETTINGS:
568       return 14;
569     case APP_NOTIFICATIONS:
570       return 15;
571     case HISTORY_DELETE_DIRECTIVES:
572       return 16;
573     case NIGORI:
574       return 17;
575     case DEVICE_INFO:
576       return 18;
577     case EXPERIMENTS:
578       return 19;
579     case SYNCED_NOTIFICATIONS:
580       return 20;
581     case PRIORITY_PREFERENCES:
582       return 21;
583     case DICTIONARY:
584       return 22;
585     case FAVICON_IMAGES:
586       return 23;
587     case FAVICON_TRACKING:
588       return 24;
589     case PROXY_TABS:
590       return 25;
591     case SUPERVISED_USER_SETTINGS:
592       return 26;
593     case SUPERVISED_USERS:
594       return 27;
595     case ARTICLES:
596       return 28;
597     case APP_LIST:
598       return 29;
599     case SUPERVISED_USER_SHARED_SETTINGS:
600       return 30;
601     case SYNCED_NOTIFICATION_APP_INFO:
602       return 31;
603     // Silence a compiler warning.
604     case MODEL_TYPE_COUNT:
605       return 0;
606   }
607   return 0;
608 }
609
610 base::StringValue* ModelTypeToValue(ModelType model_type) {
611   if (model_type >= FIRST_REAL_MODEL_TYPE) {
612     return new base::StringValue(ModelTypeToString(model_type));
613   } else if (model_type == TOP_LEVEL_FOLDER) {
614     return new base::StringValue("Top-level folder");
615   } else if (model_type == UNSPECIFIED) {
616     return new base::StringValue("Unspecified");
617   }
618   NOTREACHED();
619   return new base::StringValue(std::string());
620 }
621
622 ModelType ModelTypeFromValue(const base::Value& value) {
623   if (value.IsType(base::Value::TYPE_STRING)) {
624     std::string result;
625     CHECK(value.GetAsString(&result));
626     return ModelTypeFromString(result);
627   } else if (value.IsType(base::Value::TYPE_INTEGER)) {
628     int result;
629     CHECK(value.GetAsInteger(&result));
630     return ModelTypeFromInt(result);
631   } else {
632     NOTREACHED() << "Unsupported value type: " << value.GetType();
633     return UNSPECIFIED;
634   }
635 }
636
637 ModelType ModelTypeFromString(const std::string& model_type_string) {
638   if (model_type_string == "Bookmarks")
639     return BOOKMARKS;
640   else if (model_type_string == "Preferences")
641     return PREFERENCES;
642   else if (model_type_string == "Passwords")
643     return PASSWORDS;
644   else if (model_type_string == "Autofill")
645     return AUTOFILL;
646   else if (model_type_string == "Autofill Profiles")
647     return AUTOFILL_PROFILE;
648   else if (model_type_string == "Themes")
649     return THEMES;
650   else if (model_type_string == "Typed URLs")
651     return TYPED_URLS;
652   else if (model_type_string == "Extensions")
653     return EXTENSIONS;
654   else if (model_type_string == "Encryption keys")
655     return NIGORI;
656   else if (model_type_string == "Search Engines")
657     return SEARCH_ENGINES;
658   else if (model_type_string == "Sessions")
659     return SESSIONS;
660   else if (model_type_string == "Apps")
661     return APPS;
662   else if (model_type_string == "App List")
663     return APP_LIST;
664   else if (model_type_string == "App settings")
665     return APP_SETTINGS;
666   else if (model_type_string == "Extension settings")
667     return EXTENSION_SETTINGS;
668   else if (model_type_string == "App Notifications")
669     return APP_NOTIFICATIONS;
670   else if (model_type_string == "History Delete Directives")
671     return HISTORY_DELETE_DIRECTIVES;
672   else if (model_type_string == "Synced Notifications")
673     return SYNCED_NOTIFICATIONS;
674   else if (model_type_string == "Synced Notification App Info")
675     return SYNCED_NOTIFICATION_APP_INFO;
676   else if (model_type_string == "Device Info")
677     return DEVICE_INFO;
678   else if (model_type_string == "Experiments")
679     return EXPERIMENTS;
680   else if (model_type_string == "Priority Preferences")
681     return PRIORITY_PREFERENCES;
682   else if (model_type_string == "Dictionary")
683     return DICTIONARY;
684   else if (model_type_string == "Favicon Images")
685     return FAVICON_IMAGES;
686   else if (model_type_string == "Favicon Tracking")
687     return FAVICON_TRACKING;
688   else if (model_type_string == "Managed User Settings")
689     return SUPERVISED_USER_SETTINGS;
690   else if (model_type_string == "Managed Users")
691     return SUPERVISED_USERS;
692   else if (model_type_string == "Managed User Shared Settings")
693     return SUPERVISED_USER_SHARED_SETTINGS;
694   else if (model_type_string == "Articles")
695     return ARTICLES;
696   else if (model_type_string == "Tabs")
697     return PROXY_TABS;
698   else
699     NOTREACHED() << "No known model type corresponding to "
700                  << model_type_string << ".";
701   return UNSPECIFIED;
702 }
703
704 std::string ModelTypeSetToString(ModelTypeSet model_types) {
705   std::string result;
706   for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
707     if (!result.empty()) {
708       result += ", ";
709     }
710     result += ModelTypeToString(it.Get());
711   }
712   return result;
713 }
714
715 ModelTypeSet ModelTypeSetFromString(const std::string& model_types_string) {
716   std::string working_copy = model_types_string;
717   ModelTypeSet model_types;
718   while (!working_copy.empty()) {
719     // Remove any leading spaces.
720     working_copy = working_copy.substr(working_copy.find_first_not_of(' '));
721     if (working_copy.empty())
722       break;
723     std::string type_str;
724     size_t end = working_copy.find(',');
725     if (end == std::string::npos) {
726       end = working_copy.length() - 1;
727       type_str = working_copy;
728     } else {
729       type_str = working_copy.substr(0, end);
730     }
731     syncer::ModelType type = ModelTypeFromString(type_str);
732     if (IsRealDataType(type))
733       model_types.Put(type);
734     working_copy = working_copy.substr(end + 1);
735   }
736   return model_types;
737 }
738
739 base::ListValue* ModelTypeSetToValue(ModelTypeSet model_types) {
740   base::ListValue* value = new base::ListValue();
741   for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
742     value->Append(new base::StringValue(ModelTypeToString(it.Get())));
743   }
744   return value;
745 }
746
747 ModelTypeSet ModelTypeSetFromValue(const base::ListValue& value) {
748   ModelTypeSet result;
749   for (base::ListValue::const_iterator i = value.begin();
750        i != value.end(); ++i) {
751     result.Put(ModelTypeFromValue(**i));
752   }
753   return result;
754 }
755
756 // TODO(zea): remove all hardcoded tags in model associators and have them use
757 // this instead.
758 // NOTE: Proxy types should return empty strings (so that we don't NOTREACHED
759 // in tests when we verify they have no root node).
760 std::string ModelTypeToRootTag(ModelType type) {
761   switch (type) {
762     case BOOKMARKS:
763       return "google_chrome_bookmarks";
764     case PREFERENCES:
765       return "google_chrome_preferences";
766     case PASSWORDS:
767       return "google_chrome_passwords";
768     case AUTOFILL:
769       return "google_chrome_autofill";
770     case THEMES:
771       return "google_chrome_themes";
772     case TYPED_URLS:
773       return "google_chrome_typed_urls";
774     case EXTENSIONS:
775       return "google_chrome_extensions";
776     case NIGORI:
777       return "google_chrome_nigori";
778     case SEARCH_ENGINES:
779       return "google_chrome_search_engines";
780     case SESSIONS:
781       return "google_chrome_sessions";
782     case APPS:
783       return "google_chrome_apps";
784     case APP_LIST:
785       return "google_chrome_app_list";
786     case AUTOFILL_PROFILE:
787       return "google_chrome_autofill_profiles";
788     case APP_SETTINGS:
789       return "google_chrome_app_settings";
790     case EXTENSION_SETTINGS:
791       return "google_chrome_extension_settings";
792     case APP_NOTIFICATIONS:
793       return "google_chrome_app_notifications";
794     case HISTORY_DELETE_DIRECTIVES:
795       return "google_chrome_history_delete_directives";
796     case SYNCED_NOTIFICATIONS:
797       return "google_chrome_synced_notifications";
798     case SYNCED_NOTIFICATION_APP_INFO:
799       return "google_chrome_synced_notification_app_info";
800     case DEVICE_INFO:
801       return "google_chrome_device_info";
802     case EXPERIMENTS:
803       return "google_chrome_experiments";
804     case PRIORITY_PREFERENCES:
805       return "google_chrome_priority_preferences";
806     case DICTIONARY:
807       return "google_chrome_dictionary";
808     case FAVICON_IMAGES:
809       return "google_chrome_favicon_images";
810     case FAVICON_TRACKING:
811       return "google_chrome_favicon_tracking";
812     case SUPERVISED_USER_SETTINGS:
813       return "google_chrome_managed_user_settings";
814     case SUPERVISED_USERS:
815       return "google_chrome_managed_users";
816     case SUPERVISED_USER_SHARED_SETTINGS:
817       return "google_chrome_managed_user_shared_settings";
818     case ARTICLES:
819       return "google_chrome_articles";
820     case PROXY_TABS:
821       return std::string();
822     default:
823       break;
824   }
825   NOTREACHED() << "No known extension for model type.";
826   return "INVALID";
827 }
828
829 // TODO(akalin): Figure out a better way to do these mappings.
830 // Note: Do not include proxy types in this list. They should never receive
831 // or trigger notifications.
832 namespace {
833 const char kBookmarkNotificationType[] = "BOOKMARK";
834 const char kPreferenceNotificationType[] = "PREFERENCE";
835 const char kPasswordNotificationType[] = "PASSWORD";
836 const char kAutofillNotificationType[] = "AUTOFILL";
837 const char kThemeNotificationType[] = "THEME";
838 const char kTypedUrlNotificationType[] = "TYPED_URL";
839 const char kExtensionNotificationType[] = "EXTENSION";
840 const char kExtensionSettingNotificationType[] = "EXTENSION_SETTING";
841 const char kNigoriNotificationType[] = "NIGORI";
842 const char kAppSettingNotificationType[] = "APP_SETTING";
843 const char kAppNotificationType[] = "APP";
844 const char kAppListNotificationType[] = "APP_LIST";
845 const char kSearchEngineNotificationType[] = "SEARCH_ENGINE";
846 const char kSessionNotificationType[] = "SESSION";
847 const char kAutofillProfileNotificationType[] = "AUTOFILL_PROFILE";
848 const char kAppNotificationNotificationType[] = "APP_NOTIFICATION";
849 const char kHistoryDeleteDirectiveNotificationType[] =
850     "HISTORY_DELETE_DIRECTIVE";
851 const char kSyncedNotificationType[] = "SYNCED_NOTIFICATION";
852 const char kSyncedNotificationAppInfoType[] = "SYNCED_NOTIFICATION_APP_INFO";
853 const char kDeviceInfoNotificationType[] = "DEVICE_INFO";
854 const char kExperimentsNotificationType[] = "EXPERIMENTS";
855 const char kPriorityPreferenceNotificationType[] = "PRIORITY_PREFERENCE";
856 const char kDictionaryNotificationType[] = "DICTIONARY";
857 const char kFaviconImageNotificationType[] = "FAVICON_IMAGE";
858 const char kFaviconTrackingNotificationType[] = "FAVICON_TRACKING";
859 const char kSupervisedUserSettingNotificationType[] = "MANAGED_USER_SETTING";
860 const char kSupervisedUserNotificationType[] = "MANAGED_USER";
861 const char kSupervisedUserSharedSettingNotificationType[] =
862     "MANAGED_USER_SHARED_SETTING";
863 const char kArticleNotificationType[] = "ARTICLE";
864 }  // namespace
865
866 bool RealModelTypeToNotificationType(ModelType model_type,
867                                      std::string* notification_type) {
868   switch (model_type) {
869     case BOOKMARKS:
870       *notification_type = kBookmarkNotificationType;
871       return true;
872     case PREFERENCES:
873       *notification_type = kPreferenceNotificationType;
874       return true;
875     case PASSWORDS:
876       *notification_type = kPasswordNotificationType;
877       return true;
878     case AUTOFILL:
879       *notification_type = kAutofillNotificationType;
880       return true;
881     case THEMES:
882       *notification_type = kThemeNotificationType;
883       return true;
884     case TYPED_URLS:
885       *notification_type = kTypedUrlNotificationType;
886       return true;
887     case EXTENSIONS:
888       *notification_type = kExtensionNotificationType;
889       return true;
890     case NIGORI:
891       *notification_type = kNigoriNotificationType;
892       return true;
893     case APP_SETTINGS:
894       *notification_type = kAppSettingNotificationType;
895       return true;
896     case APPS:
897       *notification_type = kAppNotificationType;
898       return true;
899     case APP_LIST:
900       *notification_type = kAppListNotificationType;
901       return true;
902     case SEARCH_ENGINES:
903       *notification_type = kSearchEngineNotificationType;
904       return true;
905     case SESSIONS:
906       *notification_type = kSessionNotificationType;
907       return true;
908     case AUTOFILL_PROFILE:
909       *notification_type = kAutofillProfileNotificationType;
910       return true;
911     case EXTENSION_SETTINGS:
912       *notification_type = kExtensionSettingNotificationType;
913       return true;
914     case APP_NOTIFICATIONS:
915       *notification_type = kAppNotificationNotificationType;
916       return true;
917     case HISTORY_DELETE_DIRECTIVES:
918       *notification_type = kHistoryDeleteDirectiveNotificationType;
919       return true;
920     case SYNCED_NOTIFICATIONS:
921       *notification_type = kSyncedNotificationType;
922       return true;
923     case SYNCED_NOTIFICATION_APP_INFO:
924       *notification_type = kSyncedNotificationAppInfoType;
925       return true;
926     case DEVICE_INFO:
927       *notification_type = kDeviceInfoNotificationType;
928       return true;
929     case EXPERIMENTS:
930       *notification_type = kExperimentsNotificationType;
931       return true;
932     case PRIORITY_PREFERENCES:
933       *notification_type = kPriorityPreferenceNotificationType;
934       return true;
935     case DICTIONARY:
936       *notification_type = kDictionaryNotificationType;
937       return true;
938     case FAVICON_IMAGES:
939       *notification_type = kFaviconImageNotificationType;
940       return true;
941     case FAVICON_TRACKING:
942       *notification_type = kFaviconTrackingNotificationType;
943       return true;
944     case SUPERVISED_USER_SETTINGS:
945       *notification_type = kSupervisedUserSettingNotificationType;
946       return true;
947     case SUPERVISED_USERS:
948       *notification_type = kSupervisedUserNotificationType;
949       return true;
950     case SUPERVISED_USER_SHARED_SETTINGS:
951       *notification_type = kSupervisedUserSharedSettingNotificationType;
952       return true;
953     case ARTICLES:
954       *notification_type = kArticleNotificationType;
955       return true;
956     default:
957       break;
958   }
959   notification_type->clear();
960   return false;
961 }
962
963 bool NotificationTypeToRealModelType(const std::string& notification_type,
964                                      ModelType* model_type) {
965   if (notification_type == kBookmarkNotificationType) {
966     *model_type = BOOKMARKS;
967     return true;
968   } else if (notification_type == kPreferenceNotificationType) {
969     *model_type = PREFERENCES;
970     return true;
971   } else if (notification_type == kPasswordNotificationType) {
972     *model_type = PASSWORDS;
973     return true;
974   } else if (notification_type == kAutofillNotificationType) {
975     *model_type = AUTOFILL;
976     return true;
977   } else if (notification_type == kThemeNotificationType) {
978     *model_type = THEMES;
979     return true;
980   } else if (notification_type == kTypedUrlNotificationType) {
981     *model_type = TYPED_URLS;
982     return true;
983   } else if (notification_type == kExtensionNotificationType) {
984     *model_type = EXTENSIONS;
985     return true;
986   } else if (notification_type == kNigoriNotificationType) {
987     *model_type = NIGORI;
988     return true;
989   } else if (notification_type == kAppNotificationType) {
990     *model_type = APPS;
991     return true;
992   } else if (notification_type == kAppListNotificationType) {
993     *model_type = APP_LIST;
994     return true;
995   } else if (notification_type == kSearchEngineNotificationType) {
996     *model_type = SEARCH_ENGINES;
997     return true;
998   } else if (notification_type == kSessionNotificationType) {
999     *model_type = SESSIONS;
1000     return true;
1001   } else if (notification_type == kAutofillProfileNotificationType) {
1002     *model_type = AUTOFILL_PROFILE;
1003     return true;
1004   } else if (notification_type == kAppSettingNotificationType) {
1005     *model_type = APP_SETTINGS;
1006     return true;
1007   } else if (notification_type == kExtensionSettingNotificationType) {
1008     *model_type = EXTENSION_SETTINGS;
1009     return true;
1010   } else if (notification_type == kAppNotificationNotificationType) {
1011     *model_type = APP_NOTIFICATIONS;
1012     return true;
1013   } else if (notification_type == kHistoryDeleteDirectiveNotificationType) {
1014     *model_type = HISTORY_DELETE_DIRECTIVES;
1015     return true;
1016   } else if (notification_type == kSyncedNotificationType) {
1017     *model_type = SYNCED_NOTIFICATIONS;
1018     return true;
1019   } else if (notification_type == kSyncedNotificationAppInfoType) {
1020     *model_type = SYNCED_NOTIFICATION_APP_INFO;
1021     return true;
1022   } else if (notification_type == kDeviceInfoNotificationType) {
1023     *model_type = DEVICE_INFO;
1024     return true;
1025   } else if (notification_type == kExperimentsNotificationType) {
1026     *model_type = EXPERIMENTS;
1027     return true;
1028   } else if (notification_type == kPriorityPreferenceNotificationType) {
1029     *model_type = PRIORITY_PREFERENCES;
1030     return true;
1031   } else if (notification_type == kDictionaryNotificationType) {
1032     *model_type = DICTIONARY;
1033     return true;
1034   } else if (notification_type == kFaviconImageNotificationType) {
1035     *model_type = FAVICON_IMAGES;
1036     return true;
1037   } else if (notification_type == kFaviconTrackingNotificationType) {
1038     *model_type = FAVICON_TRACKING;
1039     return true;
1040   } else if (notification_type == kSupervisedUserSettingNotificationType) {
1041     *model_type = SUPERVISED_USER_SETTINGS;
1042     return true;
1043   } else if (notification_type == kSupervisedUserNotificationType) {
1044     *model_type = SUPERVISED_USERS;
1045     return true;
1046   } else if (notification_type ==
1047       kSupervisedUserSharedSettingNotificationType) {
1048     *model_type = SUPERVISED_USER_SHARED_SETTINGS;
1049     return true;
1050   } else if (notification_type == kArticleNotificationType) {
1051     *model_type = ARTICLES;
1052     return true;
1053   }
1054   *model_type = UNSPECIFIED;
1055   return false;
1056 }
1057
1058 bool IsRealDataType(ModelType model_type) {
1059   return model_type >= FIRST_REAL_MODEL_TYPE && model_type < MODEL_TYPE_COUNT;
1060 }
1061
1062 bool IsProxyType(ModelType model_type) {
1063   return model_type >= FIRST_PROXY_TYPE && model_type <= LAST_PROXY_TYPE;
1064 }
1065
1066 bool IsActOnceDataType(ModelType model_type) {
1067   return model_type == HISTORY_DELETE_DIRECTIVES;
1068 }
1069
1070 }  // namespace syncer