1 /* 2 * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "exif_parser.h" 8 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <BufferIO.h> 13 #include <Entry.h> 14 #include <File.h> 15 #include <Message.h> 16 17 #include "ReadHelper.h" 18 #include "TIFF.h" 19 20 21 static status_t 22 process_exif(uint8* data, uint32 length) 23 { 24 if (memcmp(data + 2, "Exif", 4)) 25 return B_BAD_TYPE; 26 27 BMemoryIO source(data + 8, length - 8); 28 BMessage exif; 29 status_t status = convert_exif_to_message(source, exif); 30 31 exif.PrintToStream(); 32 // even if it failed, some data might end up in the message 33 34 return status; 35 } 36 37 38 static status_t 39 process_jpeg(BPositionIO& stream) 40 { 41 enum { 42 START_OF_IMAGE_MARKER = 0xd8, 43 EXIF_MARKER = 0xe1 44 }; 45 46 uint8 header[2]; 47 if (stream.Read(&header, 2) != 2) 48 return B_IO_ERROR; 49 if (header[0] != 0xff || header[1] != START_OF_IMAGE_MARKER) 50 return B_BAD_TYPE; 51 52 while (true) { 53 // read marker 54 uint8 marker; 55 for (int32 i = 0; i < 7; i++) { 56 if (stream.Read(&marker, 1) != 1) 57 return B_BAD_TYPE; 58 59 if (marker != 0xff) 60 break; 61 } 62 63 if (marker == 0xff) 64 return B_BAD_TYPE; 65 66 // get length of section 67 68 uint16 length; 69 if (stream.Read(&length, 2) != 2) 70 return B_BAD_TYPE; 71 72 swap_data(B_UINT16_TYPE, &length, 2, B_SWAP_BENDIAN_TO_HOST); 73 74 if (marker == EXIF_MARKER) { 75 // read in section 76 stream.Seek(-2, SEEK_CUR); 77 78 uint8 exifData[length]; 79 if (stream.Read(exifData, length) == length 80 && process_exif(exifData, length) == B_OK) 81 return B_OK; 82 } else { 83 // ignore section 84 stream.Seek(length - 2, SEEK_CUR); 85 } 86 } 87 88 return B_BAD_VALUE; 89 } 90 91 92 static status_t 93 process_file(entry_ref& ref) 94 { 95 BFile file(&ref, B_READ_WRITE); 96 status_t status = file.InitCheck(); 97 if (status != B_OK) 98 return status; 99 100 // read EXIF 101 102 BBufferIO stream(&file, 65536, false); 103 status = process_jpeg(file); 104 if (status < B_OK) { 105 fprintf(stderr, "%s: processing JPEG file failed: %s\n", ref.name, 106 strerror(status)); 107 return status; 108 } 109 110 return B_OK; 111 } 112 113 114 int 115 main(int argc, char **argv) 116 { 117 for (int i = 1; i < argc; i++) { 118 BEntry entry(argv[i]); 119 entry_ref ref; 120 if (entry.InitCheck() != B_OK || entry.GetRef(&ref) != B_OK) 121 continue; 122 123 process_file(ref); 124 } 125 return -1; 126 } 127