106 |
106 |
std::cerr << "Photoshop::locateIrb: ";
|
107 |
107 |
#endif
|
108 |
108 |
// Data should follow Photoshop format, if not exit
|
109 |
|
while ( position <= sizePsData - 14
|
|
109 |
while ( position <= sizePsData - 12
|
110 |
110 |
&& memcmp(pPsData + position, Photoshop::bimId_, 4) == 0) {
|
111 |
111 |
const byte *hrd = pPsData + position;
|
112 |
112 |
position += 4;
|
... | ... | |
173 |
173 |
|
174 |
174 |
DataBuf Photoshop::setIptcIrb(const byte* pPsData,
|
175 |
175 |
long sizePsData,
|
176 |
|
const IptcData& iptcData)
|
|
176 |
const IptcData& iptcData,
|
|
177 |
bool keepEmptyBlock)
|
177 |
178 |
{
|
178 |
179 |
if (sizePsData > 0) assert(pPsData);
|
179 |
180 |
#ifdef DEBUG
|
... | ... | |
198 |
199 |
}
|
199 |
200 |
// Write new iptc record if we have it
|
200 |
201 |
DataBuf rawIptc = IptcParser::encode(iptcData);
|
201 |
|
if (rawIptc.size_ > 0) {
|
|
202 |
if (rawIptc.size_ > 0 || keepEmptyBlock) {
|
202 |
203 |
byte tmpBuf[12];
|
203 |
204 |
std::memcpy(tmpBuf, Photoshop::bimId_, 4);
|
204 |
205 |
us2Data(tmpBuf + 4, iptc_, bigEndian);
|
... | ... | |
281 |
282 |
const long bufMinSize = 36;
|
282 |
283 |
long bufRead = 0;
|
283 |
284 |
DataBuf buf(bufMinSize);
|
284 |
|
Blob iptcBlob;
|
285 |
285 |
bool foundPsData = false;
|
286 |
286 |
|
287 |
287 |
// Read section marker
|
... | ... | |
296 |
296 |
if (bufRead < 2) throw Error(15);
|
297 |
297 |
uint16_t size = getUShort(buf.pData_, bigEndian);
|
298 |
298 |
|
299 |
|
if (foundPsData && marker != app13_) {
|
300 |
|
// For IPTC, decrement search only after all app13 segments are
|
301 |
|
// loaded, assuming they all appear in sequence. But decode IPTC
|
302 |
|
// data after the loop, in case an app13 is the last segment
|
303 |
|
// before sos or eoi.
|
304 |
|
foundPsData = false;
|
305 |
|
if (--search == 0) break;
|
306 |
|
}
|
307 |
|
|
308 |
299 |
if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
|
309 |
300 |
if (size < 8) {
|
310 |
301 |
rc = 1;
|
... | ... | |
344 |
335 |
--search;
|
345 |
336 |
}
|
346 |
337 |
else if ( marker == app13_
|
|
338 |
&& !foundPsData
|
347 |
339 |
&& memcmp(buf.pData_ + 2, Photoshop::ps3Id_, 14) == 0) {
|
348 |
340 |
if (size < 16) {
|
349 |
341 |
rc = 2;
|
... | ... | |
354 |
346 |
DataBuf psData(size - 16);
|
355 |
347 |
io_->read(psData.pData_, psData.size_);
|
356 |
348 |
if (io_->error() || io_->eof()) throw Error(14);
|
|
349 |
Blob iptcBlob;
|
357 |
350 |
const byte *record = 0;
|
358 |
351 |
uint32_t sizeIptc = 0;
|
359 |
352 |
uint32_t sizeHdr = 0;
|
... | ... | |
370 |
363 |
&record,
|
371 |
364 |
&sizeHdr,
|
372 |
365 |
&sizeIptc)) {
|
373 |
|
if (sizeIptc) {
|
374 |
366 |
#ifdef DEBUG
|
375 |
|
std::cerr << "Found IPTC IRB, size = " << sizeIptc << "\n";
|
|
367 |
std::cerr << "Found IPTC IRB, size = " << sizeIptc << "\n";
|
376 |
368 |
#endif
|
|
369 |
if (sizeIptc) {
|
377 |
370 |
append(iptcBlob, record + sizeHdr, sizeIptc);
|
378 |
371 |
}
|
379 |
372 |
pCur = record + sizeHdr + sizeIptc;
|
380 |
373 |
pCur += (sizeIptc & 1);
|
381 |
374 |
}
|
|
375 |
if ( iptcBlob.size() > 0
|
|
376 |
&& IptcParser::decode(iptcData_,
|
|
377 |
&iptcBlob[0],
|
|
378 |
static_cast<uint32_t>(iptcBlob.size()))) {
|
|
379 |
#ifndef SUPPRESS_WARNINGS
|
|
380 |
std::cerr << "Warning: Failed to decode IPTC metadata.\n";
|
|
381 |
#endif
|
|
382 |
iptcData_.clear();
|
|
383 |
}
|
382 |
384 |
foundPsData = true;
|
|
385 |
--search;
|
383 |
386 |
}
|
384 |
387 |
else if (marker == com_ && comment_.empty())
|
385 |
388 |
{
|
... | ... | |
434 |
437 |
}
|
435 |
438 |
} // while there are segments to process
|
436 |
439 |
|
437 |
|
if ( iptcBlob.size() > 0
|
438 |
|
&& IptcParser::decode(iptcData_,
|
439 |
|
&iptcBlob[0],
|
440 |
|
static_cast<uint32_t>(iptcBlob.size()))) {
|
441 |
|
#ifndef SUPPRESS_WARNINGS
|
442 |
|
std::cerr << "Warning: Failed to decode IPTC metadata.\n";
|
443 |
|
#endif
|
444 |
|
iptcData_.clear();
|
445 |
|
}
|
446 |
|
|
447 |
440 |
if (rc != 0) {
|
448 |
441 |
#ifndef SUPPRESS_WARNINGS
|
449 |
442 |
std::cerr << "Warning: JPEG format error, rc = " << rc << "\n";
|
... | ... | |
487 |
480 |
int skipApp1Xmp = -1;
|
488 |
481 |
int skipApp13Ps3 = -1;
|
489 |
482 |
int skipCom = -1;
|
|
483 |
bool multipleApp13Ps3 = false;
|
490 |
484 |
DataBuf psData;
|
491 |
485 |
DataBuf rawExif;
|
492 |
486 |
|
... | ... | |
511 |
505 |
insertPos = count + 1;
|
512 |
506 |
if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
|
513 |
507 |
}
|
514 |
|
else if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
|
|
508 |
else if (marker == app1_ && skipApp1Exif == -1
|
|
509 |
&& memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
|
515 |
510 |
if (size < 8) throw Error(22);
|
516 |
511 |
skipApp1Exif = count;
|
517 |
512 |
++search;
|
... | ... | |
521 |
516 |
io_->read(rawExif.pData_, rawExif.size_);
|
522 |
517 |
if (io_->error() || io_->eof()) throw Error(22);
|
523 |
518 |
}
|
524 |
|
else if (marker == app1_ && memcmp(buf.pData_ + 2, xmpId_, 29) == 0) {
|
|
519 |
else if (marker == app1_ && skipApp1Xmp == -1
|
|
520 |
&& memcmp(buf.pData_ + 2, xmpId_, 29) == 0) {
|
525 |
521 |
if (size < 31) throw Error(22);
|
526 |
522 |
skipApp1Xmp = count;
|
527 |
523 |
++search;
|
528 |
524 |
if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
|
529 |
525 |
}
|
530 |
526 |
else if (marker == app13_ && memcmp(buf.pData_ + 2, Photoshop::ps3Id_, 14) == 0) {
|
|
527 |
if (skipApp13Ps3 == -1) {
|
531 |
528 |
#ifdef DEBUG
|
532 |
|
std::cerr << "Found APP13 Photoshop PS3 segment\n";
|
|
529 |
std::cerr << "Found APP13 Photoshop PS3 segment\n";
|
533 |
530 |
#endif
|
534 |
|
if (size < 16) throw Error(22);
|
535 |
|
skipApp13Ps3 = count;
|
536 |
|
++search;
|
537 |
|
io_->seek(16 - bufRead, BasicIo::cur);
|
538 |
|
psData.alloc(size - 16);
|
539 |
|
// Load PS data now to allow reinsertion at any point
|
540 |
|
io_->read(psData.pData_, size - 16);
|
541 |
|
if (io_->error() || io_->eof()) throw Error(20);
|
|
531 |
if (size < 16) throw Error(22);
|
|
532 |
skipApp13Ps3 = count;
|
|
533 |
++search;
|
|
534 |
io_->seek(16 - bufRead, BasicIo::cur);
|
|
535 |
psData.alloc(size - 16);
|
|
536 |
// Load PS data now to allow reinsertion at any point
|
|
537 |
io_->read(psData.pData_, size - 16);
|
|
538 |
if (io_->error() || io_->eof()) throw Error(20);
|
|
539 |
} else {
|
|
540 |
#ifdef DEBUG
|
|
541 |
std::cerr << "Found another APP13 Photoshop PS3 segment\n";
|
|
542 |
#endif
|
|
543 |
multipleApp13Ps3 = true;
|
|
544 |
}
|
542 |
545 |
}
|
543 |
546 |
else if (marker == com_ && skipCom == -1) {
|
544 |
547 |
if (size < 2) throw Error(22);
|
... | ... | |
658 |
661 |
if (psData.size_ > 0 || iptcData_.count() > 0) {
|
659 |
662 |
// Set the new IPTC IRB, keeps existing IRBs but removes the
|
660 |
663 |
// IPTC block if there is no new IPTC data to write
|
|
664 |
// and no other IPTC IRBs are following
|
661 |
665 |
DataBuf newPsData = Photoshop::setIptcIrb(psData.pData_,
|
662 |
666 |
psData.size_,
|
663 |
|
iptcData_);
|
|
667 |
iptcData_,
|
|
668 |
multipleApp13Ps3);
|
664 |
669 |
if (newPsData.size_ > 0) {
|
665 |
670 |
// Write APP13 marker, new size, and ps3Id
|
666 |
671 |
tmpBuf[0] = 0xff;
|