diff options
author | Christophe Fergeau <teuf@gnome.org> | 2008-06-24 18:39:38 +0000 |
---|---|---|
committer | Christophe Fergeau <teuf@gnome.org> | 2008-06-24 18:39:38 +0000 |
commit | 0dc45559fe076a17464cf6ff26f37d15eb31e802 (patch) | |
tree | a3c640b7f50204369d242df4c13b354e4688df74 /src/itdb_device.c | |
parent | 20b97f3b41ec433e87231549cb239417f748cd99 (diff) | |
download | libgpod-tmz-0dc45559fe076a17464cf6ff26f37d15eb31e802.tar.gz libgpod-tmz-0dc45559fe076a17464cf6ff26f37d15eb31e802.tar.xz libgpod-tmz-0dc45559fe076a17464cf6ff26f37d15eb31e802.zip |
* src/itdb_device.c: rework timezone handling: handle timezones as
stored on 5g ipods (hopefully) and fallback to using the computer
timezone if we can't figure out the ipod timezone
* tests/get-timezone.c: use functions from libgpod to get the
timezone instead of duplicating some itdb_device code
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@2018 f01d2545-417e-4e96-918e-98f8d0dbbcb6
Diffstat (limited to 'src/itdb_device.c')
-rw-r--r-- | src/itdb_device.c | 163 |
1 files changed, 131 insertions, 32 deletions
diff --git a/src/itdb_device.c b/src/itdb_device.c index 0a5f37b..2197e72 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -38,10 +38,12 @@ #include <string.h> #include <sys/stat.h> #include <sys/types.h> +#include <time.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <glib/gi18n-lib.h> +#include <glib/gstdio.h> static const Itdb_IpodInfo ipod_info_table [] = { /* Handle idiots who hose their iPod file system, or lucky people @@ -1182,73 +1184,170 @@ gboolean itdb_device_supports_photo (const Itdb_Device *device) return (itdb_device_get_artwork_formats (device, ARTWORK_TYPE_PHOTO) != NULL); } - -/* This function reads the timezone information from the iPod and sets it in - * the Itdb_Device structure. If an error occurs, the function returns silently - * and the timezone shift is set to 0 - */ -static void itdb_device_set_timezone_info (Itdb_Device *device) +static char * +get_preferences_path (const Itdb_Device *device) { + const gchar *p_preferences[] = {"Preferences", NULL}; char *dev_path; char *prefs_filename; - FILE *f; - gint32 timezone; - const int GMT_OFFSET = 0x19; - int result; - - device->timezone_shift = 0; if (device->mountpoint == NULL) { - /* Assumes the iPod is in the UTC timezone for those cases */ - return; + return NULL; } dev_path = itdb_get_device_dir (device->mountpoint); if (dev_path == NULL) { - return ; + return NULL; } prefs_filename = itdb_resolve_path (dev_path, p_preferences); g_free (dev_path); - f = fopen (prefs_filename, "r"); + return prefs_filename; +} + +static gboolean itdb_device_read_raw_timezone (const char *prefs_path, + glong offset, + gint16 *timezone) +{ + FILE *f; + int result; + + if (timezone == NULL) { + return FALSE; + } + + f = fopen (prefs_path, "r"); if (f == NULL) { - g_free (prefs_filename); - return; + return FALSE; } - result = fseek (f, 0xB10, SEEK_SET); + result = fseek (f, offset, SEEK_SET); if (result != 0) { fclose (f); - g_free (prefs_filename); - return; + return FALSE; } - result = fread (&timezone, sizeof (timezone), 1, f); + result = fread (timezone, sizeof (*timezone), 1, f); if (result != 1) { fclose (f); - g_free (prefs_filename); - return; + return FALSE; } fclose (f); - g_free (prefs_filename); - timezone = GINT32_FROM_LE (timezone); - if ((timezone < 0) || (timezone > (2*12) << 1)) { + *timezone = GINT16_FROM_LE (*timezone); + + return TRUE; +} + +static gboolean raw_timezone_to_utc_shift_4g (gint16 raw_timezone, + gint *utc_shift) +{ + const int GMT_OFFSET = 0x19; + + if (utc_shift == NULL) { + return FALSE; + } + + if ((raw_timezone < 0) || (raw_timezone > (2*12) << 1)) { /* invalid timezone */ - return; + return FALSE; } - timezone -= GMT_OFFSET; + raw_timezone -= GMT_OFFSET; - device->timezone_shift = (timezone >> 1) * 3600; - if (timezone & 1) { + *utc_shift = (raw_timezone >> 1) * 3600; + if (raw_timezone & 1) { /* Adjust for DST */ - device->timezone_shift += 3600; + *utc_shift += 3600; + } + + return TRUE; +} + +static gboolean raw_timezone_to_utc_shift_5g (gint16 raw_timezone, + gint *utc_shift) +{ + const int TZ_SHIFT = 8; + + if (utc_shift == NULL) { + return FALSE; + } + /* The iPod stores the timezone information as a number of minutes + * from Tokyo timezone which increases when going eastward (ie + * going from Tokyo to LA and then to Europe). + * The calculation below shifts the origin so that 0 corresponds + * to UTC-12 and the max is 24*60 and corresponds to UTC+12 + * Finally, we substract 12*60 to that value to get a signed number + * giving the timezone relative to UTC. + */ + *utc_shift = raw_timezone*60 - TZ_SHIFT*3600; + + return TRUE; +} + +static gint get_local_timezone (void) +{ + return timezone; /* global variable defined by time.h, see man tzset */ +} + +/* This function reads the timezone information from the iPod and sets it in + * the Itdb_Device structure. If an error occurs, the function returns silently + * and the timezone shift is set to 0 + */ +static void itdb_device_set_timezone_info (Itdb_Device *device) +{ + gint16 raw_timezone; + gint timezone = 0; + gboolean result; + struct stat stat_buf; + int status; + char *prefs_path; + + device->timezone_shift = get_local_timezone (); + + prefs_path = get_preferences_path (device); + status = g_stat (prefs_path, &stat_buf); + if (status != 0) { + g_free (prefs_path); + return; + } + switch (stat_buf.st_size) { + case 2892: + result = itdb_device_read_raw_timezone (prefs_path, 0xb10, + &raw_timezone); + g_free (prefs_path); + if (!result) { + return; + } + result = raw_timezone_to_utc_shift_4g (raw_timezone, &timezone); + break; + case 2924: + result = itdb_device_read_raw_timezone (prefs_path, 0xb22, + &raw_timezone); + g_free (prefs_path); + if (!result) { + return; + } + result = raw_timezone_to_utc_shift_5g (raw_timezone, &timezone); + break; + case 2952: + /* ipod classic, not implemented yet */ + default: + /* We don't know how to get the timezone of this ipod model, + * assume the computer timezone and the ipod timezone match + */ + return; } + + if ((timezone < -12*3600) || (timezone > 12 * 3600)) { + return; + } + + device->timezone_shift = timezone; } /** |