57 const char* guidAscii) {
59 constexpr size_t kFullLengthSize = 4;
60 constexpr size_t kOffsetSize = 4;
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;
80 guidAsDigest.
data[i / 2] = 16 * digit;
82 guidAsDigest.
data[i / 2] += digit;
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) {
100 const uint8_t* partGuidAscii =
params->bytes() + kSigSize;
107 uint32_t partFullLength = 0;
108 uint32_t partOffset = 0;
110 const uint8_t* partOffsetBytes =
112 for (
size_t i = 0; i < 4; ++i) {
113 partFullLength *= 256;
115 partFullLength += partFullLengthBytes[i];
116 partOffset += partOffsetBytes[i];
121 fullLength = partFullLength;
125 if (partFullLength != fullLength) {
126 SkCodecPrintf(
"Multiple parts had different total lengths.\n");
133 parts.push_back({partOffset, partData});
135 if (parts.empty() || fullLength == 0) {
140 std::sort(parts.begin(), parts.end(), [](
const Part&
a,
const Part&
b) {
141 return std::get<0>(a) < std::get<0>(b);
146 uint8_t* xmpExtendedBase =
reinterpret_cast<uint8_t*
>(xmpExtendedData->writable_data());
147 uint8_t* xmpExtendedCurrent = xmpExtendedBase;
149 for (
const auto& part : parts) {
150 uint32_t currentOffset =
static_cast<uint32_t
>(xmpExtendedCurrent - xmpExtendedBase);
151 uint32_t partOffset = std::get<0>(part);
154 if (partOffset != currentOffset) {
158 if (partData->size() > fullLength - currentOffset) {
162 memcpy(xmpExtendedCurrent, partData->data(), partData->size());
163 xmpExtendedCurrent += partData->size();
166 if (
static_cast<uint32_t
>(xmpExtendedCurrent - xmpExtendedBase) != fullLength) {
172 md5.write(xmpExtendedData->data(), xmpExtendedData->size());
173 if (
md5.finish() != guidAsDigest) {
178 return xmpExtendedData;