Index: apps/recorder/bmp.c
===================================================================
--- apps/recorder/bmp.c	(révision 13363)
+++ apps/recorder/bmp.c	(copie de travail)
@@ -138,21 +138,23 @@
 }
 
 /******************************************************************************
- * read_bmp_file()
+ * read_bmp_file_fd()
  *
- * Reads a BMP file and puts the data in rockbox format in *bitmap.
+ * Reads a BMP file starting at the current position in an open file and puts 
+ * the data in rockbox format in *bitmap.
  *
  *****************************************************************************/
-int read_bmp_file(char* filename,
-                  struct bitmap *bm,
-                  int maxsize,
-                  int format)
+int read_bmp_fd(int fd,
+                struct bitmap *bm,
+                int maxsize,
+                int format)
 {
     struct bmp_header bmph;
     int width, height, padded_width;
     int dst_height, dst_width;
-    int fd, row, col, ret;
+    int row, col, ret;
     int depth, numcolors, compression, totalsize;
+    int currpos;
 
     unsigned char *bitmap = bm->data;
     uint32_t bmpbuf[LCD_WIDTH]; /* Buffer for one line */
@@ -185,32 +187,23 @@
     (void)format;
 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
 
-    fd = open(filename, O_RDONLY);
-
-    /* Exit if file opening failed */
-    if (fd < 0) {
-        DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
-        return fd * 10 - 1;
-    }
-
     /* read fileheader */
     ret = read(fd, &bmph, sizeof(struct bmp_header));
     if (ret < 0) {
-        close(fd);
         return ret * 10 - 2;
     }
 
     if (ret != sizeof(struct bmp_header)) {
         DEBUGF("read_bmp_file: can't read BMP header.");
-        close(fd);
         return -3;
     }
 
+    currpos = sizeof(struct bmp_header);
+
     width = readlong(&bmph.width);
     if (width > LCD_WIDTH) {
         DEBUGF("read_bmp_file: Bitmap too wide (%d pixels, max is %d)\n",
                         width, LCD_WIDTH);
-        close(fd);
         return -4;
     }
 
@@ -269,7 +262,6 @@
     if (totalsize > maxsize) {
         DEBUGF("read_bmp_file: Bitmap too large for buffer: "
                "%d bytes.\n", totalsize);
-        close(fd);
         return -6;
     }
 
@@ -286,9 +278,9 @@
             != numcolors * (int)sizeof(uint32_t))
         {
             DEBUGF("read_bmp_file: Can't read color palette\n");
-            close(fd);
             return -7;
         }
+        currpos += numcolors * sizeof(uint32_t);
     }
 
     switch (depth) {
@@ -322,14 +314,13 @@
         if (compression != 0) { /* not BI_RGB */
             DEBUGF("read_bmp_file: Unsupported compression (type %d)\n",
                    compression);
-            close(fd);
             return -8;
         }
         break;
     }
 
     /* Search to the beginning of the image data */
-    lseek(fd, (off_t)readlong(&bmph.off_bits), SEEK_SET);
+    lseek(fd, (off_t)readlong(&bmph.off_bits) - currpos, SEEK_CUR);
 
     memset(bitmap, 0, totalsize);
 
@@ -347,7 +338,6 @@
         if (ret != padded_width) {
             DEBUGF("read_bmp_file: error reading image, read returned: %d "
                    "expected: %d\n", ret, padded_width);
-            close(fd);
             return -9;
         }
 
@@ -537,8 +527,35 @@
         }
     }
 
-    close(fd);
-
     DEBUGF("totalsize: %d\n", totalsize);
     return totalsize; /* return the used buffer size. */
 }
+
+
+/******************************************************************************
+ * read_bmp_file()
+ *
+ * Reads a BMP file and puts the data in rockbox format in *bitmap.
+ *
+ *****************************************************************************/
+int read_bmp_file(char* filename,
+                  struct bitmap *bm,
+                  int maxsize,
+                  int format)
+{
+    int fd, res;
+
+    fd = open(filename, O_RDONLY);
+
+    /* Exit if file opening failed */
+    if (fd < 0) {
+        DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
+        return fd * 10 - 1;
+    }
+
+    res = read_bmp_fd(fd, bm, maxsize, format);
+
+    close(fd);
+
+    return res;
+}
Index: apps/recorder/bmp.h
===================================================================
--- apps/recorder/bmp.h	(révision 13363)
+++ apps/recorder/bmp.h	(copie de travail)
@@ -30,8 +30,14 @@
  * Returns < 0 for error, or number of bytes used from the bitmap buffer
  *
  **********************************************/
+int read_bmp_fd(int fd,
+                struct bitmap *bm,
+                int maxsize,
+                int format);
+
 int read_bmp_file(char* filename,
                   struct bitmap *bm,
                   int maxsize,
                   int format);
+
 #endif
Index: apps/gui/wps_parser.c
===================================================================
--- apps/gui/wps_parser.c	(révision 13363)
+++ apps/gui/wps_parser.c	(copie de travail)
@@ -313,37 +313,6 @@
     return skip_end_of_line(wps_bufptr);
 }
 
-static bool load_bitmap(struct wps_data *wps_data,
-                        char* filename,
-                        struct bitmap *bm)
-{
-    int format;
-#ifdef HAVE_REMOTE_LCD
-    if (wps_data->remote_wps)
-        format = FORMAT_ANY|FORMAT_REMOTE;
-    else
-#endif
-        format = FORMAT_ANY|FORMAT_TRANSPARENT;
-
-    int ret = read_bmp_file(filename, bm,
-                            wps_data->img_buf_free,
-                            format);
-
-    if (ret > 0)
-    {
-#if LCD_DEPTH == 16
-        if (ret % 2) ret++;
-        /* Always consume an even number of bytes */
-#endif
-        wps_data->img_buf_ptr += ret;
-        wps_data->img_buf_free -= ret;
-
-        return true;
-    }
-    else
-        return false;
-}
-
 static int get_image_id(int c)
 {
     if(c >= 'a' && c <= 'z')
@@ -354,9 +323,13 @@
         return -1;
 }
 
+/* Read a bitmap filename in the WPS at start and return the full path to that
+   bitmap in buf by appending it to bmpdir.
+   bmpdir can be NULL to only get the filename in buf. */
 static char *get_image_filename(const char *start, const char* bmpdir,
                                 char *buf, int buf_size)
 {
+    int bmpdirlen = 0;
     const char *end = strchr(start, '|');
 
     if ( !end || (end - start) >= (buf_size - ROCKBOX_DIR_LEN - 2) )
@@ -365,12 +338,15 @@
         return NULL;
     }
 
-    int bmpdirlen = strlen(bmpdir);
+    if (bmpdir)
+    {
+        bmpdirlen = strlen(bmpdir);
+        strcpy(buf, bmpdir);
+        buf[bmpdirlen++] = '/';
+    }
 
-    strcpy(buf, bmpdir);
-    buf[bmpdirlen] = '/';
-    memcpy( &buf[bmpdirlen + 1], start, end - start);
-    buf[bmpdirlen + 1 + end - start] = 0;
+    memcpy( &buf[bmpdirlen], start, end - start);
+    buf[bmpdirlen + end - start] = 0;
 
     return buf;
 }
@@ -903,7 +879,6 @@
 
 #ifdef HAVE_LCD_BITMAP
 
-
 static void clear_bmp_names(void)
 {
     int n;
@@ -917,34 +892,158 @@
 #endif
 }
 
-static void load_wps_bitmaps(struct wps_data *wps_data, char *bmpdir)
+static bool load_bitmap(struct wps_data *wps_data,
+                        char* filename, int fd,
+                        struct bitmap *bm)
 {
+    int format, ret;
+#ifdef HAVE_REMOTE_LCD
+    if (wps_data->remote_wps)
+        format = FORMAT_ANY|FORMAT_REMOTE;
+    else
+#endif
+        format = FORMAT_ANY|FORMAT_TRANSPARENT;
+
+    bm->data = wps_data->img_buf_ptr;
+    if (filename)
+    {
+        ret = read_bmp_file(filename, bm, wps_data->img_buf_free, format);
+    }
+    else if (fd >= 0)
+    {
+        ret = read_bmp_fd(fd, bm, wps_data->img_buf_free, format);
+    }
+    else
+        return false;
+
+    if (ret > 0)
+    {
+#if LCD_DEPTH == 16
+        if (ret % 2) ret++;
+        /* Always consume an even number of bytes */
+#endif
+        wps_data->img_buf_ptr += ret;
+        wps_data->img_buf_free -= ret;
+
+        return true;
+    }
+    else
+        return false;
+}
+
+/* Process a tar file header.  Confirm that the filename in header 
+   is the same as the parameter, and return the location in the tar
+   file of the next file (or 0 if no more files).  Returns -1 if the 
+   filenames don't match.
+
+   A tar file consists of one or more files, each preceeded by
+   a 512-byte tar header block.  The files themselves are padded
+   to a multiple of 512 bytes.
+*/
+int process_tar_header(int fd, unsigned char *buf, int bufsize)
+{
+    int nextpos;
+    int n, len, i;
+    unsigned char *tar_header = buf;
+
+    /* We only need the first 136 bytes */
+    if (bufsize < 136)
+        return -1;
+    n = read(fd, tar_header, 136);
+    i = strlen(tar_header);
+
+    /* Parse the filesize field */
+    len = 0;
+    for (i = 124 ; i < 124 + 11 ; i++) {
+        len = (8 * len) + tar_header[i] - '0';
+    }
+    /* Round length up to next multiple of 512 */
+    len = (len + 511) & (~511);
+
+    /* Skip rest of header */
+    nextpos = lseek(fd, 512 - 136, SEEK_CUR);
+
+    /* Calculate start of next file */
+    nextpos += len;
+
+    if (nextpos >= filesize(fd)) {
+        return 0;
+    } else {
+        return nextpos;
+    }
+}
+
+static void load_wps_bitmaps(struct wps_data *wps_data,
+                             char *bmpdir, int bmptar)
+{
     char img_path[MAX_PATH];
+    int n;
+    int nextpos = 0;
 
-    int n;
-    for (n = 0; n < MAX_IMAGES; n++)
+    if (bmptar >= 0)
     {
-        if (bmp_names[n])
+        unsigned char tar_header[136];
+
+        do
         {
-            get_image_filename(bmp_names[n], bmpdir,
-                               img_path, sizeof(img_path));
+            /* load image name from the .tar */
+            nextpos = process_tar_header(bmptar, tar_header,
+                                         sizeof(tar_header));
 
-            /* load the image */
-            wps_data->img[n].bm.data = wps_data->img_buf_ptr;
-            if (load_bitmap(wps_data, img_path, &wps_data->img[n].bm))
+            /* look for the image's index in the WPS */
+            for (n = 0; n < MAX_IMAGES; n++)
             {
-                wps_data->img[n].loaded = true;
+                if (bmp_names[n])
+                {
+                    get_image_filename(bmp_names[n], NULL,
+                                       img_path, sizeof(img_path));
+
+                    if ( !wps_data->img[n].loaded
+                         && strcmp(tar_header, img_path) == 0 )
+                    {
+                        DEBUGF("tar: %s -> %d", tar_header, n);
+
+                        /* we found the index for the picture : load it */
+                        if (load_bitmap(wps_data, NULL, bmptar,
+                                        &wps_data->img[n].bm))
+                        {
+                            wps_data->img[n].loaded = true;
+                        }
+                    }
+                }
             }
+
+            if (nextpos > 0)
+            {
+                lseek(bmptar, nextpos, SEEK_SET);
+            }
         }
+        while (nextpos > 0);
     }
+    else
+    {
+        for (n = 0; n < MAX_IMAGES; n++)
+        {
+            if (bmp_names[n])
+            {
+                get_image_filename(bmp_names[n], bmpdir,
+                                   img_path, sizeof(img_path));
 
+                /* load the image */
+                if (load_bitmap(wps_data, img_path, 0, &wps_data->img[n].bm))
+                {
+                    wps_data->img[n].loaded = true;
+                }
+            }
+        }
+    }
+
     if (pb_bmp_name)
     {
         get_image_filename(pb_bmp_name, bmpdir, img_path, sizeof(img_path));
 
         /* load the image */
-        wps_data->progressbar.bm.data = wps_data->img_buf_ptr;
-        if (load_bitmap(wps_data, img_path, &wps_data->progressbar.bm)
+        if (load_bitmap(wps_data, img_path, 0, &wps_data->progressbar.bm)
             && wps_data->progressbar.bm.width <= LCD_WIDTH)
         {
             wps_data->progressbar.have_bitmap_pb = true;
@@ -955,7 +1054,7 @@
     if (backdrop_bmp_name)
     {
         get_image_filename(backdrop_bmp_name, bmpdir,
-                            img_path, sizeof(img_path));
+                           img_path, sizeof(img_path));
 #ifdef HAVE_REMOTE_LCD
         if (wps_data->remote_wps)
 #if LCD_REMOTE_DEPTH > 1
@@ -1072,8 +1171,17 @@
         strncpy(bmpdir, buf, dot - buf);
         bmpdir[bmpdirlen] = 0;
 
+        /* Open the bitmap .tar file if it exists */
+        char bmptarname[MAX_PATH];
+        strcpy(bmptarname, bmpdir);
+        strcat(bmptarname, ".tar");
+        int bmptar = open(bmptarname, O_RDONLY);
+
         /* load the bitmaps that were found by the parsing */
-        load_wps_bitmaps(wps_data, bmpdir);
+        load_wps_bitmaps(wps_data, bmpdir, bmptar);
+
+        if (bmptar >= 0)
+            close(bmptar);
 #endif
         return true;
     }
