1// Copyright 2015 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16//
17// TiffDirectory contains an abstraction of an image file directory (IFD) as
18// proposed by the TIFF specification.
19
20#ifndef PIEX_TIFF_DIRECTORY_TIFF_DIRECTORY_H_
21#define PIEX_TIFF_DIRECTORY_TIFF_DIRECTORY_H_
22
23#include <cstdint>
24#include <map>
25#include <string>
26#include <vector>
27
28namespace piex {
29namespace tiff_directory {
30
31enum Endian {
32 kLittleEndian = 0,
33 kBigEndian = 1,
34};
35
36struct Rational {
37 std::uint32_t numerator;
38 std::uint32_t denominator;
39};
40
41struct SRational {
42 std::int32_t numerator;
43 std::int32_t denominator;
44};
45
46enum TiffTypes {
47 TIFF_TYPE_NONE = 0,
48 TIFF_TYPE_BYTE, /* 8bit unsigned */
49 TIFF_TYPE_ASCII, /* Ascii string (terminated by \0) */
50 TIFF_TYPE_SHORT, /* 16bit unsigned */
51 TIFF_TYPE_LONG, /* 32bit unsigned */
52 TIFF_TYPE_RATIONAL, /* 32bit/32bit unsigned */
53 TIFF_TYPE_SBYTE, /* 8bit signed */
54 TIFF_TYPE_UNDEFINED, /* undefined (depend of tag) */
55 TIFF_TYPE_SSHORT, /* 16bit signed*/
56 TIFF_TYPE_SLONG, /* 32bit signed */
57 TIFF_TYPE_SRATIONAL, /* 32bit/32bit signed */
58 TIFF_TYPE_FLOAT, /* 32-bit IEEE float */
59 TIFF_TYPE_DOUBLE, /* 64-bit IEEE float */
60 TIFF_IFD, /* IFD type */
61};
62
63// The TiffDirectory class stores all information necessary to interpret TIFF
64// tags and manages also potential sub directories.
65class TiffDirectory {
66 public:
67 typedef std::uint32_t Tag;
68 typedef std::uint32_t Type;
69
70 explicit TiffDirectory(Endian endianness);
71
72 // Returns true if the directory contains the specified tag.
73 bool Has(const Tag tag) const;
74
75 // Gets the value of a tag of byte vector type.
76 // Returns false if the tag is not part of the directory or if the
77 // type is not BYTE or UNDEFINED.
78 bool Get(const Tag tag, std::vector<std::uint8_t>* value) const;
79
80 // Gets the value of a tag of type "ASCII".
81 // Returns false if the tag is not part of the directory or if its
82 // type is not ASCII.
83 // If *err is not equal to ERR_OK initially, this method does nothing.
84 bool Get(const Tag tag, std::string* value) const;
85
86 // Gets the value of a tag of type "SHORT" or "LONG".
87 // Returns false
88 // - if the tag is not part of the directory or
89 // - if the type is not SHORT or LONG, or
90 // - if, for the non-vector version, the number of elements is unequal to 1.
91 bool Get(const Tag tag, std::uint32_t* value) const;
92 bool Get(const Tag tag, std::vector<std::uint32_t>* value) const;
93
94 // Gets the value of a tag of type "SHORT", "LONG" or "RATIONAL".
95 // Returns false
96 // - if the tag is not part of the directory or
97 // - if the type is not SHORT, LONG or RATIONAL, or
98 // - if, for the non-vector version, the number of elements is unequal to 1.
99 bool Get(const Tag tag, Rational* value) const;
100 bool Get(const Tag tag, std::vector<Rational>* value) const;
101
102 // Gets the value of a tag of type "SSHORT", "SLONG" or "SRATIONAL".
103 // Returns false
104 // - if the tag is not part of the directory or
105 // - if the type is not SSHORT, SLONG or SRATIONAL, or
106 // - if, for the non-vector version, the number of elements is unequal to 1.
107 bool Get(const Tag tag, SRational* value) const;
108 bool Get(const Tag tag, std::vector<SRational>* value) const;
109
110 // Gets the 'offset' to the value data in the file and its 'length' in bytes.
111 // Returns false if the 'tag' is not part of the directory or if its type does
112 // not match the desired 'type'.
113 bool GetOffsetAndLength(const Tag tag, const Type type, std::uint32_t* offset,
114 std::uint32_t* length) const;
115
116 // Adds a tag to the directory, setting its type, number of elements
117 // ('count'), the offset to the binary data in the file ('offset') and the
118 // associated binary data ('value'). The binary data is encoded according to
119 // the TIFF specification with the endianness that was specified when this
120 // object was constructed. The caller must ensure that the size of 'value' and
121 // the data it contains are consistent with 'type' and 'count'. It is not
122 // legal to call this method with a tag that is already contained in the
123 // directory.
124 void AddEntry(const Tag tag, const Type type, const std::uint32_t count,
125 const std::uint32_t offset,
126 const std::vector<std::uint8_t>& value);
127
128 // Add a subdirectory to the directory.
129 void AddSubDirectory(const TiffDirectory& sub_directory);
130
131 // Returns a vector of all subdirectories contained in this directory.
132 const std::vector<TiffDirectory>& GetSubDirectories() const;
133
134 private:
135 struct DirectoryEntry {
136 Type type;
137 std::uint32_t count; // The number of values of type, not a byte count.
138 std::uint32_t offset; // Offset of the entry's data in the file. '0' means
139 // the offset is not set.
140 std::vector<std::uint8_t> value;
141 };
142
143 const DirectoryEntry* Find(const Tag tag) const;
144
145 std::map<Tag, DirectoryEntry> directory_entries_;
146 std::vector<Tag> tag_order_;
147 std::vector<TiffDirectory> sub_directories_;
148 Endian endian_;
149};
150
151// Returns the number of bytes a single value of 'type' requires; this is
152// guaranteed to be in the range of 0 to 8.
153// Returns 0 if 'type' is TIFF_TYPE_NONE or invalid. Sets 'success' to false if
154// 'type' is invalid. If you are not interested in 'success' you can set it to
155// a nullptr.
156size_t SizeOfType(const TiffDirectory::Type type, bool* success);
157
158} // namespace tiff_directory
159} // namespace piex
160
161#endif // PIEX_TIFF_DIRECTORY_TIFF_DIRECTORY_H_
162