diff --git a/docs/iPod_setup_languages.jpg b/docs/iPod_setup_languages.jpg new file mode 100644 index 0000000..cdc4894 Binary files /dev/null and b/docs/iPod_setup_languages.jpg differ diff --git a/docs/ipod_languages_screenshot.png b/docs/ipod_languages_screenshot.png deleted file mode 100644 index 9f35767..0000000 Binary files a/docs/ipod_languages_screenshot.png and /dev/null differ diff --git a/parser/Cargo.toml b/parser/Cargo.toml index 149683e..c857743 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -8,3 +8,6 @@ edition = "2021" [dependencies] chrono = "0.4.31" csv = "1.3.0" + +# Languages parsing +isolang = "2.4.0" \ No newline at end of file diff --git a/parser/src/constants/preferences_constants.rs b/parser/src/constants/preferences_constants.rs index 971f26a..e63fcfc 100644 --- a/parser/src/constants/preferences_constants.rs +++ b/parser/src/constants/preferences_constants.rs @@ -30,4 +30,4 @@ pub const VOLUME_LIMIT_OFFSET : usize = 2896; // 0xB50 pub const VOLUME_LIMIT_LEN : usize = 1; pub const REGION_OFFSET : usize = 2928; // 0xB70 -pub const REGION_LEN : usize = 1; +pub const REGION_LEN : usize = 2; diff --git a/parser/src/parsers/preferences_parser.rs b/parser/src/parsers/preferences_parser.rs index e73e2d5..bf28a69 100644 --- a/parser/src/parsers/preferences_parser.rs +++ b/parser/src/parsers/preferences_parser.rs @@ -72,9 +72,9 @@ pub fn parse_preferences_file(itunesdb_file_as_bytes: Vec) { println!("Daylight Savings Time enabled?: {}", preferences::is_daylight_savings_enabled(dst_setting_raw as u8)); - let language_selection_idx = helpers::get_slice_as_le_u32(idx, &itunesdb_file_as_bytes, preferences_constants::LANGUAGE_SELECTION_OFFSET, preferences_constants::LANGUAGE_SELECTION_LEN); + let lang_selection_idx = helpers::get_slice_as_le_u32(idx, &itunesdb_file_as_bytes, preferences_constants::LANGUAGE_SELECTION_OFFSET, preferences_constants::LANGUAGE_SELECTION_LEN); - println!("Selected language idx: {}", language_selection_idx); + println!("Selected language idx: {} ~ Parses to '{}'", lang_selection_idx, preferences::decode_language_from_idx(lang_selection_idx as u8)); let tz_info_raw = helpers::get_slice_as_le_u32(idx, &itunesdb_file_as_bytes, preferences_constants::TIMEZONE_INFO_OFFSET, preferences_constants::TIMEZONE_INFO_LEN); diff --git a/parser/src/preferences.rs b/parser/src/preferences.rs index 0fa1ee7..8fe15f4 100644 --- a/parser/src/preferences.rs +++ b/parser/src/preferences.rs @@ -5,7 +5,6 @@ * Provides functionality for working with the Preferences file */ -use std::num::Wrapping; pub fn is_daylight_savings_enabled(raw_dst_setting : u8) -> bool { @@ -14,11 +13,56 @@ pub fn is_daylight_savings_enabled(raw_dst_setting : u8) -> bool { return raw_dst_setting == dst_enabled_val; } +/// This function is a little bit dubious, the logic for it was added in a comment on the original documentation +/// and I get invalid values with it sometimes. pub fn decode_timezone(raw_timezone_info : u8) -> u8 { let gmt_timezone_const = 0x19; // 25d, supposed to represent GMT (UTC+0) - let timezone_hour = (Wrapping(raw_timezone_info)) - Wrapping(gmt_timezone_const); + let timezone_hour = (std::num::Wrapping(raw_timezone_info)) - std::num::Wrapping(gmt_timezone_const); return timezone_hour.0 / 2; +} + +/// This was a little bit tricky to figure out. The index comes from when the device starts up for the first time, and +/// asks you to choose the language list. +/// I couldn't find anywhere this was documented so I ended up having to find an old iPod myself, reset it, and scroll +/// through the list of available languages. +/// Note that interestingly, the string tables on the iPod (stored in the UISS_combined.plist file) have the language strings +/// installed for "Thai" (`th-TH`), even though in the settings you can't actually change the device to that language. +pub fn decode_language_from_idx(lang_idx : u8) -> String { + + let selected_lang : Option = match lang_idx { + 0_u8 | 1_u8 => isolang::Language::from_639_1("en"), + 2_u8 => isolang::Language::from_639_1("ja"), + 3_u8 => isolang::Language::from_639_1("cs"), + 4_u8 => isolang::Language::from_639_1("da"), + 5_u8 => isolang::Language::from_639_1("de"), + 6_u8 => isolang::Language::from_639_1("es"), + 7_u8 => isolang::Language::from_639_1("fr"), + 8_u8 => isolang::Language::from_639_1("el"), + 9_u8 => isolang::Language::from_639_1("hr"), + 10_u8 =>isolang::Language::from_639_1("it"), + 11_u8 => isolang::Language::from_639_1("hu"), + 12_u8 => isolang::Language::from_639_1("nl"), + 13_u8 => isolang::Language::from_639_1("no"), + 14_u8 | 15_u8 => isolang::Language::from_639_1("pt"), + 16_u8 => isolang::Language::from_639_1("ru"), + 17_u8 => isolang::Language::from_639_1("pl"), + 18_u8 => isolang::Language::from_639_1("ro"), + 19_u8 => isolang::Language::from_639_1("sk"), + 20_u8 => isolang::Language::from_639_1("fi"), + 21_u8 => isolang::Language::from_639_1("sv"), + 22_u8 => isolang::Language::from_639_1("tr"), + 23_u8 => isolang::Language::from_639_1("ar"), + 24_u8 => isolang::Language::from_639_1("ko"), + 25_u8 | 26_u8 | 27_u8 => isolang::Language::from_639_1("zh"), + 28_u8 => isolang::Language::from_639_1("he"), + unknown_lang_code => { + panic!("'{}' is not a valid ISO-639-1 language code", unknown_lang_code); + } + + }; + + return selected_lang.unwrap().to_name().to_string(); } \ No newline at end of file