Mercurial > geeqie
changeset 45:7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
* format_raw.[ch]: Move camera specific code to manufacturer specific
format_*.c files. Change code so that file descripter version is now a
separate functions that wraps the standard parser by using mmap.
* format_canon.[ch]: Moved Canon specific raw support here, removed
file descriptor versions of parser. This Canon raw file parser written
by Daniel M. German.
* format_fuji.[ch]: Move Fuji specific raw support here, parser written
by Lars Ellenberg.
* exif.c: Update for change to format_raw_img_exif_offsets.
* filelist.c: Add cr2 extension to Canon raw format list.
* image-load.c: Fixes for changes to format_raw_img_exif_offset_fd so
that buffer is refilled using new offset of file descriptor.
* src/Makefile.am: Add format_canon.[ch], format_fuji.[ch] to build.
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
##### an offical release when making enhancements and translation updates. #####
author | gqview |
---|---|
date | Thu, 26 May 2005 18:10:52 +0000 |
parents | 458e396d3f35 |
children | 905f8fa583a3 |
files | ChangeLog THIS_CVS_IS_NOT_UP_TO_DATE src/Makefile.am src/exif.c src/filelist.c src/format_canon.c src/format_canon.h src/format_fuji.c src/format_fuji.h src/format_raw.c src/format_raw.h src/image-load.c |
diffstat | 12 files changed, 737 insertions(+), 47 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Wed May 18 23:52:16 2005 +0000 +++ b/ChangeLog Thu May 26 18:10:52 2005 +0000 @@ -1,3 +1,19 @@ +Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net> + + * format_raw.[ch]: Move camera specific code to manufacturer specific + format_*.c files. Change code so that file descripter version is now a + separate functions that wraps the standard parser by using mmap. + * format_canon.[ch]: Moved Canon specific raw support here, removed + file descriptor versions of parser. This Canon raw file parser written + by Daniel M. German. + * format_fuji.[ch]: Move Fuji specific raw support here, parser written + by Lars Ellenberg. + * exif.c: Update for change to format_raw_img_exif_offsets. + * filelist.c: Add cr2 extension to Canon raw format list. + * image-load.c: Fixes for changes to format_raw_img_exif_offset_fd so + that buffer is refilled using new offset of file descriptor. + * src/Makefile.am: Add format_canon.[ch], format_fuji.[ch] to build. + Wed May 18 19:36:49 2005 John Ellis <johne@verizon.net> * utilops.[ch] (file_util_rename_dir): New utility to rename a folder,
--- a/THIS_CVS_IS_NOT_UP_TO_DATE Wed May 18 23:52:16 2005 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -The CVS on sourceforge is far behind the latest version, -this CVS is not used for GQview development. - -There is no public CVS! - -(This CVS was set up as a test, and is here in the event GQview development CVS does go public)
--- a/src/Makefile.am Wed May 18 23:52:16 2005 +0000 +++ b/src/Makefile.am Thu May 26 18:10:52 2005 +0000 @@ -84,6 +84,10 @@ exif.h \ filelist.c \ filelist.h \ + format_canon.c \ + format_canon.h \ + format_fuji.c \ + format_fuji.h \ format_raw.c \ format_raw.h \ fullscreen.c \
--- a/src/exif.c Wed May 18 23:52:16 2005 +0000 +++ b/src/exif.c Thu May 26 18:10:52 2005 +0000 @@ -1088,7 +1088,7 @@ { guint32 offset = 0; - if (format_raw_img_exif_offsets(-1, f, size, NULL, &offset)) + if (format_raw_img_exif_offsets(f, size, NULL, &offset)) { res = parse_TIFF(exif, (unsigned char*)f + offset, size - offset); }
--- a/src/filelist.c Wed May 18 23:52:16 2005 +0000 +++ b/src/filelist.c Thu May 26 18:10:52 2005 +0000 @@ -211,7 +211,8 @@ /* These are the raw camera formats with embedded jpeg/exif. * (see format_raw.c) */ - filter_add_if_missing("raf", "Fujifilm raw camera format", ".raf", TRUE); + filter_add_if_missing("raf", "Fujifilm raw format", ".raf", TRUE); + filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", TRUE); } static GList *filter_to_list(const gchar *extensions)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_canon.c Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,473 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + * + * + * Code to add support for Canon CR2 and CRW files, version 0.2 + * + * Developed by Daniel M. German, dmgerman at uvic.ca + * + * you can find the sources for this patch at http://turingmachine.org/~dmg/libdcraw/gqview/ + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <glib.h> + +#include "intl.h" + +#include "format_canon.h" +#include "format_raw.h" + + +#if 0 + #define CANON_DEBUG +#endif + +#ifdef CANON_DEBUG +int canonEnableDebug = 0; +/* This should be really a stack, but I am too lazy to implement */ +#define DEBUG_ENABLE (canonEnableDebug = 0) +#define DEBUG_DISABLE (canonEnableDebug = 1) +/* It would be nice if these functions indented according to depth in the stack, but I am too lazy to implement */ + +#define DEBUG_ENTRY(a) (canonEnableDebug || fprintf(stderr, "Entering function: %s [%s:%d]\n", a, __FILE__, __LINE__)) +#define DEBUG_EXIT(a) (canonEnableDebug || fprintf(stderr, "Exiting function: %s [%s:%d]\n", a, __FILE__, __LINE__)) +#define DEBUG_1(a) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n", __FILE__, __LINE__)) +#define DEBUG_2(a,b) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, __FILE__, __LINE__)) +#define DEBUG_3(a,b,c) (canonEnableDebug || fprintf(stderr, a " [%s:%d]\n",b, c, __FILE__, __LINE__)) + +#else +#define DEBUG_ENABLE +#define DEBUG_DISABLE +#define DEBUG_ENTRY(a) +#define DEBUG_EXIT(a) + +#define DEBUG_1(a) +#define DEBUG_2(a,b) +#define DEBUG_3(a,b,c) +#endif + + +/* canon_read_int4 + + +The problem with gqview is that sometimes the data is to be read from +a file, and sometimes it is in memory. This function tries to isolate +the rest of the code from having to deal with both cases + +This function reads a 4 byte unsigned integer, and fixes its endianism. + +If fd >= 0 then the value is read from the corresponding file descriptor + + in that case, if offset is > 0, then the value is read from that offset + + otherwise it is read from the current file pointer + +if fd < 0 then the value is read from the memory pointed by data + offset + + +offset is a pointer to the actual offset of the file. + +sizeInt can be 2 or 4 (it is the number of bytes to read) + +RETURNS true is no error, false if it can't read the value + + +*/ +static int canon_read_int(unsigned int *offset, const void *data, int sizeInt, unsigned int *value ) +{ + DEBUG_DISABLE; + + DEBUG_ENTRY("canon_read_int"); + /* Verify values before we do anything */ + if (sizeInt != 2 && sizeInt != 4) return FALSE; + if (offset == NULL) return FALSE; + if (*offset <= 0) return FALSE; + if (data == NULL) return FALSE; + if (value == NULL) return FALSE; + + if (sizeInt == 4) { + *value = GUINT32_FROM_LE(*(guint32*)(data + *offset)); + *offset +=4; + DEBUG_3("Read 4 bytes %d %x", *value, *value); + } else { + *value = GUINT16_FROM_LE(*(guint32*)(data + *offset)); + *offset +=2; + DEBUG_3("Read 2 bytes %d %x", *value, *value); + } + + DEBUG_EXIT("canon_read_int"); + + DEBUG_ENABLE; + return TRUE; +} + +#define CANON_HEADER_SIZE 26 + +/* + + The CR2 format is really a TIFF format. It is nicely documented in the TIFF V 6.0 document available from adobe. + + The CR2 file contains two thumbnails, one tiny and one decent sized. The record Id of the latter is 0x0111. + + The photo info is also available, in EXIF, and it looks like I don't need to do anything! Yeah! + +*/ + +static int canon_cr2_process_directory(void *data, int offsetIFD, guint *jpegLocation, guint *exifLocation) +{ + unsigned int offset; + int returnValue = FALSE; + + DEBUG_ENTRY("canon_cr2_process_directory"); + + /* The directory is a link list, after an array of records, the next 4 byptes point to the offset of the next directory. + + All offsets are absolution within the file (in CRWs the offsets are relative ). + + */ + + while (offsetIFD != 0 && offsetIFD != 0xFFFF) { + int countEntries=0; + int i; + /* Read directory, we start by reading number of entries in the directory */ + + offset = offsetIFD; + if (!canon_read_int(&offset, data, 2, &countEntries)) { + goto return_only; + } + DEBUG_2("Number of entries: %d\n", countEntries); + + for (i=0;i<countEntries;i++) { + /* read each entry */ + + int recordId; +#if 0 + int format; + int size; +#endif + + /* read record type */ + if (!canon_read_int(&offset, data, 2, &recordId)) { + goto return_only; + } + + /* Did we find the JPEG */ + if (recordId == 0x0111) { + DEBUG_1("This is the record to find**********************\n"); + offset +=6; + if (!canon_read_int(&offset, data, 4, jpegLocation)) { + goto return_only; + } + DEBUG_3("JPEG Location %d 0x%x\n", *jpegLocation, *jpegLocation); + /* We don't want to keep reading, because there is another + 0x0111 record at the end that contains the raw data */ + returnValue = TRUE; + goto return_only; + } else { + /* advance pointer by skipping rest of record */ + offset += 10; + } + } + /* The next 4 bytes are the offset of next directory, if zero we are done + + */ + if (!canon_read_int(&offset, data, 4, &offsetIFD)) { + goto return_only; + } + DEBUG_3("Value of NEXT offsetIFD: %d 0x%x\n", offsetIFD, offsetIFD); + } + + returnValue = TRUE; + DEBUG_1("Going to return true"); + + return_only: + DEBUG_EXIT("canon_cr2_process_directory"); + + return TRUE; + + +} + + +static int format_raw_test_canon_cr2(void *data, const guint len, + guint *image_offset, guint *exif_offset) +{ +#if 0 + char signature[4]; + unsigned int offset = 4; +#endif + int offsetIFD; + int returnValue = FALSE; + void *jpgInDataOffset; + + DEBUG_ENTRY("format_raw_test_canon_cr2"); + + /* Verify signature */ + if (memcmp(data, "\x49\x49\x2a\00", 4) != 0) { + DEBUG_1("This is not a CR2"); + goto return_only; + } + + /* Get address of first directory */ + offsetIFD = GUINT32_FROM_LE(*(guint32*)(data + 4)); + + + DEBUG_2("Value of offsetIFD: %d\n", offsetIFD); + + returnValue = canon_cr2_process_directory(data, offsetIFD, image_offset, exif_offset); + + if (returnValue) { + jpgInDataOffset = data + *image_offset; + + /* Make sure we really got a JPEG */ + + if (memcmp(jpgInDataOffset, "\xff\xd8",2) != 0) { + /* It is not at the JPEG! */ + DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset); + returnValue = FALSE; + } + } + +return_only: + DEBUG_EXIT("format_raw_test_canon_cr2"); + + return returnValue; +} + + +gint format_raw_test_canon(const void *data, const guint len, + guint *image_offset, guint *exif_offset) +{ + + + /* There are at least 2 types of Canon raw files. CRW and CR2 + + CRW files have a proprietary format. + + HEADER + Heap + RAW data + JPEG data + PHoto data + + HEADER_LENGTH 32 bytes + int2 byteOrder; Always II (MM Motorola ---big endian, II Intel --little endian) + int4 length; Should be 26 + char identifier[8];type HEAP, subtype heap CCDR + int2 version; + int2 subversion; + char unused[14]; + */ + + int returnValue = FALSE; + int heapHeaderOffset = 0; + int heapRecordsCount = 0; +#if 0 + guint32 rawInt4; + guint16 rawInt2; +#endif + int i; + unsigned int currentOffset; + /* File has to be little endian, first two bytes II */ + + if (len < 100) + return FALSE; + + if (format_raw_test_canon_cr2((void *)data, len, image_offset, exif_offset)) { + return TRUE; + } + + if (memcmp("II", data, 2) != 0) { + return FALSE; + } + /* NO DEBUG BEFORE THIS POINT, we want to debug only Canon */ + + DEBUG_ENTRY("format_raw_test_canon"); + + DEBUG_2("Length of buffer read %u", len); + + DEBUG_2("CRW header length Data %d", GUINT32_FROM_LE(*(guint32*)(data + 2))); + + /* the length has to be CANON_HEADER_SIZE */ + if (GUINT32_FROM_LE(*(guint32*)(data + 2)) != CANON_HEADER_SIZE) { + DEBUG_1("It is not the right size"); + goto return_only; + } + + if (!memcmp("HEAPCCDR", data+6, 8) == 0) { + DEBUG_1("This file is not a Canon CRW raw photo"); + goto return_only; + + } + + /* Ok, so now we know that this is a CRW file */ + + /* The heap is a strange data structure. It is recursive, so a record + can contain a heap itself. That is indeed the case for the photo information + reecord. Luckily the first heap contains the jpeg, so we don't need to do + any recursive processing. + + Its "header" is a the end. The header is a sequence of records, + and the data of each record is at the beginning of the heap + + +-----------------+ + | data raw | + +-----------------+ + | data jpeg | + +-----------------+ + | data photo info | + +-----------------+ + |header of heap | + | # records | it should be 3 + | raw info | + | jpeg info | + | photo info | + +-----------------+ + + The header contains + number of records: 2 bytes + for each record (10 bytes long) + type: 2 bytes + length: 4 bytes + offset: 4 bytes + + In some records the length and offset are actually data, + but none for the ones in the first heap. + + the offset is with respect to the beginning of the heap, not the + beginning of the file. That allows heaps to be "movable" + + For the purpose of finding the JPEG, all we need is to scan the fist heap, + which contains the following record types: + + 0x2005 Record RAW data + 0x2007 Record JPEG data + 0x300a Record with photo info + + */ + + + if (len < 0x10000) { + DEBUG_2("We have a problem, the length is too small %d ", len); + goto return_only; + } + currentOffset = len-4; + + + /* The last 4 bytes have the offset of the header of the heap */ + if (!canon_read_int(¤tOffset, data, 4, &heapHeaderOffset)) + goto return_only; + + /* The heapoffset has to be adjusted to the actual file size, the header is CANON_HEADER_SIZE bytes long */ + heapHeaderOffset += CANON_HEADER_SIZE; + DEBUG_2("heap header Offset %d ", heapHeaderOffset); + + /* Just check, it does not hurt, we don't want to crash */ + if (heapHeaderOffset > len) + goto return_only; + + currentOffset = heapHeaderOffset; + /* Let us read the number of records in the heap */ + if (!canon_read_int(¤tOffset, data, 2, &heapRecordsCount)) + goto return_only; + + DEBUG_2("heap record count %d ", heapRecordsCount); + + if (heapRecordsCount != 3) { + /* In all the cameras I have seen, this is always 3 + if not, something is wrong, so just quit */ + goto return_only; + } + + for (i=0;i<3;i++) { + int recordType; + int recordOffset; + int recordLength; + const void *jpgInDataOffset; + /* Read each record, to find jpg, it should be second */ + + if (!canon_read_int(¤tOffset, data, 2, &recordType)) + goto return_only; + + DEBUG_2("record type 0x%x ", recordType); + + if (recordType != 0x2007) { + /* Go to the next record, don't waste time, + but first, eat 8 bytes from header */ + currentOffset += 8; + continue; /* Nah, wrong record, go to next */ + } + /* Bingo, we are at the JPEG record */ + + /* Read length */ + if (!canon_read_int(¤tOffset, data, 4, &recordLength)) + goto return_only; + + DEBUG_2("record length %d ", recordLength); + + /* Read offset */ + + if (!canon_read_int(¤tOffset, data, 4, &recordOffset)) + goto return_only; + + DEBUG_2("record offset 0x%d ", recordOffset); + + /* Great, we now know where the JPEG is! + it is CANON_HEADER_SIZE (size of CRW header) + recordOffset + */ + + *image_offset = CANON_HEADER_SIZE + recordOffset; + DEBUG_2("image offset %d ", *image_offset); + + /* keep checking for potential errors */ + if (*image_offset > len) { + goto return_only; + } + /* Get the JPEG is */ + + jpgInDataOffset = data + *image_offset; + + if (memcmp(jpgInDataOffset, "\xff\xd8\xff\xdb",4) != 0) { + /* It is not at the JPEG! */ + DEBUG_2("THis is not a jpeg after all: there are the first 4 bytes 0x%x ", (int)jpgInDataOffset); + goto return_only; + } + returnValue = TRUE; + goto return_only; + } + /* undo whatever we need in case of an error*/ + DEBUG_1("We scan all records, but nothing was found!!!!!!!!!!!!!!!!!!"); + + + /* At this point we are returning */ +return_only: + if (returnValue) { + DEBUG_1("****We got an embedded JPEG for a canon CRW"); + + } + + DEBUG_EXIT("format_raw_test_canon"); + return returnValue; + +#undef DEBUG_2 +#undef DEBUG +#undef DEBUG_ENTRY +#undef DEBUG_EXIT + +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_canon.h Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,31 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + * + * + * Code to add support for Canon CR2 and CRW files, version 0.2 + * + * Developed by Daniel M. German, dmgerman at uvic.ca + * + * you can find the sources for this patch at http://turingmachine.org/~dmg/libdcraw/gqview/ + * + */ + +#ifndef __FORMAT_RAW_CANON_H +#define __FORMAT_RAW_CANON_H + + +gint format_raw_test_canon(const void *data, const guint len, + guint *image_offset, guint *exif_offset); + + +#define FORMAT_RAW_CANON { "II", 2, "Canon crw format", format_raw_test_canon }, \ + { "\x49\x49\x2a\00", 4, "Canon cr2 format", format_raw_test_canon } + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_fuji.c Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,59 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * Authors: + * Original version 2005 Lars Ellenberg, base on dcraw by David coffin. + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <glib.h> + +#include "intl.h" + +#include "format_fuji.h" +#include "format_raw.h" + + +gint format_raw_test_fuji(const void *data, const guint len, + guint *image_offset, guint *exif_offset) +{ + guint io; + guint eo; + + if (len < 128 || + memcmp(data, "FUJIFILM", 8) != 0) + { + return FALSE; + } + + io = GUINT32_FROM_BE(*(guint32*)(data + 84)); + eo = *image_offset + 12; + + /* verify jpeg marker */ + if (memcmp(data + io, "\xff\xd8\xff\xe1", 4) != 0) + { + return FALSE; + } + + if (image_offset) *image_offset = io; + if (exif_offset) *exif_offset = eo; + + printf("raw Fuji format file\n"); + + return TRUE; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/format_fuji.h Thu May 26 18:10:52 2005 +0000 @@ -0,0 +1,25 @@ +/* + * GQView + * (C) 2005 John Ellis + * + * Authors: + * Original version 2005 Lars Ellenberg, base on dcraw by David coffin. + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + */ + +#ifndef __FORMAT_RAW_FUJI_H +#define __FORMAT_RAW_FUJI_H + + +gint format_raw_test_fuji(const void *data, const guint len, + guint *image_offset, guint *exif_offset); + + +#define FORMAT_RAW_FUJI { "FUJIFILM", 8, "Fuji raw format", format_raw_test_fuji } + + +#endif +
--- a/src/format_raw.c Wed May 18 23:52:16 2005 +0000 +++ b/src/format_raw.c Thu May 26 18:10:52 2005 +0000 @@ -14,9 +14,13 @@ # include "config.h" #endif + #include <stdio.h> #include <string.h> #include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> #include <glib.h> @@ -24,54 +28,59 @@ #include "format_raw.h" -static gint format_raw_test_canon(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) -{ - return FALSE; -} +#include "format_canon.h" +#include "format_fuji.h" + + +typedef struct _FormatEntry FormatEntry; +struct _FormatEntry { + const void *header_pattern; + const guint header_length; + const gchar *description; + FormatRawParseFunc func_parse; +}; + -static gint format_raw_test_fuji(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) +static FormatEntry format_list[] = { + FORMAT_RAW_CANON, + FORMAT_RAW_FUJI, + { NULL, 0, NULL, NULL } +}; + + +static FormatEntry *format_raw_find(const void *data, const guint len) { - if (len < 128 || - memcmp(data, "FUJIFILM", 8) != 0) + gint n; + + n = 0; + while (format_list[n].header_pattern) { - return FALSE; + if (format_list[n].header_length <= len && + memcmp(data, format_list[n].header_pattern, format_list[n].header_length) == 0) + { + return &format_list[n]; + } + n++; } - *image_offset = GUINT32_FROM_BE(*(guint32*)(data + 84)); - *exif_offset = *image_offset + 12; -printf("found a raw fuji file!\n"); - return TRUE; + return NULL; } -static gint format_raw_test_nikon(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) +static gint format_raw_parse(FormatEntry *entry, + const void *data, const guint len, + guint *image_offset, guint *exif_offset) { - return FALSE; -} - - -gint format_raw_img_exif_offsets(int fd, const void *data, const guint len, - guint *image_offset, guint *exif_offset) -{ - guint32 io = 0; - guint32 eo = 0; + gint io = 0; + gint eo = 0; gint found; - if (fd < 0 && !data) return FALSE; -#if 0 - if (len < 512) return FALSE; -#endif + if (!entry || !entry->func_parse) return FALSE; - found = format_raw_test_canon(fd, data, len, &io, &eo) || - format_raw_test_fuji (fd, data, len, &io, &eo) || - format_raw_test_nikon(fd, data, len, &io, &eo); + found = entry->func_parse(data, len, &io, &eo); if (!found || io >= len - 4 || - eo >= len || - memcmp(data + io, "\xff\xd8\xff\xe1", 4) != 0) /* jpeg marker */ + eo >= len) { return FALSE; } @@ -82,5 +91,69 @@ return TRUE; } +gint format_raw_img_exif_offsets(const void *data, const guint len, + guint *image_offset, guint *exif_offset) +{ + FormatEntry *entry; + + if (!data || len < 1) return FALSE; + + entry = format_raw_find(data, len); + + if (!entry || !entry->func_parse) return FALSE; + + return format_raw_parse(entry, data, len, image_offset, exif_offset); +} +gint format_raw_img_exif_offsets_fd(int fd, const void *header_data, const guint header_len, + guint *image_offset, guint *exif_offset) +{ + FormatEntry *entry; + void *map_data = NULL; + size_t map_len = 0; + struct stat st; + gint success; + + if (!header_data || fd < 0) return FALSE; + + entry = format_raw_find(header_data, header_len); + + if (!entry || !entry->func_parse) return FALSE; + + if (fstat(fd, &st) == -1) + { + printf("Failed to stat file %d\n", fd); + return FALSE; + } + map_len = st.st_size; + map_data = mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0); + if (map_data == MAP_FAILED) + { + printf("Failed to mmap of file %d\n", fd); + return FALSE; + } + + success = format_raw_parse(entry, map_data, map_len, image_offset, exif_offset); + + if (munmap(map_data, map_len) == -1) + { + printf("Failed to unmap file %d\n", fd); + } + + if (success && image_offset) + { + if (lseek(fd, *image_offset, SEEK_SET) != *image_offset) + { + printf("Failed to seek to embedded image\n"); + + *image_offset = 0; + if (*exif_offset) *exif_offset = 0; + success = FALSE; + } + } + + return success; +} + +
--- a/src/format_raw.h Wed May 18 23:52:16 2005 +0000 +++ b/src/format_raw.h Thu May 26 18:10:52 2005 +0000 @@ -13,8 +13,16 @@ #ifndef __FORMAT_RAW_H #define __FORMAT_RAW_H -gint format_raw_img_exif_offsets(int fd, const void *data, const guint len, + +typedef gint (* FormatRawParseFunc)(const void *data, const guint len, + guint *image_offset, guint *exif_offset); + + +gint format_raw_img_exif_offsets(const void *data, const guint len, guint *image_offset, guint *exif_offset); +gint format_raw_img_exif_offsets_fd(int fd, const void *header_data, const guint header_len, + guint *image_offset, guint *exif_offset); + #endif
--- a/src/image-load.c Wed May 18 23:52:16 2005 +0000 +++ b/src/image-load.c Thu May 26 18:10:52 2005 +0000 @@ -217,17 +217,23 @@ b = read(il->load_fd, &buf, sizeof(buf)); + if (b > 1 && + format_raw_img_exif_offsets_fd(il->load_fd, buf, b, &offset, NULL)) + { + if (debug) printf("Raw file %s contains embedded image\n", il->path); + + b = read(il->load_fd, &buf, sizeof(buf)); + } + if (b < 1) { image_loader_stop(il); return FALSE; } - format_raw_img_exif_offsets(il->load_fd, buf, b, &offset, NULL); - - if (gdk_pixbuf_loader_write(il->loader, buf + offset, b - offset, NULL)) + if (gdk_pixbuf_loader_write(il->loader, buf, b, NULL)) { - il->bytes_read += b; + il->bytes_read += b + offset; if (b < sizeof(buf)) {