1 #ifndef __WEBP_Support_hpp__
2 #define __WEBP_Support_hpp__ 1
3
4 #include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
5
6 #include "public/include/XMP_Const.h"
7 #include "public/include/XMP_IO.hpp"
8
9 #include "XMPFiles/source/XMPFiles_Impl.hpp"
10 #include "source/Endian.h"
11 #include "source/XMPFiles_IO.hpp"
12
13 #include <array>
14 #include <map>
15 #include <vector>
16
17 // forward declaration:
18 class WEBP_MetaHandler;
19
20 namespace WEBP {
21
22 // Read 16, 24 or 32 bits stored in little-endian order.
23 //
24 // The inline functions provided in EndianUtils.hpp and XIO.hpp operate on
25 // pointers to XMP_Uns32, and then flip the bytes if the desired endianness
26 // differs from the host's. It seems to me that it is much simpler to read
27 // the data into XMP_Uns8 (i.e. unsigned char) arrays and just use shift
28 // operators (which operate on values rather than their representation
29 // in memory) to convert between values and the bytes read from or written to
30 // a file in a platform-independent way. And besides, WEBP stores dimensions
31 // in 24 bit LE, and converting that to and from a 32 bit pointer, having to
32 // account for the platform's endianness, would be a nightmare.
GetLE16(const XMP_Uns8 * const data)33 static inline XMP_Uns32 GetLE16(const XMP_Uns8* const data)
34 {
35 return (XMP_Uns32)(data[0] << 0) | (data[1] << 8);
36 }
37
GetLE24(const XMP_Uns8 * const data)38 static inline XMP_Uns32 GetLE24(const XMP_Uns8* const data)
39 {
40 return GetLE16(data) | (data[2] << 16);
41 }
42
GetLE32(const XMP_Uns8 * const data)43 static inline XMP_Uns32 GetLE32(const XMP_Uns8* const data)
44 {
45 return (XMP_Uns32)GetLE16(data) | (GetLE16(data + 2) << 16);
46 }
47
48 // Store 16, 24 or 32 bits in little-endian order.
PutLE16(XMP_Uns8 * const data,XMP_Uns32 val)49 static inline void PutLE16(XMP_Uns8* const data, XMP_Uns32 val)
50 {
51 assert(val < (1 << 16));
52 data[0] = (val >> 0);
53 data[1] = (val >> 8);
54 }
55
PutLE24(XMP_Uns8 * const buf,XMP_Uns32 val)56 static inline void PutLE24(XMP_Uns8* const buf, XMP_Uns32 val)
57 {
58 assert(val < (1 << 24));
59 PutLE16(buf, val & 0xffff);
60 buf[2] = (val >> 16);
61 }
62
PutLE32(XMP_Uns8 * const data,XMP_Uns32 val)63 static inline void PutLE32(XMP_Uns8* const data, XMP_Uns32 val)
64 {
65 PutLE16(data, (XMP_Uns32)(val & 0xffff));
66 PutLE16(data + 2, (XMP_Uns32)(val >> 16));
67 }
68
69 #define WEBP_MKFOURCC(a, b, c, d) \
70 ((XMP_Uns32)(a) | (b) << 8 | (c) << 16 | (d) << 24)
71
72 // VP8X Feature Flags.
73 typedef enum FeatureFlagBits {
74 FRAGMENTS_FLAG_BIT, // Experimental, not enabled by default
75 ANIMATION_FLAG_BIT,
76 XMP_FLAG_BIT,
77 EXIF_FLAG_BIT,
78 ALPHA_FLAG_BIT,
79 ICCP_FLAG_BIT
80 } FeatureFlagBits;
81
82 typedef enum ChunkId {
83 WEBP_CHUNK_VP8X, // VP8X
84 WEBP_CHUNK_ICCP, // ICCP
85 WEBP_CHUNK_ANIM, // ANIM
86 WEBP_CHUNK_ANMF, // ANMF
87 WEBP_CHUNK_FRGM, // FRGM
88 WEBP_CHUNK_ALPHA, // ALPH
89 WEBP_CHUNK_IMAGE, // VP8/VP8L
90 WEBP_CHUNK_EXIF, // EXIF
91 WEBP_CHUNK_XMP, // XMP
92 WEBP_CHUNK_UNKNOWN, // Other chunks.
93 WEBP_CHUNK_NIL
94 } ChunkId;
95
96 const XMP_Uns32 kChunk_RIFF = WEBP_MKFOURCC('R', 'I', 'F', 'F');
97 const XMP_Uns32 kChunk_WEBP = WEBP_MKFOURCC('W', 'E', 'B', 'P');
98 const XMP_Uns32 kChunk_VP8_ = WEBP_MKFOURCC('V', 'P', '8', ' ');
99 const XMP_Uns32 kChunk_VP8L = WEBP_MKFOURCC('V', 'P', '8', 'L');
100 const XMP_Uns32 kChunk_VP8X = WEBP_MKFOURCC('V', 'P', '8', 'X');
101 const XMP_Uns32 kChunk_XMP_ = WEBP_MKFOURCC('X', 'M', 'P', ' ');
102 const XMP_Uns32 kChunk_ANIM = WEBP_MKFOURCC('A', 'N', 'I', 'M');
103 const XMP_Uns32 kChunk_ICCP = WEBP_MKFOURCC('I', 'C', 'C', 'P');
104 const XMP_Uns32 kChunk_EXIF = WEBP_MKFOURCC('E', 'X', 'I', 'F');
105 const XMP_Uns32 kChunk_ANMF = WEBP_MKFOURCC('A', 'N', 'M', 'F');
106 const XMP_Uns32 kChunk_FRGM = WEBP_MKFOURCC('F', 'R', 'G', 'M');
107 const XMP_Uns32 kChunk_ALPH = WEBP_MKFOURCC('A', 'L', 'P', 'H');
108
109 static std::map<XMP_Uns32, ChunkId> chunkMap = {
110 { kChunk_VP8X, WEBP_CHUNK_VP8X }, { kChunk_ICCP, WEBP_CHUNK_ICCP },
111 { kChunk_ANIM, WEBP_CHUNK_ANIM }, { kChunk_ANMF, WEBP_CHUNK_ANMF },
112 { kChunk_FRGM, WEBP_CHUNK_FRGM }, { kChunk_ALPH, WEBP_CHUNK_ALPHA },
113 { kChunk_VP8_, WEBP_CHUNK_IMAGE }, { kChunk_VP8L, WEBP_CHUNK_IMAGE },
114 { kChunk_EXIF, WEBP_CHUNK_EXIF }, { kChunk_XMP_, WEBP_CHUNK_XMP }
115 };
116
117 class Container;
118
119 class Chunk {
120 public:
121 Chunk(Container* parent, WEBP_MetaHandler* handler);
122 Chunk(Container* parent, XMP_Uns32 tag);
123 virtual ~Chunk();
124
125 virtual void write(WEBP_MetaHandler* handler);
126
127 Container* parent;
128 XMP_Uns32 tag;
129 RawDataBlock data;
130 XMP_Int64 pos;
131 XMP_Int64 size;
132 bool needsRewrite;
133 };
134
135 class XMPChunk
136 : public Chunk {
137 public:
138 XMPChunk(Container* parent, WEBP_MetaHandler* handler);
139 XMPChunk(Container* parent);
140 void write(WEBP_MetaHandler* handler);
141 };
142
143 class VP8XChunk
144 : public Chunk {
145 public:
146 VP8XChunk(Container* parent, WEBP_MetaHandler* handler);
147 VP8XChunk(Container* parent);
148 bool xmp();
149 void xmp(bool);
150 XMP_Uns32 width();
151 XMP_Uns32 height();
152 void width(XMP_Uns32);
153 void height(XMP_Uns32);
154 };
155
156 typedef std::array<std::vector<Chunk*>, WEBP_CHUNK_NIL> Chunks;
157
158 class Container
159 : public Chunk {
160 public:
161 Container(WEBP_MetaHandler* handler);
162 ~Container();
163
164 void write(WEBP_MetaHandler* handler);
165 void addChunk(Chunk*);
166 Chunk* getExifChunk();
167
168 Chunks chunks;
169 VP8XChunk* vp8x;
170 };
171
172 } // namespace WEBP
173
174 #endif // __WEBP_Support_hpp__
175