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