open image files on demand rather than keeping them open: bug #393
This commit is contained in:
parent
134d57c220
commit
58f7d669dc
@ -566,7 +566,6 @@ namespace Action {
|
||||
return -2;
|
||||
}
|
||||
int rc = image->readMetadata();
|
||||
image->detach();
|
||||
if (rc) {
|
||||
std::cerr << path_
|
||||
<< ": Could not read metadata\n";
|
||||
@ -975,7 +974,6 @@ namespace {
|
||||
return -2;
|
||||
}
|
||||
int rc = sourceImage->readMetadata();
|
||||
sourceImage->detach();
|
||||
if (rc) {
|
||||
std::cerr << source
|
||||
<< ": Could not read metadata\n";
|
||||
|
||||
208
src/image.cpp
208
src/image.cpp
@ -72,7 +72,7 @@ namespace Exiv2 {
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
Image::AutoPtr newExvInstance(const std::string& path, FILE* fp);
|
||||
Image::AutoPtr newExvInstance(const std::string& path, bool create);
|
||||
//! Check if the file ifp is an EXV file.
|
||||
bool isExvType(FILE* ifp, bool advance);
|
||||
/*!
|
||||
@ -80,7 +80,7 @@ namespace Exiv2 {
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
Image::AutoPtr newJpegInstance(const std::string& path, FILE* fp);
|
||||
Image::AutoPtr newJpegInstance(const std::string& path, bool create);
|
||||
//! Check if the file ifp is a JPEG image.
|
||||
bool isJpegType(FILE* ifp, bool advance);
|
||||
|
||||
@ -110,35 +110,34 @@ namespace Exiv2 {
|
||||
|
||||
Image::Type ImageFactory::getType(const std::string& path) const
|
||||
{
|
||||
FILE* ifp = fopen(path.c_str(), "rb");
|
||||
if (!ifp) return Image::none;
|
||||
FileCloser closer(fopen(path.c_str(), "rb"));
|
||||
if (!closer.fp_) return Image::none;
|
||||
|
||||
Image::Type type = Image::none;
|
||||
Registry::const_iterator b = registry_.begin();
|
||||
Registry::const_iterator e = registry_.end();
|
||||
for (Registry::const_iterator i = b; i != e; ++i)
|
||||
{
|
||||
if (i->second.isThisType(ifp, false)) {
|
||||
if (i->second.isThisType(closer.fp_, false)) {
|
||||
type = i->first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(ifp);
|
||||
return type;
|
||||
} // ImageFactory::getType
|
||||
|
||||
Image::AutoPtr ImageFactory::open(const std::string& path) const
|
||||
{
|
||||
Image::AutoPtr image;
|
||||
FILE* ifp = fopen(path.c_str(), "rb");
|
||||
if (!ifp) return image;
|
||||
FileCloser closer(fopen(path.c_str(), "rb"));
|
||||
if (!closer.fp_) return image;
|
||||
|
||||
Registry::const_iterator b = registry_.begin();
|
||||
Registry::const_iterator e = registry_.end();
|
||||
for (Registry::const_iterator i = b; i != e; ++i)
|
||||
{
|
||||
if (i->second.isThisType(ifp, false)) {
|
||||
image = Image::AutoPtr(i->second.newInstance(path, ifp));
|
||||
if (i->second.isThisType(closer.fp_, false)) {
|
||||
image = Image::AutoPtr(i->second.newInstance(path, false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -150,10 +149,9 @@ namespace Exiv2 {
|
||||
{
|
||||
Registry::const_iterator i = registry_.find(type);
|
||||
if (i != registry_.end()) {
|
||||
return i->second.newInstance(path, 0);
|
||||
return i->second.newInstance(path, true);
|
||||
}
|
||||
Image::AutoPtr p;
|
||||
return p;
|
||||
return Image::AutoPtr();
|
||||
} // ImageFactory::create
|
||||
|
||||
|
||||
@ -171,33 +169,22 @@ namespace Exiv2 {
|
||||
|
||||
JpegBase::JpegBase(const std::string& path, bool create,
|
||||
const byte initData[], size_t dataSize)
|
||||
: fp_(0), path_(path),
|
||||
sizeExifData_(0), pExifData_(0), sizeIptcData_(0), pIptcData_(0)
|
||||
: path_(path), sizeExifData_(0), pExifData_(0),
|
||||
sizeIptcData_(0), pIptcData_(0)
|
||||
{
|
||||
if (create) {
|
||||
fp_ = fopen(path.c_str(), "w+b");
|
||||
if (fp_) initFile(initData, dataSize);
|
||||
FILE* fp = fopen(path.c_str(), "w+b");
|
||||
if (fp) {
|
||||
initFile(fp, initData, dataSize);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fp_ = fopen(path.c_str(), "rb");
|
||||
}
|
||||
}
|
||||
|
||||
JpegBase::JpegBase(const std::string& path, FILE* fp)
|
||||
: fp_(fp), path_(path), sizeExifData_(0),
|
||||
pExifData_(0), sizeIptcData_(0), pIptcData_(0)
|
||||
{
|
||||
assert(fp_);
|
||||
}
|
||||
|
||||
int JpegBase::initFile(const byte initData[], size_t dataSize)
|
||||
int JpegBase::initFile(FILE* fp, const byte initData[], size_t dataSize)
|
||||
{
|
||||
if (!fp_ || ferror(fp_)) return 4;
|
||||
if (fwrite(initData, 1, dataSize, fp_) != dataSize) {
|
||||
return 4;
|
||||
}
|
||||
fseek(fp_, 0, SEEK_SET);
|
||||
if (ferror(fp_)) {
|
||||
if (!fp || ferror(fp)) return 4;
|
||||
if (fwrite(initData, 1, dataSize, fp) != dataSize) {
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
@ -205,23 +192,15 @@ namespace Exiv2 {
|
||||
|
||||
JpegBase::~JpegBase()
|
||||
{
|
||||
if (fp_) fclose(fp_);
|
||||
delete[] pExifData_;
|
||||
delete[] pIptcData_;
|
||||
}
|
||||
|
||||
int JpegBase::detach()
|
||||
{
|
||||
if (fp_) fclose(fp_);
|
||||
fp_ = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool JpegBase::good() const
|
||||
{
|
||||
if (fp_ == 0) return false;
|
||||
rewind(fp_);
|
||||
return isThisType(fp_, false);
|
||||
FileCloser closer(fopen(path_.c_str(), "rb"));
|
||||
if (closer.fp_ == 0 ) return false;
|
||||
return isThisType(closer.fp_, false);
|
||||
}
|
||||
|
||||
void JpegBase::clearMetadata()
|
||||
@ -282,16 +261,16 @@ namespace Exiv2 {
|
||||
setComment(image.comment());
|
||||
}
|
||||
|
||||
int JpegBase::advanceToMarker() const
|
||||
int JpegBase::advanceToMarker(FILE *fp) const
|
||||
{
|
||||
int c = -1;
|
||||
// Skips potential padding between markers
|
||||
while ((c=fgetc(fp_)) != 0xff) {
|
||||
while ((c=fgetc(fp)) != 0xff) {
|
||||
if (c == EOF) return -1;
|
||||
}
|
||||
|
||||
// Markers can start with any number of 0xff
|
||||
while ((c=fgetc(fp_)) == 0xff) {
|
||||
while ((c=fgetc(fp)) == 0xff) {
|
||||
if (c == EOF) return -1;
|
||||
}
|
||||
return c;
|
||||
@ -299,12 +278,12 @@ namespace Exiv2 {
|
||||
|
||||
int JpegBase::readMetadata()
|
||||
{
|
||||
if (!fp_) return 1;
|
||||
rewind(fp_);
|
||||
FileCloser closer(fopen(path_.c_str(), "rb"));
|
||||
if (!closer.fp_) return 1;
|
||||
|
||||
// Ensure that this is the correct image type
|
||||
if (!isThisType(fp_, true)) {
|
||||
if (ferror(fp_) || feof(fp_)) return 1;
|
||||
if (!isThisType(closer.fp_, true)) {
|
||||
if (ferror(closer.fp_) || feof(closer.fp_)) return 1;
|
||||
return 2;
|
||||
}
|
||||
clearMetadata();
|
||||
@ -314,23 +293,23 @@ namespace Exiv2 {
|
||||
DataBuf buf(bufMinSize);
|
||||
|
||||
// Read section marker
|
||||
int marker = advanceToMarker();
|
||||
int marker = advanceToMarker(closer.fp_);
|
||||
if (marker < 0) return 2;
|
||||
|
||||
while (marker != sos_ && marker != eoi_ && search > 0) {
|
||||
// Read size and signature (ok if this hits EOF)
|
||||
bufRead = (long)fread(buf.pData_, 1, bufMinSize, fp_);
|
||||
if (ferror(fp_)) return 1;
|
||||
bufRead = (long)fread(buf.pData_, 1, bufMinSize, closer.fp_);
|
||||
if (ferror(closer.fp_)) return 1;
|
||||
uint16_t size = getUShort(buf.pData_, bigEndian);
|
||||
|
||||
if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
|
||||
if (size < 8) return 2;
|
||||
// Seek to begining and read the Exif data
|
||||
fseek(fp_, 8-bufRead, SEEK_CUR);
|
||||
fseek(closer.fp_, 8-bufRead, SEEK_CUR);
|
||||
long sizeExifData = size - 8;
|
||||
pExifData_ = new byte[sizeExifData];
|
||||
fread(pExifData_, 1, sizeExifData, fp_);
|
||||
if (ferror(fp_) || feof(fp_)) {
|
||||
fread(pExifData_, 1, sizeExifData, closer.fp_);
|
||||
if (ferror(closer.fp_) || feof(closer.fp_)) {
|
||||
delete[] pExifData_;
|
||||
pExifData_ = 0;
|
||||
return 1;
|
||||
@ -342,10 +321,10 @@ namespace Exiv2 {
|
||||
else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) == 0) {
|
||||
if (size < 16) return 2;
|
||||
// Read the rest of the APP13 segment
|
||||
// needed if bufMinSize!=16: fseek(fp_, 16-bufRead, SEEK_CUR);
|
||||
// needed if bufMinSize!=16: fseek(closer.fp_, 16-bufRead, SEEK_CUR);
|
||||
DataBuf psData(size - 16);
|
||||
fread(psData.pData_, 1, psData.size_, fp_);
|
||||
if (ferror(fp_) || feof(fp_)) return 1;
|
||||
fread(psData.pData_, 1, psData.size_, closer.fp_);
|
||||
if (ferror(closer.fp_) || feof(closer.fp_)) return 1;
|
||||
const byte *record = 0;
|
||||
uint16_t sizeIptc = 0;
|
||||
uint16_t sizeHdr = 0;
|
||||
@ -365,10 +344,10 @@ namespace Exiv2 {
|
||||
// Jpegs can have multiple comments, but for now only read
|
||||
// the first one (most jpegs only have one anyway). Comments
|
||||
// are simple single byte ISO-8859-1 strings.
|
||||
fseek(fp_, 2-bufRead, SEEK_CUR);
|
||||
fseek(closer.fp_, 2-bufRead, SEEK_CUR);
|
||||
buf.alloc(size-2);
|
||||
fread(buf.pData_, 1, size-2, fp_);
|
||||
if (ferror(fp_) || feof(fp_)) return 1;
|
||||
fread(buf.pData_, 1, size-2, closer.fp_);
|
||||
if (ferror(closer.fp_) || feof(closer.fp_)) return 1;
|
||||
comment_.assign(reinterpret_cast<char*>(buf.pData_), size-2);
|
||||
while ( comment_.length()
|
||||
&& comment_.at(comment_.length()-1) == '\0') {
|
||||
@ -379,10 +358,10 @@ namespace Exiv2 {
|
||||
else {
|
||||
if (size < 2) return 2;
|
||||
// Skip the remainder of the unknown segment
|
||||
if (fseek(fp_, size-bufRead, SEEK_CUR)) return 2;
|
||||
if (fseek(closer.fp_, size-bufRead, SEEK_CUR)) return 2;
|
||||
}
|
||||
// Read the beginning of the next segment
|
||||
marker = advanceToMarker();
|
||||
marker = advanceToMarker(closer.fp_);
|
||||
if (marker < 0) return 2;
|
||||
}
|
||||
return 0;
|
||||
@ -434,18 +413,18 @@ namespace Exiv2 {
|
||||
|
||||
int JpegBase::writeMetadata()
|
||||
{
|
||||
if (!fp_) return 1;
|
||||
rewind(fp_);
|
||||
FileCloser reader(fopen(path_.c_str(), "rb"));
|
||||
if (!reader.fp_) return 1;
|
||||
|
||||
// Write the output to a temporary file
|
||||
pid_t pid = getpid();
|
||||
std::string tmpname = path_ + toString(pid);
|
||||
FILE* ofl = fopen(tmpname.c_str(), "wb");
|
||||
if (!ofl) return -3;
|
||||
FileCloser writer(fopen(tmpname.c_str(), "wb"));
|
||||
if (!writer.fp_) return -3;
|
||||
|
||||
int rc = doWriteMetadata(ofl);
|
||||
fclose(ofl);
|
||||
fclose(fp_);
|
||||
int rc = doWriteMetadata(reader.fp_, writer.fp_);
|
||||
writer.close();
|
||||
reader.close();
|
||||
if (rc == 0) {
|
||||
// Workaround for MSVCRT rename that does not overwrite existing files
|
||||
if (remove(path_.c_str()) != 0) rc = -4;
|
||||
@ -458,26 +437,24 @@ namespace Exiv2 {
|
||||
// remove temporary file
|
||||
remove(tmpname.c_str());
|
||||
}
|
||||
// Reopen the file
|
||||
fp_ = fopen(path_.c_str(), "rb");
|
||||
if (!fp_) return -1;
|
||||
|
||||
return rc;
|
||||
} // JpegBase::writeMetadata
|
||||
|
||||
int JpegBase::doWriteMetadata(FILE* ofp) const
|
||||
int JpegBase::doWriteMetadata(FILE *ifp, FILE* ofp) const
|
||||
{
|
||||
if (!fp_) return 1;
|
||||
if (!ifp) return 1;
|
||||
if (!ofp) return 4;
|
||||
|
||||
// Ensure that this is the correct image type
|
||||
if (!isThisType(fp_, true)) {
|
||||
if (ferror(fp_) || feof(fp_)) return 1;
|
||||
if (!isThisType(ifp, true)) {
|
||||
if (ferror(ifp) || feof(ifp)) return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
const long bufMinSize = 16;
|
||||
long bufRead = 0;
|
||||
DataBuf buf(bufMinSize);
|
||||
const long seek = ftell(fp_);
|
||||
const long seek = ftell(ifp);
|
||||
int count = 0;
|
||||
int search = 0;
|
||||
int insertPos = 0;
|
||||
@ -490,7 +467,7 @@ namespace Exiv2 {
|
||||
if (writeHeader(ofp)) return 4;
|
||||
|
||||
// Read section marker
|
||||
int marker = advanceToMarker();
|
||||
int marker = advanceToMarker(ifp);
|
||||
if (marker < 0) return 2;
|
||||
|
||||
// First find segments of interest. Normally app0 is first and we want
|
||||
@ -498,45 +475,44 @@ namespace Exiv2 {
|
||||
// don't bother.
|
||||
while (marker != sos_ && marker != eoi_ && search < 3) {
|
||||
// Read size and signature (ok if this hits EOF)
|
||||
bufRead = (long)fread(buf.pData_, 1, bufMinSize, fp_);
|
||||
if (ferror(fp_)) return 1;
|
||||
bufRead = (long)fread(buf.pData_, 1, bufMinSize, ifp);
|
||||
if (ferror(ifp)) return 1;
|
||||
uint16_t size = getUShort(buf.pData_, bigEndian);
|
||||
|
||||
if (marker == app0_) {
|
||||
if (size < 2) return 2;
|
||||
insertPos = count + 1;
|
||||
if (fseek(fp_, size-bufRead, SEEK_CUR)) return 2;
|
||||
if (fseek(ifp, size-bufRead, SEEK_CUR)) return 2;
|
||||
}
|
||||
else if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
|
||||
if (size < 8) return 2;
|
||||
skipApp1Exif = count;
|
||||
++search;
|
||||
if (fseek(fp_, size-bufRead, SEEK_CUR)) return 2;
|
||||
if (fseek(ifp, size-bufRead, SEEK_CUR)) return 2;
|
||||
}
|
||||
else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) == 0) {
|
||||
if (size < 16) return 2;
|
||||
skipApp13Ps3 = count;
|
||||
++search;
|
||||
// needed if bufMinSize!=16: fseek(fp_, 16-bufRead, SEEK_CUR);
|
||||
// needed if bufMinSize!=16: fseek(ifp, 16-bufRead, SEEK_CUR);
|
||||
psData.alloc(size - 16);
|
||||
// Load PS data now to allow reinsertion at any point
|
||||
fread(psData.pData_, 1, psData.size_, fp_);
|
||||
if (ferror(fp_) || feof(fp_)) return 1;
|
||||
fread(psData.pData_, 1, psData.size_, ifp);
|
||||
if (ferror(ifp) || feof(ifp)) return 1;
|
||||
}
|
||||
else if (marker == com_ && skipCom == -1)
|
||||
{
|
||||
else if (marker == com_ && skipCom == -1) {
|
||||
if (size < 2) return 2;
|
||||
// Jpegs can have multiple comments, but for now only handle
|
||||
// the first one (most jpegs only have one anyway).
|
||||
skipCom = count;
|
||||
++search;
|
||||
if (fseek(fp_, size-bufRead, SEEK_CUR)) return 2;
|
||||
if (fseek(ifp, size-bufRead, SEEK_CUR)) return 2;
|
||||
}
|
||||
else {
|
||||
if (size < 2) return 2;
|
||||
if (fseek(fp_, size-bufRead, SEEK_CUR)) return 2;
|
||||
if (fseek(ifp, size-bufRead, SEEK_CUR)) return 2;
|
||||
}
|
||||
marker = advanceToMarker();
|
||||
marker = advanceToMarker(ifp);
|
||||
if (marker < 0) return 2;
|
||||
++count;
|
||||
}
|
||||
@ -545,9 +521,9 @@ namespace Exiv2 {
|
||||
if (pIptcData_) ++search;
|
||||
if (!comment_.empty()) ++search;
|
||||
|
||||
fseek(fp_, seek, SEEK_SET);
|
||||
fseek(ifp, seek, SEEK_SET);
|
||||
count = 0;
|
||||
marker = advanceToMarker();
|
||||
marker = advanceToMarker(ifp);
|
||||
if (marker < 0) return 2;
|
||||
|
||||
// To simplify this a bit, new segments are inserts at either the start
|
||||
@ -556,8 +532,8 @@ namespace Exiv2 {
|
||||
// Segments are erased if there is no assigned metadata.
|
||||
while (marker != sos_ && search > 0) {
|
||||
// Read size and signature (ok if this hits EOF)
|
||||
bufRead = (long)fread(buf.pData_, 1, bufMinSize, fp_);
|
||||
if (ferror(fp_)) return 1;
|
||||
bufRead = (long)fread(buf.pData_, 1, bufMinSize, ifp);
|
||||
if (ferror(ifp)) return 1;
|
||||
// Careful, this can be a meaningless number for empty
|
||||
// images with only an eoi_ marker
|
||||
uint16_t size = getUShort(buf.pData_, bigEndian);
|
||||
@ -624,7 +600,7 @@ namespace Exiv2 {
|
||||
if (fwrite(tmpBuf, 1, 12, ofp) != 12) return 4;
|
||||
if (fwrite(pIptcData_, 1, sizeIptcData_ , ofp) != (size_t)sizeIptcData_) return 4;
|
||||
// data is padded to be even (but not included in size)
|
||||
if (sizeIptcData_ & 1 ) {
|
||||
if (sizeIptcData_ & 1) {
|
||||
if (fputc(0, ofp)==EOF) return 4;
|
||||
}
|
||||
if (ferror(ofp)) return 4;
|
||||
@ -636,35 +612,35 @@ namespace Exiv2 {
|
||||
if (ferror(ofp)) return 4;
|
||||
}
|
||||
}
|
||||
if( marker == eoi_ ) {
|
||||
if (marker == eoi_) {
|
||||
break;
|
||||
}
|
||||
else if (skipApp1Exif==count || skipApp13Ps3==count || skipCom==count) {
|
||||
--search;
|
||||
fseek(fp_, size-bufRead, SEEK_CUR);
|
||||
fseek(ifp, size-bufRead, SEEK_CUR);
|
||||
}
|
||||
else {
|
||||
if (size < 2) return 2;
|
||||
buf.alloc(size+2);
|
||||
fseek(fp_, -bufRead-2, SEEK_CUR);
|
||||
fread(buf.pData_, 1, size+2, fp_);
|
||||
if (ferror(fp_) || feof(fp_)) return 1;
|
||||
fseek(ifp, -bufRead-2, SEEK_CUR);
|
||||
fread(buf.pData_, 1, size+2, ifp);
|
||||
if (ferror(ifp) || feof(ifp)) return 1;
|
||||
if (fwrite(buf.pData_, 1, size+2, ofp) != (size_t)size+2) return 4;
|
||||
if (ferror(ofp)) return 4;
|
||||
}
|
||||
|
||||
// Next marker
|
||||
marker = advanceToMarker();
|
||||
marker = advanceToMarker(ifp);
|
||||
if (marker < 0) return 2;
|
||||
++count;
|
||||
}
|
||||
|
||||
// Copy rest of the stream
|
||||
fseek(fp_, -2, SEEK_CUR);
|
||||
fseek(ifp, -2, SEEK_CUR);
|
||||
fflush( ofp );
|
||||
buf.alloc(4096);
|
||||
size_t readSize = 0;
|
||||
while ((readSize=fread(buf.pData_, 1, buf.size_, fp_))) {
|
||||
while ((readSize=fread(buf.pData_, 1, buf.size_, ifp))) {
|
||||
if (fwrite(buf.pData_, 1, readSize, ofp) != readSize) return 4;
|
||||
}
|
||||
if (ferror(ofp)) return 4;
|
||||
@ -713,16 +689,16 @@ namespace Exiv2 {
|
||||
return isJpegType(ifp, advance);
|
||||
}
|
||||
|
||||
Image::AutoPtr newJpegInstance(const std::string& path, FILE* fp)
|
||||
Image::AutoPtr newJpegInstance(const std::string& path, bool create)
|
||||
{
|
||||
Image::AutoPtr image;
|
||||
if (fp == 0) {
|
||||
if (create) {
|
||||
image = Image::AutoPtr(new JpegImage(path, true));
|
||||
if (!image->good()) image.reset();
|
||||
}
|
||||
else {
|
||||
image = Image::AutoPtr(new JpegImage(path, fp));
|
||||
image = Image::AutoPtr(new JpegImage(path, false));
|
||||
}
|
||||
if (!image->good()) image.reset();
|
||||
return image;
|
||||
}
|
||||
|
||||
@ -766,16 +742,16 @@ namespace Exiv2 {
|
||||
return isExvType(ifp, advance);
|
||||
}
|
||||
|
||||
Image::AutoPtr newExvInstance(const std::string& path, FILE* fp)
|
||||
Image::AutoPtr newExvInstance(const std::string& path, bool create)
|
||||
{
|
||||
Image::AutoPtr image;
|
||||
if (fp == 0) {
|
||||
if (create) {
|
||||
image = Image::AutoPtr(new ExvImage(path, true));
|
||||
if (!image->good()) image.reset();
|
||||
}
|
||||
else {
|
||||
image = Image::AutoPtr(new ExvImage(path, fp));
|
||||
image = Image::AutoPtr(new ExvImage(path, false));
|
||||
}
|
||||
if (!image->good()) image.reset();
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
@ -126,11 +126,6 @@ namespace Exiv2 {
|
||||
from the actual file until writeMetadata is called.
|
||||
*/
|
||||
virtual void clearMetadata() =0;
|
||||
/*!
|
||||
@brief Close associated image file but preserve buffered metadata.
|
||||
@return 0 if successful.
|
||||
*/
|
||||
virtual int detach() =0;
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
@ -179,7 +174,7 @@ namespace Exiv2 {
|
||||
|
||||
//! Type for function pointer that creates new Image instances
|
||||
typedef Image::AutoPtr (*NewInstanceFct)(const std::string& path,
|
||||
FILE* ifp);
|
||||
bool create);
|
||||
//! Type for function pointer that checks image types
|
||||
typedef bool (*IsThisTypeFct)(FILE* ifp, bool advance);
|
||||
|
||||
@ -325,7 +320,6 @@ namespace Exiv2 {
|
||||
void clearComment();
|
||||
void setMetadata(const Image& image);
|
||||
void clearMetadata();
|
||||
int detach();
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
@ -341,13 +335,6 @@ namespace Exiv2 {
|
||||
protected:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor for subclasses that have already opened a
|
||||
file stream on the specified path.
|
||||
@param path Full path to image file.
|
||||
@param fp File pointer to open file.
|
||||
*/
|
||||
JpegBase(const std::string& path, FILE* fp);
|
||||
/*!
|
||||
@brief Constructor that can either open an existing image or create
|
||||
a new image from scratch. If a new image is to be created, any
|
||||
@ -409,7 +396,6 @@ namespace Exiv2 {
|
||||
|
||||
private:
|
||||
// DATA
|
||||
FILE* fp_; //!< Image file (read write)
|
||||
const std::string path_; //!< Image file name
|
||||
long sizeExifData_; //!< Size of the Exif data buffer
|
||||
byte* pExifData_; //!< Exif data buffer
|
||||
@ -422,10 +408,11 @@ namespace Exiv2 {
|
||||
@brief Advances file stream to one byte past the next Jpeg marker
|
||||
and returns the marker. This method should be called when the
|
||||
file stream is positioned one byte past the end of a Jpeg segment.
|
||||
@param fp File stream to advance
|
||||
@return the next Jpeg segment marker if successful;<BR>
|
||||
-1 if a maker was not found before EOF;<BR>
|
||||
*/
|
||||
int advanceToMarker() const;
|
||||
int advanceToMarker(FILE *fp) const;
|
||||
/*!
|
||||
@brief Locates Photoshop formated Iptc data in a memory buffer.
|
||||
Operates on raw data (rather than file streams) to simplify reuse.
|
||||
@ -450,23 +437,25 @@ namespace Exiv2 {
|
||||
uint16_t *const sizeHdr,
|
||||
uint16_t *const sizeIptc) const;
|
||||
/*!
|
||||
@brief Write to the associated file stream with the provided data.
|
||||
@brief Write to the specified file stream with the provided data.
|
||||
@param fp File stream to be written to (should be "w+b" mode)
|
||||
@param initData Data to be written to the associated file
|
||||
@param dataSize Size in bytes of data to be written
|
||||
@return 0 if successful;<BR>
|
||||
4 if the output file can not be written to;<BR>
|
||||
*/
|
||||
int initFile(const byte initData[], size_t dataSize);
|
||||
int initFile(FILE* fp, const byte initData[], size_t dataSize);
|
||||
/*!
|
||||
@brief Provides the main implementation of writeMetadata by
|
||||
writing all buffered metadata to associated file.
|
||||
@param os Output stream to write to (e.g., a temporary file).
|
||||
@param ifp Input file stream. Non-metadata is copied to output file.
|
||||
@param ofp Output file stream to write to (e.g., a temporary file).
|
||||
@return 0 if successful;<br>
|
||||
1 if reading from associated file failed;<BR>
|
||||
2 if the file does not contain a valid image;<BR>
|
||||
4 if the temporary output file can not be written to;<BR>
|
||||
1 if reading from input file failed;<BR>
|
||||
2 if the input file does not contain a valid image;<BR>
|
||||
4 if the output file can not be written to;<BR>
|
||||
*/
|
||||
int doWriteMetadata(FILE* ofp) const;
|
||||
int doWriteMetadata(FILE *ifp, FILE* ofp) const;
|
||||
|
||||
// NOT Implemented
|
||||
//! Default constructor.
|
||||
@ -481,7 +470,6 @@ namespace Exiv2 {
|
||||
@brief Helper class to access JPEG images
|
||||
*/
|
||||
class JpegImage : public JpegBase {
|
||||
friend Image::AutoPtr newJpegInstance(const std::string& path, FILE* fp);
|
||||
friend bool isJpegType(FILE* ifp, bool advance);
|
||||
public:
|
||||
//! @name Creators
|
||||
@ -528,17 +516,6 @@ namespace Exiv2 {
|
||||
static const byte soi_; // SOI marker
|
||||
static const byte blank_[]; // Minimal Jpeg image
|
||||
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor to be used when a Jpeg file has already
|
||||
been opened. Meant for internal factory use.
|
||||
@param path Full path to opened image file.
|
||||
@param fp File pointer to open file.
|
||||
*/
|
||||
JpegImage(const std::string& path, FILE* fp) : JpegBase(path, fp) {}
|
||||
//@}
|
||||
|
||||
// NOT Implemented
|
||||
//! Default constructor
|
||||
JpegImage();
|
||||
@ -550,7 +527,6 @@ namespace Exiv2 {
|
||||
|
||||
//! Helper class to access %Exiv2 files
|
||||
class ExvImage : public JpegBase {
|
||||
friend Image::AutoPtr newExvInstance(const std::string& path, FILE* fp);
|
||||
friend bool isExvType(FILE* ifp, bool advance);
|
||||
public:
|
||||
//! @name Creators
|
||||
@ -597,17 +573,6 @@ namespace Exiv2 {
|
||||
static const char exiv2Id_[]; // Exv identifier
|
||||
static const byte blank_[]; // Minimal exiv file
|
||||
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor to be used when an Exv file has already
|
||||
been opened. Meant for internal factory use.
|
||||
@param path Full path to opened image file.
|
||||
@param fp File pointer to open file.
|
||||
*/
|
||||
ExvImage(const std::string& path, FILE* fp) : JpegBase(path, fp) {}
|
||||
//@}
|
||||
|
||||
// NOT Implemented
|
||||
//! Default constructor
|
||||
ExvImage();
|
||||
|
||||
@ -62,7 +62,6 @@ try {
|
||||
": Could not read metadata from (" << params.read_ << ")\n";
|
||||
return 5;
|
||||
}
|
||||
readImg->detach();
|
||||
|
||||
Exiv2::Image::AutoPtr writeImg
|
||||
= Exiv2::ImageFactory::instance().open(params.write_);
|
||||
|
||||
@ -153,6 +153,30 @@ namespace Exiv2 {
|
||||
byte* pData_;
|
||||
}; // class DataBuf
|
||||
|
||||
/*!
|
||||
@brief Utility class that closes a file stream pointer upon destruction.
|
||||
Its primary use is to be a stack variable in functions that need
|
||||
to ensure files get closed. Useful when functions return errors
|
||||
from many locations.
|
||||
*/
|
||||
class FileCloser {
|
||||
// Not implemented
|
||||
//! Copy constructor
|
||||
FileCloser(const FileCloser&);
|
||||
//! Assignment operator
|
||||
FileCloser& operator=(const FileCloser&);
|
||||
public:
|
||||
//! Default constructor
|
||||
FileCloser() : fp_(0) {}
|
||||
//! Constructor with an initial buffer size
|
||||
FileCloser(FILE *fp) : fp_(fp) {}
|
||||
//! Destructor, deletes the allocated buffer
|
||||
~FileCloser() { close(); }
|
||||
void close() { if (fp_) fclose(fp_); fp_ = 0; }
|
||||
//! The file stream pointer
|
||||
FILE *fp_;
|
||||
}; // class FileCloser
|
||||
|
||||
// *****************************************************************************
|
||||
// free functions
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user