| 101 | } |
| 102 | |
| 103 | bool CrossPointSettings::loadFromFile() { |
| 104 | // Try JSON first |
| 105 | if (Storage.exists(SETTINGS_FILE_JSON)) { |
| 106 | String json = Storage.readFile(SETTINGS_FILE_JSON); |
| 107 | if (!json.isEmpty()) { |
| 108 | bool resave = false; |
| 109 | bool result = JsonSettingsIO::loadSettings(*this, json.c_str(), &resave); |
| 110 | if (result && resave) { |
| 111 | if (saveToFile()) { |
| 112 | LOG_DBG("CPS", "Resaved settings to update format"); |
| 113 | } else { |
| 114 | LOG_ERR("CPS", "Failed to resave settings after format update"); |
| 115 | } |
| 116 | } |
| 117 | migrateLanguageBinaryFile(); |
| 118 | return result; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | // Fall back to binary migration |
| 123 | if (Storage.exists(SETTINGS_FILE_BIN)) { |
| 124 | if (loadFromBinaryFile()) { |
| 125 | migrateLanguageBinaryFile(); |
| 126 | if (saveToFile()) { |
| 127 | Storage.rename(SETTINGS_FILE_BIN, SETTINGS_FILE_BAK); |
| 128 | LOG_DBG("CPS", "Migrated settings.bin to settings.json"); |
| 129 | return true; |
| 130 | } else { |
| 131 | LOG_ERR("CPS", "Failed to save migrated settings to JSON"); |
| 132 | return false; |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | // No settings files at all -- check for standalone language.bin |
| 138 | return migrateLanguageBinaryFile(); |
| 139 | } |
| 140 | |
| 141 | bool CrossPointSettings::migrateLanguageBinaryFile() { |
| 142 | // V1_LANGUAGES / V1_LANGUAGE_COUNT are emitted by gen_i18n.py with the |