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
21static status_t
22process_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
38static status_t
39process_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
92static status_t
93process_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
114int
115main(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