- 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
+ /* walk the directory entries looking for type jpeg (tag 0x2007),
+ * for reference, other tags are 0x2005 for raw and 0x300a for photo info:
+ */
+ for (i = 0; i < count ; i++)
+ {
+ guint entry_offset;
+ guint record_type;
+ guint record_offset;
+ guint record_length;
+
+ entry_offset = offset + i * CRW_DIR_ENTRY_SIZE;
+
+ /* entry is 10 bytes (in order):
+ * 2 for type
+ * 4 for length of data
+ * 4 for offset into data segment of this block
+ */
+ record_type = exif_byte_get_int16(data + entry_offset, CRW_BYTE_ORDER);
+ record_length = exif_byte_get_int32(data + entry_offset + 2, CRW_BYTE_ORDER);
+ record_offset = exif_byte_get_int32(data + entry_offset + 6, CRW_BYTE_ORDER);
+
+ /* tag we want for jpeg data */
+ if (record_type == 0x2007)
+ {
+ guint jpeg_offset;
+
+ jpeg_offset = block_offset + record_offset;
+ if (len < jpeg_offset + record_length ||
+ record_length < 4 ||
+ memcmp(data + jpeg_offset, "\xff\xd8\xff\xdb", 4) != 0)
+ {
+ return FALSE;
+ }
+
+ /* we now know offset and verified jpeg */
+ *image_offset = jpeg_offset;
+ return TRUE;
+ }
+ }