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; }