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