|
|
|
@ -324,12 +324,14 @@ namespace Exiv2 {
|
|
|
|
|
int c = -1;
|
|
|
|
|
// Skips potential padding between markers
|
|
|
|
|
while ((c=io_->getb()) != 0xff) {
|
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
|
if (c == EOF)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Markers can start with any number of 0xff
|
|
|
|
|
while ((c=io_->getb()) == 0xff) {
|
|
|
|
|
if (c == EOF) return -2;
|
|
|
|
|
if (c == EOF)
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
@ -560,50 +562,48 @@ namespace Exiv2 {
|
|
|
|
|
out << Internal::stringFormat("%8ld | 0xff%02x %-5s", \
|
|
|
|
|
io_->tell()-2,marker,nm[marker].c_str())
|
|
|
|
|
|
|
|
|
|
void JpegBase::printStructure(std::ostream& out, PrintStructureOption option,int depth)
|
|
|
|
|
void JpegBase::printStructure(std::ostream& out, PrintStructureOption option, int depth)
|
|
|
|
|
{
|
|
|
|
|
if (io_->open() != 0) throw Error(kerDataSourceOpenFailed, io_->path(), strError());
|
|
|
|
|
if (io_->open() != 0)
|
|
|
|
|
throw Error(kerDataSourceOpenFailed, io_->path(), strError());
|
|
|
|
|
// Ensure that this is the correct image type
|
|
|
|
|
if (!isThisType(*io_, false)) {
|
|
|
|
|
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
|
|
|
|
|
if (io_->error() || io_->eof())
|
|
|
|
|
throw Error(kerFailedToReadImageData);
|
|
|
|
|
throw Error(kerNotAJpeg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool bPrint = option==kpsBasic || option==kpsRecursive;
|
|
|
|
|
bool bPrint = option == kpsBasic || option == kpsRecursive;
|
|
|
|
|
Exiv2::Uint32Vector iptcDataSegs;
|
|
|
|
|
|
|
|
|
|
if ( bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase ) {
|
|
|
|
|
|
|
|
|
|
if (bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase) {
|
|
|
|
|
// nmonic for markers
|
|
|
|
|
std::string nm[256] ;
|
|
|
|
|
nm[0xd8]="SOI" ;
|
|
|
|
|
nm[0xd9]="EOI" ;
|
|
|
|
|
nm[0xda]="SOS" ;
|
|
|
|
|
nm[0xdb]="DQT" ;
|
|
|
|
|
nm[0xdd]="DRI" ;
|
|
|
|
|
nm[0xfe]="COM" ;
|
|
|
|
|
std::string nm[256];
|
|
|
|
|
nm[0xd8] = "SOI";
|
|
|
|
|
nm[0xd9] = "EOI";
|
|
|
|
|
nm[0xda] = "SOS";
|
|
|
|
|
nm[0xdb] = "DQT";
|
|
|
|
|
nm[0xdd] = "DRI";
|
|
|
|
|
nm[0xfe] = "COM";
|
|
|
|
|
|
|
|
|
|
// 0xe0 .. 0xef are APPn
|
|
|
|
|
// 0xc0 .. 0xcf are SOFn (except 4)
|
|
|
|
|
nm[0xc4]="DHT" ;
|
|
|
|
|
for ( int i = 0 ; i <= 15 ; i++ ) {
|
|
|
|
|
nm[0xc4] = "DHT";
|
|
|
|
|
for (int i = 0; i <= 15; i++) {
|
|
|
|
|
char MN[10];
|
|
|
|
|
sprintf(MN,"APP%d",i);
|
|
|
|
|
nm[0xe0+i] = MN;
|
|
|
|
|
if ( i != 4 ) {
|
|
|
|
|
sprintf(MN,"SOF%d",i);
|
|
|
|
|
nm[0xc0+i] = MN;
|
|
|
|
|
sprintf(MN, "APP%d", i);
|
|
|
|
|
nm[0xe0 + i] = MN;
|
|
|
|
|
if (i != 4) {
|
|
|
|
|
sprintf(MN, "SOF%d", i);
|
|
|
|
|
nm[0xc0 + i] = MN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// which markers have a length field?
|
|
|
|
|
bool mHasLength[256];
|
|
|
|
|
for ( int i = 0 ; i < 256 ; i ++ )
|
|
|
|
|
mHasLength[i]
|
|
|
|
|
= ( i >= sof0_ && i <= sof15_)
|
|
|
|
|
|| ( i >= app0_ && i <= (app0_ | 0x0F))
|
|
|
|
|
|| ( i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_ )
|
|
|
|
|
;
|
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
|
|
|
mHasLength[i] = (i >= sof0_ && i <= sof15_) || (i >= app0_ && i <= (app0_ | 0x0F)) ||
|
|
|
|
|
(i == dht_ || i == dqt_ || i == dri_ || i == com_ || i == sos_);
|
|
|
|
|
|
|
|
|
|
// Container for the signature
|
|
|
|
|
bool bExtXMP = false;
|
|
|
|
@ -613,15 +613,16 @@ namespace Exiv2 {
|
|
|
|
|
|
|
|
|
|
// Read section marker
|
|
|
|
|
int marker = advanceToMarker();
|
|
|
|
|
if (marker < 0) throw Error(kerNotAJpeg);
|
|
|
|
|
if (marker < 0)
|
|
|
|
|
throw Error(kerNotAJpeg);
|
|
|
|
|
|
|
|
|
|
bool done = false;
|
|
|
|
|
bool first= true;
|
|
|
|
|
bool first = true;
|
|
|
|
|
while (!done) {
|
|
|
|
|
// print marker bytes
|
|
|
|
|
if ( first && bPrint ) {
|
|
|
|
|
if (first && bPrint) {
|
|
|
|
|
out << "STRUCTURE OF JPEG FILE: " << io_->path() << std::endl;
|
|
|
|
|
out << " address | marker | length | data" << std::endl ;
|
|
|
|
|
out << " address | marker | length | data" << std::endl;
|
|
|
|
|
REPORT_MARKER;
|
|
|
|
|
}
|
|
|
|
|
first = false;
|
|
|
|
@ -630,15 +631,18 @@ namespace Exiv2 {
|
|
|
|
|
// Read size and signature
|
|
|
|
|
std::memset(buf.pData_, 0x0, buf.size_);
|
|
|
|
|
bufRead = io_->read(buf.pData_, bufMinSize);
|
|
|
|
|
if (io_->error()) throw Error(kerFailedToReadImageData);
|
|
|
|
|
if (bufRead < 2) throw Error(kerNotAJpeg);
|
|
|
|
|
uint16_t size = mHasLength[marker] ? getUShort(buf.pData_, bigEndian) : 0 ;
|
|
|
|
|
if ( bPrint && mHasLength[marker] ) out << Internal::stringFormat(" | %7d ", size);
|
|
|
|
|
if (io_->error())
|
|
|
|
|
throw Error(kerFailedToReadImageData);
|
|
|
|
|
if (bufRead < 2)
|
|
|
|
|
throw Error(kerNotAJpeg);
|
|
|
|
|
uint16_t size = mHasLength[marker] ? getUShort(buf.pData_, bigEndian) : 0;
|
|
|
|
|
if (bPrint && mHasLength[marker])
|
|
|
|
|
out << Internal::stringFormat(" | %7d ", size);
|
|
|
|
|
|
|
|
|
|
// print signature for APPn
|
|
|
|
|
if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
|
|
|
|
|
// http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf p75
|
|
|
|
|
const char* signature = (const char*) buf.pData_+2;
|
|
|
|
|
const char* signature = (const char*)buf.pData_ + 2;
|
|
|
|
|
|
|
|
|
|
// 728 rmills@rmillsmbp:~/gnu/exiv2/ttt $ exiv2 -pS test/data/exiv2-bug922.jpg
|
|
|
|
|
// STRUCTURE OF JPEG FILE: test/data/exiv2-bug922.jpg
|
|
|
|
@ -647,13 +651,13 @@ namespace Exiv2 {
|
|
|
|
|
// 2 | 0xe1 APP1 | 911 | Exif..MM.*.......%.........#....
|
|
|
|
|
// 915 | 0xe1 APP1 | 870 | http://ns.adobe.com/xap/1.0/.<x:
|
|
|
|
|
// 1787 | 0xe1 APP1 | 65460 | http://ns.adobe.com/xmp/extensio
|
|
|
|
|
if ( option == kpsXMP && std::string(signature).find("http://ns.adobe.com/x")== 0 ) {
|
|
|
|
|
if (option == kpsXMP && std::string(signature).find("http://ns.adobe.com/x") == 0) {
|
|
|
|
|
// extract XMP
|
|
|
|
|
if ( size > 0 ) {
|
|
|
|
|
io_->seek(-bufRead , BasicIo::cur);
|
|
|
|
|
byte* xmp = new byte[size+1];
|
|
|
|
|
io_->read(xmp,size);
|
|
|
|
|
int start = 0 ;
|
|
|
|
|
if (size > 0) {
|
|
|
|
|
io_->seek(-bufRead, BasicIo::cur);
|
|
|
|
|
byte* xmp = new byte[size + 1];
|
|
|
|
|
io_->read(xmp, size);
|
|
|
|
|
int start = 0;
|
|
|
|
|
|
|
|
|
|
// http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf
|
|
|
|
|
// if we find HasExtendedXMP, set the flag and ignore this block
|
|
|
|
@ -662,60 +666,61 @@ namespace Exiv2 {
|
|
|
|
|
// we could implement out of sequence with a dictionary of sequence/offset
|
|
|
|
|
// and dumping the XMP in a post read operation similar to kpsIptcErase
|
|
|
|
|
// for the moment, dumping 'on the fly' is working fine
|
|
|
|
|
if ( ! bExtXMP ) {
|
|
|
|
|
while (xmp[start]) start++;
|
|
|
|
|
if (!bExtXMP) {
|
|
|
|
|
while (xmp[start])
|
|
|
|
|
start++;
|
|
|
|
|
if ( ::strstr((char*)xmp+start,"HasExtendedXMP") ) {
|
|
|
|
|
start = size ; // ignore this packet, we'll get on the next time around
|
|
|
|
|
start++;
|
|
|
|
|
if (::strstr((char*)xmp + start, "HasExtendedXMP")) {
|
|
|
|
|
start = size; // ignore this packet, we'll get on the next time around
|
|
|
|
|
bExtXMP = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
start = 2+35+32+4+4; // Adobe Spec, p19
|
|
|
|
|
start = 2 + 35 + 32 + 4 + 4; // Adobe Spec, p19
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.write((const char*)(xmp+start),size-start);
|
|
|
|
|
delete [] xmp;
|
|
|
|
|
out.write((const char*)(xmp + start), size - start);
|
|
|
|
|
delete[] xmp;
|
|
|
|
|
bufRead = size;
|
|
|
|
|
done = !bExtXMP;
|
|
|
|
|
}
|
|
|
|
|
} else if ( option == kpsIccProfile && std::strcmp(signature,iccId_) == 0 ) {
|
|
|
|
|
} else if (option == kpsIccProfile && std::strcmp(signature, iccId_) == 0) {
|
|
|
|
|
// extract ICCProfile
|
|
|
|
|
if ( size > 0 ) {
|
|
|
|
|
if (size > 0) {
|
|
|
|
|
io_->seek(-bufRead, BasicIo::cur); // back to buffer (after marker)
|
|
|
|
|
io_->seek( 14+2, BasicIo::cur); // step over header
|
|
|
|
|
DataBuf icc(size-(14+2));
|
|
|
|
|
io_->read( icc.pData_,icc.size_);
|
|
|
|
|
out.write((const char*)icc.pData_,icc.size_);
|
|
|
|
|
io_->seek(14 + 2, BasicIo::cur); // step over header
|
|
|
|
|
DataBuf icc(size - (14 + 2));
|
|
|
|
|
io_->read(icc.pData_, icc.size_);
|
|
|
|
|
out.write((const char*)icc.pData_, icc.size_);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
std::cout << "iccProfile size = " << icc.size_ << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
bufRead = size;
|
|
|
|
|
}
|
|
|
|
|
} else if ( option == kpsIptcErase && std::strcmp(signature,"Photoshop 3.0") == 0 ) {
|
|
|
|
|
} else if (option == kpsIptcErase && std::strcmp(signature, "Photoshop 3.0") == 0) {
|
|
|
|
|
// delete IPTC data segment from JPEG
|
|
|
|
|
if ( size > 0 ) {
|
|
|
|
|
io_->seek(-bufRead , BasicIo::cur);
|
|
|
|
|
if (size > 0) {
|
|
|
|
|
io_->seek(-bufRead, BasicIo::cur);
|
|
|
|
|
iptcDataSegs.push_back(io_->tell());
|
|
|
|
|
iptcDataSegs.push_back(size);
|
|
|
|
|
}
|
|
|
|
|
} else if ( bPrint ) {
|
|
|
|
|
out << "| " << Internal::binaryToString(buf,size>32?32:size,size>0?2:0);
|
|
|
|
|
if ( std::strcmp(signature,iccId_) == 0 ) {
|
|
|
|
|
int chunk = (int) signature[12];
|
|
|
|
|
int chunks = (int) signature[13];
|
|
|
|
|
out << Internal::stringFormat(" chunk %d/%d",chunk,chunks);
|
|
|
|
|
} else if (bPrint) {
|
|
|
|
|
out << "| " << Internal::binaryToString(buf, size > 32 ? 32 : size, size > 0 ? 2 : 0);
|
|
|
|
|
if (std::strcmp(signature, iccId_) == 0) {
|
|
|
|
|
int chunk = (int)signature[12];
|
|
|
|
|
int chunks = (int)signature[13];
|
|
|
|
|
out << Internal::stringFormat(" chunk %d/%d", chunk, chunks);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for MPF: http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
|
|
|
|
|
// for FLIR: http://owl.phy.queensu.ca/~phil/exiftool/TagNames/FLIR.html
|
|
|
|
|
bool bFlir = option == kpsRecursive && marker == (app0_+1) && std::strcmp(signature,"FLIR")==0;
|
|
|
|
|
bool bExif = option == kpsRecursive && marker == (app0_+1) && std::strcmp(signature,"Exif")==0;
|
|
|
|
|
bool bMPF = option == kpsRecursive && marker == (app0_+2) && std::strcmp(signature,"MPF")==0;
|
|
|
|
|
bool bPS = option == kpsRecursive && std::strcmp(signature,"Photoshop 3.0")==0;
|
|
|
|
|
if( bFlir || bExif || bMPF || bPS ) {
|
|
|
|
|
bool bFlir = option == kpsRecursive && marker == (app0_ + 1) && std::strcmp(signature, "FLIR") == 0;
|
|
|
|
|
bool bExif = option == kpsRecursive && marker == (app0_ + 1) && std::strcmp(signature, "Exif") == 0;
|
|
|
|
|
bool bMPF = option == kpsRecursive && marker == (app0_ + 2) && std::strcmp(signature, "MPF") == 0;
|
|
|
|
|
bool bPS = option == kpsRecursive && std::strcmp(signature, "Photoshop 3.0") == 0;
|
|
|
|
|
if (bFlir || bExif || bMPF || bPS) {
|
|
|
|
|
// extract Exif data block which is tiff formatted
|
|
|
|
|
if ( size > 0 ) {
|
|
|
|
|
if (size > 0) {
|
|
|
|
|
out << std::endl;
|
|
|
|
|
|
|
|
|
|
// allocate storage and current file position
|
|
|
|
@ -723,18 +728,18 @@ namespace Exiv2 {
|
|
|
|
|
uint32_t restore = io_->tell();
|
|
|
|
|
|
|
|
|
|
// copy the data to memory
|
|
|
|
|
io_->seek(-bufRead , BasicIo::cur);
|
|
|
|
|
io_->read(exif,size);
|
|
|
|
|
uint32_t start = std::strcmp(signature,"Exif")==0 ? 8 : 6;
|
|
|
|
|
uint32_t max = (uint32_t) size -1;
|
|
|
|
|
io_->seek(-bufRead, BasicIo::cur);
|
|
|
|
|
io_->read(exif, size);
|
|
|
|
|
uint32_t start = std::strcmp(signature, "Exif") == 0 ? 8 : 6;
|
|
|
|
|
uint32_t max = (uint32_t)size - 1;
|
|
|
|
|
|
|
|
|
|
// is this an fff block?
|
|
|
|
|
if ( bFlir ) {
|
|
|
|
|
start = 0 ;
|
|
|
|
|
if (bFlir) {
|
|
|
|
|
start = 0;
|
|
|
|
|
bFlir = false;
|
|
|
|
|
while ( start < max ) {
|
|
|
|
|
if ( std::strcmp((const char*)(exif+start),"FFF")==0 ) {
|
|
|
|
|
bFlir = true ;
|
|
|
|
|
while (start < max) {
|
|
|
|
|
if (std::strcmp((const char*)(exif + start), "FFF") == 0) {
|
|
|
|
|
bFlir = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
start++;
|
|
|
|
@ -743,43 +748,49 @@ namespace Exiv2 {
|
|
|
|
|
|
|
|
|
|
// there is a header in FLIR, followed by a tiff block
|
|
|
|
|
// Hunt down the tiff using brute force
|
|
|
|
|
if ( bFlir ) {
|
|
|
|
|
if (bFlir) {
|
|
|
|
|
// FLIRFILEHEAD* pFFF = (FLIRFILEHEAD*) (exif+start) ;
|
|
|
|
|
while ( start < max ) {
|
|
|
|
|
if ( exif[start] == 'I' && exif[start+1] == 'I' ) break;
|
|
|
|
|
if ( exif[start] == 'M' && exif[start+1] == 'M' ) break;
|
|
|
|
|
while (start < max) {
|
|
|
|
|
if (exif[start] == 'I' && exif[start + 1] == 'I')
|
|
|
|
|
break;
|
|
|
|
|
if (exif[start] == 'M' && exif[start + 1] == 'M')
|
|
|
|
|
break;
|
|
|
|
|
start++;
|
|
|
|
|
}
|
|
|
|
|
if ( start < max ) std::cout << " FFF start = " << start << std::endl ;
|
|
|
|
|
if (start < max)
|
|
|
|
|
std::cout << " FFF start = " << start << std::endl;
|
|
|
|
|
// << " index = " << pFFF->dwIndexOff << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( bPS ) {
|
|
|
|
|
IptcData::printStructure(out,exif,size,depth);
|
|
|
|
|
if (bPS) {
|
|
|
|
|
IptcData::printStructure(out, exif, size, depth);
|
|
|
|
|
} else {
|
|
|
|
|
// create a copy on write memio object with the data, then print the structure
|
|
|
|
|
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif+start,size-start));
|
|
|
|
|
if ( start < max ) printTiffStructure(*p,out,option,depth);
|
|
|
|
|
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif + start, size - start));
|
|
|
|
|
if (start < max)
|
|
|
|
|
printTiffStructure(*p, out, option, depth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// restore and clean up
|
|
|
|
|
io_->seek(restore,Exiv2::BasicIo::beg);
|
|
|
|
|
delete [] exif;
|
|
|
|
|
io_->seek(restore, Exiv2::BasicIo::beg);
|
|
|
|
|
delete[] exif;
|
|
|
|
|
bLF = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// print COM marker
|
|
|
|
|
if ( bPrint && marker == com_ ) {
|
|
|
|
|
int n = (size-2)>32?32:size-2; // size includes 2 for the two bytes for size!
|
|
|
|
|
out << "| " << Internal::binaryToString(buf,n,2); // start after the two bytes
|
|
|
|
|
if (bPrint && marker == com_) {
|
|
|
|
|
int n = (size - 2) > 32 ? 32 : size - 2; // size includes 2 for the two bytes for size!
|
|
|
|
|
out << "| " << Internal::binaryToString(buf, n, 2); // start after the two bytes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip the segment if the size is known
|
|
|
|
|
if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(kerFailedToReadImageData);
|
|
|
|
|
if (io_->seek(size - bufRead, BasicIo::cur))
|
|
|
|
|
throw Error(kerFailedToReadImageData);
|
|
|
|
|
|
|
|
|
|
if ( bLF ) out << std::endl;
|
|
|
|
|
if (bLF)
|
|
|
|
|
out << std::endl;
|
|
|
|
|
|
|
|
|
|
if (marker != sos_) {
|
|
|
|
|
// Read the beginning of the next segment
|
|
|
|
@ -787,34 +798,39 @@ namespace Exiv2 {
|
|
|
|
|
REPORT_MARKER;
|
|
|
|
|
}
|
|
|
|
|
done |= marker == eoi_ || marker == sos_;
|
|
|
|
|
if ( done && bPrint ) out << std::endl;
|
|
|
|
|
if (done && bPrint)
|
|
|
|
|
out << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( option == kpsIptcErase && iptcDataSegs.size() ) {
|
|
|
|
|
if (option == kpsIptcErase && iptcDataSegs.size()) {
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
std::cout << "iptc data blocks: " << iptcDataSegs.size() << std::endl;
|
|
|
|
|
uint32_t toggle = 0 ;
|
|
|
|
|
for ( Uint32Vector_i i = iptcDataSegs.begin(); i != iptcDataSegs.end() ; i++ ) {
|
|
|
|
|
std::cout << *i ;
|
|
|
|
|
if ( toggle++ % 2 ) std::cout << std::endl; else std::cout << ' ' ;
|
|
|
|
|
uint32_t toggle = 0;
|
|
|
|
|
for (Uint32Vector_i i = iptcDataSegs.begin(); i != iptcDataSegs.end(); i++) {
|
|
|
|
|
std::cout << *i;
|
|
|
|
|
if (toggle++ % 2)
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
else
|
|
|
|
|
std::cout << ' ';
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
uint32_t count = (uint32_t) iptcDataSegs.size();
|
|
|
|
|
uint32_t count = (uint32_t)iptcDataSegs.size();
|
|
|
|
|
|
|
|
|
|
// figure out which blocks to copy
|
|
|
|
|
uint64_t* pos = new uint64_t[count+2];
|
|
|
|
|
pos[0] = 0 ;
|
|
|
|
|
uint64_t* pos = new uint64_t[count + 2];
|
|
|
|
|
pos[0] = 0;
|
|
|
|
|
// copy the data that is not iptc
|
|
|
|
|
Uint32Vector_i it = iptcDataSegs.begin();
|
|
|
|
|
for ( uint64_t i = 0 ; i < count ; i++ ) {
|
|
|
|
|
bool bOdd = (i%2)!=0;
|
|
|
|
|
for (uint64_t i = 0; i < count; i++) {
|
|
|
|
|
bool bOdd = (i % 2) != 0;
|
|
|
|
|
bool bEven = !bOdd;
|
|
|
|
|
pos[i+1] = bEven ? *it : pos[i] + *it;
|
|
|
|
|
pos[i + 1] = bEven ? *it : pos[i] + *it;
|
|
|
|
|
it++;
|
|
|
|
|
}
|
|
|
|
|
pos[count+1] = io_->size() - pos[count];
|
|
|
|
|
pos[count + 1] = io_->size() - pos[count];
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
for ( uint64_t i = 0 ; i < count+2 ; i++ ) std::cout << pos[i] << " " ;
|
|
|
|
|
for (uint64_t i = 0; i < count + 2; i++)
|
|
|
|
|
std::cout << pos[i] << " ";
|
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
// $ dd bs=1 skip=$((0)) count=$((13164)) if=ETH0138028.jpg of=E1.jpg
|
|
|
|
@ -825,22 +841,23 @@ namespace Exiv2 {
|
|
|
|
|
// binary copy io_ to a temporary file
|
|
|
|
|
BasicIo::AutoPtr tempIo(new MemIo);
|
|
|
|
|
|
|
|
|
|
assert (tempIo.get() != 0);
|
|
|
|
|
for ( uint64_t i = 0 ; i < (count/2)+1 ; i++ ) {
|
|
|
|
|
uint64_t start = pos[2*i]+2 ; // step JPG 2 byte marker
|
|
|
|
|
if ( start == 2 ) start = 0 ; // read the file 2 byte SOI
|
|
|
|
|
long length = (long) (pos[2*i+1] - start) ;
|
|
|
|
|
if ( length ) {
|
|
|
|
|
assert(tempIo.get() != 0);
|
|
|
|
|
for (uint64_t i = 0; i < (count / 2) + 1; i++) {
|
|
|
|
|
uint64_t start = pos[2 * i] + 2; // step JPG 2 byte marker
|
|
|
|
|
if (start == 2)
|
|
|
|
|
start = 0; // read the file 2 byte SOI
|
|
|
|
|
long length = (long)(pos[2 * i + 1] - start);
|
|
|
|
|
if (length) {
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
std::cout << start <<":"<< length << std::endl;
|
|
|
|
|
std::cout << start << ":" << length << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
io_->seek(start,BasicIo::beg);
|
|
|
|
|
io_->seek(start, BasicIo::beg);
|
|
|
|
|
DataBuf buf(length);
|
|
|
|
|
io_->read(buf.pData_,buf.size_);
|
|
|
|
|
tempIo->write(buf.pData_,buf.size_);
|
|
|
|
|
io_->read(buf.pData_, buf.size_);
|
|
|
|
|
tempIo->write(buf.pData_, buf.size_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete [] pos;
|
|
|
|
|
delete[] pos;
|
|
|
|
|
|
|
|
|
|
io_->seek(0, BasicIo::beg);
|
|
|
|
|
io_->transfer(*tempIo); // may throw
|
|
|
|
|