Index: apps/recorder/bmp.c =================================================================== --- apps/recorder/bmp.c (revision 12103) +++ apps/recorder/bmp.c (working copy) @@ -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; } @@ -218,7 +211,6 @@ if (height > LCD_HEIGHT) { DEBUGF("read_bmp_file: Bitmap too high (%d pixels, max is %d)\n", height, LCD_HEIGHT); - close(fd); return -5; } @@ -276,7 +268,6 @@ if (totalsize > maxsize) { DEBUGF("read_bmp_file: Bitmap too large for buffer: " "%d bytes.\n", totalsize); - close(fd); return -6; } @@ -293,9 +284,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) { @@ -329,14 +320,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); @@ -354,7 +344,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; } @@ -544,8 +533,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 (revision 12103) +++ apps/recorder/bmp.h (working copy) @@ -29,8 +29,14 @@ * array. Returns 0 on success. * **********************************************/ +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/gwps-common.c =================================================================== --- apps/gui/gwps-common.c (revision 12103) +++ apps/gui/gwps-common.c (working copy) @@ -92,6 +92,59 @@ return -1; } #endif + + +/* 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, char* filename) +{ + int nextpos; + int n, len, i; + char* p; + unsigned char tar_header[136]; /* We only need the first 136 bytes */ + + n = read(fd, tar_header, 136); + + p = strrchr(filename,'/'); + i = strlen(tar_header); + + if ((p != NULL) && (strcmp(tar_header, p + 1)==0)) { + /* Filenames match, 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; + } + } else { + /* Filenames don't match, seek back to start of current header */ + lseek(fd, -136, SEEK_CUR); + return -1; + } +} + + /* * parse the given buffer for following static tags: @@ -107,7 +160,8 @@ * false otherwise */ bool wps_data_preload_tags(struct wps_data *data, char *buf, - const char *bmpdir, size_t bmpdirlen) + const char *bmpdir, size_t bmpdirlen, + int bmptar) { if(!data || !buf) return false; @@ -116,6 +170,7 @@ /* no bitmap-lcd == no bitmap loading */ (void)bmpdir; (void)bmpdirlen; + (void)bmptar; #endif buf = skip_utf8_bom(buf); @@ -124,7 +179,7 @@ if('%' != *buf) return false; buf++; - + c = *buf; switch (c) { @@ -318,11 +373,27 @@ return false; } - /* load the image */ data->img[n].bm.data = data->img_buf_ptr; - ret = read_bmp_file(imgname, &data->img[n].bm, - data->img_buf_free, - FORMAT_ANY|FORMAT_TRANSPARENT); + if (bmptar >= 0) { + /* load image from the .tar */ + int nextpos = process_tar_header(bmptar, imgname); + if (nextpos < 0) { + /* Error */ + return false; + } else { + ret = read_bmp_fd(bmptar, &data->img[n].bm, + data->img_buf_free, + FORMAT_ANY|FORMAT_TRANSPARENT); + if (nextpos > 0) { + lseek(bmptar,nextpos,SEEK_SET); + } + } + } else { + /* load the image from a .bmp file */ + ret = read_bmp_file(imgname, &data->img[n].bm, + data->img_buf_free, + FORMAT_ANY|FORMAT_TRANSPARENT); + } if (ret > 0) { Index: apps/gui/gwps-common.h =================================================================== --- apps/gui/gwps-common.h (revision 12103) +++ apps/gui/gwps-common.h (working copy) @@ -34,7 +34,8 @@ bool update(struct gui_wps *gwps); bool ffwd_rew(int button); bool wps_data_preload_tags(struct wps_data *data, char *buf, - const char *bmpdir, size_t bmpdirlen); + const char *bmpdir, size_t bmpdirlen, + int bmptar); void display_keylock_text(bool locked); #endif Index: apps/gui/gwps.c =================================================================== --- apps/gui/gwps.c (revision 12103) +++ apps/gui/gwps.c (working copy) @@ -712,6 +712,8 @@ bool isfile) { int fd; + int bmptar; + char bmptarname[MAX_PATH]; if(!wps_data || !buf) return false; @@ -757,6 +759,12 @@ { unsigned int start = 0; + /* Open the bitmap .tar file if it exists */ + strncpy(bmptarname,buf,bmpdirlen); + bmptarname[bmpdirlen]=0; + strcat(bmptarname,".tar"); + bmptar = open(bmptarname, O_RDONLY); + wps_reset(wps_data); #ifdef HAVE_LCD_BITMAP wps_data->img_buf_ptr = wps_data->img_buf; /* where in image buffer */ @@ -768,7 +776,7 @@ { if(!wps_data_preload_tags(wps_data, &wps_data->format_buffer[start], - buf, bmpdirlen)) + buf, bmpdirlen, bmptar)) { start += strlen(&wps_data->format_buffer[start]); @@ -785,6 +793,11 @@ gui_wps_format(wps_data); } + if (bmptar >= 0) + { + close(bmptar); + } + close(fd); wps_data->wps_loaded = true;