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