Flutter Engine
The Flutter Engine
Functions | Variables
SkJpegXmp.cpp File Reference
#include "src/codec/SkJpegXmp.h"
#include "include/private/SkGainmapInfo.h"
#include "include/utils/SkParse.h"
#include "src/codec/SkCodecPriv.h"
#include "src/codec/SkJpegConstants.h"
#include "src/core/SkMD5.h"
#include "src/xml/SkDOM.h"
#include <string>
#include <tuple>

Go to the source code of this file.

Functions

static sk_sp< SkDataread_xmp_standard (const std::vector< sk_sp< SkData > > &decoderApp1Params)
 
static sk_sp< SkDataread_xmp_extended (const std::vector< sk_sp< SkData > > &decoderApp1Params, const char *guidAscii)
 
std::unique_ptr< SkXmpSkJpegMakeXmp (const std::vector< sk_sp< SkData > > &decoderApp1Params)
 

Variables

constexpr size_t kGuidAsciiSize = 32
 

Function Documentation

◆ read_xmp_extended()

static sk_sp< SkData > read_xmp_extended ( const std::vector< sk_sp< SkData > > &  decoderApp1Params,
const char *  guidAscii 
)
static

Definition at line 56 of file SkJpegXmp.cpp.

57 {
58 constexpr size_t kSigSize = sizeof(kXMPExtendedSig);
59 constexpr size_t kFullLengthSize = 4;
60 constexpr size_t kOffsetSize = 4;
61 constexpr size_t kHeaderSize = kSigSize + kGuidAsciiSize + kFullLengthSize + kOffsetSize;
62
63 // Validate the provided ASCII guid.
64 if (strlen(guidAscii) != kGuidAsciiSize) {
65 SkCodecPrintf("Invalid ASCII GUID size.\n");
66 return nullptr;
67 }
68 SkMD5::Digest guidAsDigest;
69 for (size_t i = 0; i < kGuidAsciiSize; ++i) {
70 uint8_t digit = 0;
71 if (guidAscii[i] >= '0' && guidAscii[i] <= '9') {
72 digit = guidAscii[i] - '0';
73 } else if (guidAscii[i] >= 'A' && guidAscii[i] <= 'F') {
74 digit = guidAscii[i] - 'A' + 10;
75 } else {
76 SkCodecPrintf("GUID is not upper-case hex.\n");
77 return nullptr;
78 }
79 if (i % 2 == 0) {
80 guidAsDigest.data[i / 2] = 16 * digit;
81 } else {
82 guidAsDigest.data[i / 2] += digit;
83 }
84 }
85
86 // Iterate through the image's segments.
87 uint32_t fullLength = 0;
88 using Part = std::tuple<uint32_t, sk_sp<SkData>>;
89 std::vector<Part> parts;
90 for (const auto& params : decoderApp1Params) {
91 // Skip segments that don't have the right marker, signature, or are too small.
92 if (params->size() <= kHeaderSize) {
93 continue;
94 }
95 if (memcmp(params->bytes(), kXMPExtendedSig, kSigSize) != 0) {
96 continue;
97 }
98
99 // Ignore parts that do not match the expected GUID.
100 const uint8_t* partGuidAscii = params->bytes() + kSigSize;
101 if (memcmp(guidAscii, partGuidAscii, kGuidAsciiSize) != 0) {
102 SkCodecPrintf("Ignoring unexpected GUID.\n");
103 continue;
104 }
105
106 // Read the full length and the offset for this part.
107 uint32_t partFullLength = 0;
108 uint32_t partOffset = 0;
109 const uint8_t* partFullLengthBytes = params->bytes() + kSigSize + kGuidAsciiSize;
110 const uint8_t* partOffsetBytes =
111 params->bytes() + kSigSize + kGuidAsciiSize + kFullLengthSize;
112 for (size_t i = 0; i < 4; ++i) {
113 partFullLength *= 256;
114 partOffset *= 256;
115 partFullLength += partFullLengthBytes[i];
116 partOffset += partOffsetBytes[i];
117 }
118
119 // If this is the first part, set our global full length size.
120 if (parts.empty()) {
121 fullLength = partFullLength;
122 }
123
124 // Ensure all parts agree on the full length.
125 if (partFullLength != fullLength) {
126 SkCodecPrintf("Multiple parts had different total lengths.\n");
127 return nullptr;
128 }
129
130 // Add it to the list.
131 auto partData = SkData::MakeWithoutCopy(params->bytes() + kHeaderSize,
132 params->size() - kHeaderSize);
133 parts.push_back({partOffset, partData});
134 }
135 if (parts.empty() || fullLength == 0) {
136 return nullptr;
137 }
138
139 // Sort the list of parts by offset.
140 std::sort(parts.begin(), parts.end(), [](const Part& a, const Part& b) {
141 return std::get<0>(a) < std::get<0>(b);
142 });
143
144 // Stitch the parts together. Fail if we find that they are not contiguous.
145 auto xmpExtendedData = SkData::MakeUninitialized(fullLength);
146 uint8_t* xmpExtendedBase = reinterpret_cast<uint8_t*>(xmpExtendedData->writable_data());
147 uint8_t* xmpExtendedCurrent = xmpExtendedBase;
148 SkMD5 md5;
149 for (const auto& part : parts) {
150 uint32_t currentOffset = static_cast<uint32_t>(xmpExtendedCurrent - xmpExtendedBase);
151 uint32_t partOffset = std::get<0>(part);
152 const sk_sp<SkData>& partData = std::get<1>(part);
153 // Make sure the data is contiguous and doesn't overflow the buffer.
154 if (partOffset != currentOffset) {
155 SkCodecPrintf("XMP extension parts not contiguous\n");
156 return nullptr;
157 }
158 if (partData->size() > fullLength - currentOffset) {
159 SkCodecPrintf("XMP extension parts overflow\n");
160 return nullptr;
161 }
162 memcpy(xmpExtendedCurrent, partData->data(), partData->size());
163 xmpExtendedCurrent += partData->size();
164 }
165 // Make sure we wrote the full buffer.
166 if (static_cast<uint32_t>(xmpExtendedCurrent - xmpExtendedBase) != fullLength) {
167 SkCodecPrintf("XMP extension did not match full length.\n");
168 return nullptr;
169 }
170
171 // Make sure the MD5 hash of the extended data matched the GUID.
172 md5.write(xmpExtendedData->data(), xmpExtendedData->size());
173 if (md5.finish() != guidAsDigest) {
174 SkCodecPrintf("XMP extension did not hash to GUID.\n");
175 return nullptr;
176 }
177
178 return xmpExtendedData;
179}
static SkMD5::Digest md5(const SkBitmap &bm)
Definition: CodecTest.cpp:77
#define SkCodecPrintf(...)
Definition: SkCodecPriv.h:23
static constexpr size_t kHeaderSize
static constexpr uint8_t kXMPExtendedSig[]
constexpr size_t kGuidAsciiSize
Definition: SkJpegXmp.cpp:20
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition: SkData.h:116
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
const void * data() const
Definition: SkData.h:37
size_t size() const
Definition: SkData.h:30
Definition: SkMD5.h:19
const EmbeddedViewParams * params
static bool b
struct MyStruct a[10]
const myers::Point & get< 1 >(const myers::Segment &s)
Definition: Myers.h:81
const myers::Point & get< 0 >(const myers::Segment &s)
Definition: Myers.h:80
uint8_t data[16]
Definition: SkMD5.h:39

◆ read_xmp_standard()

static sk_sp< SkData > read_xmp_standard ( const std::vector< sk_sp< SkData > > &  decoderApp1Params)
static

Definition at line 27 of file SkJpegXmp.cpp.

27 {
28 constexpr size_t kSigSize = sizeof(kXMPStandardSig);
29 // Iterate through the image's segments.
30 for (const auto& params : decoderApp1Params) {
31 // Skip segments that don't have the right marker, signature, or are too small.
32 if (params->size() <= kSigSize) {
33 continue;
34 }
35 if (memcmp(params->bytes(), kXMPStandardSig, kSigSize) != 0) {
36 continue;
37 }
38 return SkData::MakeWithoutCopy(params->bytes() + kSigSize, params->size() - kSigSize);
39 }
40 return nullptr;
41}
static constexpr uint8_t kXMPStandardSig[]

◆ SkJpegMakeXmp()

std::unique_ptr< SkXmp > SkJpegMakeXmp ( const std::vector< sk_sp< SkData > > &  decoderApp1Params)

Definition at line 181 of file SkJpegXmp.cpp.

181 {
182 auto xmpStandard = read_xmp_standard(decoderApp1Params);
183 if (!xmpStandard) {
184 return nullptr;
185 }
186
187 std::unique_ptr<SkXmp> xmp = SkXmp::Make(xmpStandard);
188 if (!xmp) {
189 return nullptr;
190 }
191
192 // Extract the GUID (the MD5 hash) of the extended metadata.
193 const char* extendedGuid = xmp->getExtendedXmpGuid();
194 if (!extendedGuid) {
195 return xmp;
196 }
197
198 // Extract and validate the extended metadata from the JPEG structure.
199 auto xmpExtended = read_xmp_extended(decoderApp1Params, extendedGuid);
200 if (!xmpExtended) {
201 SkCodecPrintf("Extended XMP was indicated but failed to read or validate.\n");
202 return xmp;
203 }
204
205 return SkXmp::Make(xmpStandard, xmpExtended);
206}
static sk_sp< SkData > read_xmp_standard(const std::vector< sk_sp< SkData > > &decoderApp1Params)
Definition: SkJpegXmp.cpp:27
static sk_sp< SkData > read_xmp_extended(const std::vector< sk_sp< SkData > > &decoderApp1Params, const char *guidAscii)
Definition: SkJpegXmp.cpp:56
static std::unique_ptr< SkXmp > Make(sk_sp< SkData > xmpData)
Definition: SkXmp.cpp:652

Variable Documentation

◆ kGuidAsciiSize

constexpr size_t kGuidAsciiSize = 32
constexpr

Definition at line 20 of file SkJpegXmp.cpp.