summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorteuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6>2008-06-24 18:39:38 +0000
committerteuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6>2008-06-24 18:39:38 +0000
commit58d08a77ea60ac3d98d9217061cc8123c71842bb (patch)
treea3c640b7f50204369d242df4c13b354e4688df74
parent1b04395686fa620779e5eb1bc6f46abaa42e17dc (diff)
downloadlibgpod-58d08a77ea60ac3d98d9217061cc8123c71842bb.tar.gz
libgpod-58d08a77ea60ac3d98d9217061cc8123c71842bb.tar.xz
libgpod-58d08a77ea60ac3d98d9217061cc8123c71842bb.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
-rw-r--r--ChangeLog8
-rw-r--r--src/itdb_device.c163
-rw-r--r--tests/get-timezone.c53
3 files changed, 144 insertions, 80 deletions
diff --git a/ChangeLog b/ChangeLog
index d4a071b..30eb43e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-06-24 Christophe Fergeau <teuf@gnome.org>
+
+ * 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
+
2008-06-15 Christophe Fergeau <teuf@gnome.org>
* src/itdb_device.c: oops, forgot a ','
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;
}
/**
diff --git a/tests/get-timezone.c b/tests/get-timezone.c
index 1c612d2..ab39b1f 100644
--- a/tests/get-timezone.c
+++ b/tests/get-timezone.c
@@ -16,16 +16,12 @@
#include <errno.h>
#include <stdio.h>
#include <itdb.h>
+#include <itdb_device.h>
int main (int argc, char **argv)
{
char *mountpoint;
- char *device_dir;
- char *prefs_filename;
- FILE *f;
- int result;
- gint32 timezone;
- const int GMT_OFFSET = 0x19;
+ Itdb_Device *device;
if (argc >= 2) {
mountpoint = argv[1];
@@ -34,49 +30,10 @@ int main (int argc, char **argv)
return -1;
}
- device_dir = itdb_get_device_dir (mountpoint);
- if (device_dir == NULL) {
- g_print ("No iPod mounted at %s\n", mountpoint);
- return -1;
- }
- prefs_filename = itdb_get_path (device_dir, "Preferences");
- g_free (device_dir);
+ device = itdb_device_new ();
+ itdb_device_set_mountpoint (device, mountpoint);
- f = fopen (prefs_filename, "r");
- if (f == NULL) {
- g_print ("Couldn't open %s: %s\n", prefs_filename, g_strerror (errno));
- g_free (prefs_filename);
- return -1;
- }
-
- result = fseek (f, 0xB10, SEEK_SET);
- if (result != 0) {
- g_print ("Couldn't seek in %s: %s\n", prefs_filename,
- g_strerror (errno));
- fclose (f);
- g_free (prefs_filename);
- return -1;
- }
-
- result = fread (&timezone, sizeof (timezone), 1, f);
- if (result != 1) {
- g_print ("Couldn't read from %s: %s\n", prefs_filename,
- g_strerror (errno));
- fclose (f);
- g_free (prefs_filename);
- }
-
- fclose (f);
- g_free (prefs_filename);
-
- timezone = GINT32_FROM_LE (timezone);
- timezone -= GMT_OFFSET;
-
- g_print ("Timezone: UTC%+d", timezone >> 1);
- if (timezone & 1) {
- g_print (" DST");
- }
- g_print ("\n");
+ g_print ("Timezone: UTC%+d\n", device->timezone_shift/3600);
return 0;
}