Exemple #1
0
    DataBuf IptcParser::encode(const IptcData& iptcData)
    {
        DataBuf buf(iptcData.size());
        byte *pWrite = buf.pData_;

        IptcData::const_iterator iter = iptcData.begin();
        IptcData::const_iterator end = iptcData.end();
        for ( ; iter != end; ++iter) {
            // marker, record Id, dataset num
            *pWrite++ = marker_;
            *pWrite++ = static_cast<byte>(iter->record());
            *pWrite++ = static_cast<byte>(iter->tag());

            // extended or standard dataset?
            long dataSize = iter->size();
            if (dataSize > 32767) {
                // always use 4 bytes for extended length
                uint16_t sizeOfSize = 4 | 0x8000;
                us2Data(pWrite, sizeOfSize, bigEndian);
                pWrite += 2;
                ul2Data(pWrite, dataSize, bigEndian);
                pWrite += 4;
            }
            else {
                us2Data(pWrite, static_cast<uint16_t>(dataSize), bigEndian);
                pWrite += 2;
            }
            pWrite += iter->value().copy(pWrite, bigEndian);
        }

        return buf;
    } // IptcParser::encode
Exemple #2
0
    uint32_t PsdImage::writeIptcData(const IptcData& iptcData, BasicIo& out) const
    {
        uint32_t resLength = 0;
        byte buf[8];

        if (iptcData.count() > 0) {
            DataBuf rawIptc = IptcParser::encode(iptcData);
            if (rawIptc.size_ > 0) {
#ifdef DEBUG
                std::cerr << std::hex << "write: resourceId: " << kPhotoshopResourceID_IPTC_NAA << "\n";
                std::cerr << std::dec << "Writing IPTC_NAA: size: " << rawIptc.size_ << "\n";
#endif
                ul2Data(buf, kPhotoshopResourceType, bigEndian);
                if (out.write(buf, 4) != 4) throw Error(21);
                us2Data(buf, kPhotoshopResourceID_IPTC_NAA, bigEndian);
                if (out.write(buf, 2) != 2) throw Error(21);
                us2Data(buf, 0, bigEndian);                      // NULL resource name
                if (out.write(buf, 2) != 2) throw Error(21);
                ul2Data(buf, rawIptc.size_, bigEndian);
                if (out.write(buf, 4) != 4) throw Error(21);
                // Write encoded Iptc data
                if (out.write(rawIptc.pData_, rawIptc.size_) != rawIptc.size_) throw Error(21);
                resLength += rawIptc.size_ + 12;
                if (rawIptc.size_ & 1)    // even padding
                {
                    buf[0] = 0;
                    if (out.write(buf, 1) != 1) throw Error(21);
                    resLength++;
                }
            }
        }
        return resLength;
    } // PsdImage::writeIptcData
Exemple #3
0
void processAdd(const std::string& line, int num)
{
    std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
    std::string::size_type keyEnd = line.find_first_of(" \t", keyStart+1);
    std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd+1);

    if (keyStart == std::string::npos ||
        keyEnd == std::string::npos ||
        dataStart == std::string::npos) {
        std::ostringstream os;
        os << "Invalid \'a\' command at line " << num;
        throw Error(os.str());
    }

    std::string key(line.substr(keyStart, keyEnd-keyStart));
    std::pair<uint16, uint16> p = IptcDataSets::decomposeKey(key);
    if (p.first == 0xffff) throw Error("Invalid key " + key);
    if (p.second == IptcDataSets::invalidRecord) throw Error("Invalid key " + key);

    std::string data(line.substr(dataStart));
    // if data starts and ends with quotes, remove them
    if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
        data = data.substr(1, data.size()-2);
    }
    TypeId type = IptcDataSets::dataSetType(p.first, p.second);
    Value *val = Value::create(type);
    val->read(data);

    int rc = g_iptcData.add(IptcKey(key), val);
    if (rc) {
        std::string error = IptcData::strError(rc, "Input file");
        throw Error(error);
    }
    
}
Exemple #4
0
void processAdd(const std::string& line, int num, IptcData &iptcData)
{
    std::string::size_type keyStart = line.find_first_not_of(" \t", 1);
    std::string::size_type keyEnd = line.find_first_of(" \t", keyStart+1);
    std::string::size_type dataStart = line.find_first_not_of(" \t", keyEnd+1);

    if (keyStart == std::string::npos ||
        keyEnd == std::string::npos ||
        dataStart == std::string::npos) {
        std::ostringstream os;
        os << "Invalid \'a\' command at line " << num;
        throw Error(1, os.str());
    }

    std::string key(line.substr(keyStart, keyEnd-keyStart));
    IptcKey iptcKey(key);

    std::string data(line.substr(dataStart));
    // if data starts and ends with quotes, remove them
    if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
        data = data.substr(1, data.size()-2);
    }
    TypeId type = IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
    Value::AutoPtr value = Value::create(type);
    value->read(data);

    int rc = iptcData.add(iptcKey, value.get());
    if (rc) {
        throw Error(1, "Iptc dataset already exists and is not repeatable");
    }
}
Exemple #5
0
void processRemove(const std::string& line, int num, IptcData &iptcData)
{
    std::string::size_type keyStart = line.find_first_not_of(" \t", 1);

    if (keyStart == std::string::npos) {
        std::ostringstream os;
        os << "Invalid \'r\' command at line " << num;
        throw Error(1, os.str());
    }

    const std::string key( line.substr(keyStart) );
    IptcKey iptcKey(key);

    IptcData::iterator iter = iptcData.findKey(iptcKey);
    if (iter != iptcData.end()) {
        iptcData.erase(iter);
    }
}
Exemple #6
0
    DataBuf Photoshop::setIptcIrb(const byte*     pPsData,
                                  long            sizePsData,
                                  const IptcData& iptcData)
    {
        if (sizePsData > 0) assert(pPsData);
#ifdef DEBUG
        std::cerr << "IRB block at the beginning of Photoshop::setIptcIrb\n";
        if (sizePsData == 0) std::cerr << "  None.\n";
        else hexdump(std::cerr, pPsData, sizePsData);
#endif
        const byte* record    = pPsData;
        uint32_t    sizeIptc  = 0;
        uint32_t    sizeHdr   = 0;
        DataBuf rc;
        // Safe to call with zero psData.size_
        if (0 > Photoshop::locateIptcIrb(pPsData, sizePsData,
                                         &record, &sizeHdr, &sizeIptc)) {
            return rc;
        }
        Blob psBlob;
        const uint32_t sizeFront = static_cast<uint32_t>(record - pPsData);
        // Write data before old record.
        if (sizePsData > 0 && sizeFront > 0) {
            append(psBlob, pPsData, sizeFront);
        }
        // Write new iptc record if we have it
        DataBuf rawIptc(iptcData.copy());
        if (rawIptc.size_ > 0) {
            byte tmpBuf[12];
            memcpy(tmpBuf, Photoshop::bimId_, 4);
            us2Data(tmpBuf + 4, iptc_, bigEndian);
            tmpBuf[6] = 0;
            tmpBuf[7] = 0;
            ul2Data(tmpBuf + 8, rawIptc.size_, bigEndian);
            append(psBlob, tmpBuf, 12);
            append(psBlob, rawIptc.pData_, rawIptc.size_);
            // Data is padded to be even (but not included in size)
            if (rawIptc.size_ & 1) psBlob.push_back(0x00);
        }
        // Write existing stuff after record, data is rounded to be even.
        const uint32_t sizeOldData = sizeHdr + sizeIptc + (sizeIptc & 1);
        // Note: Because of the rounding, sizeFront + sizeOldData can be 
        // _greater_ than sizePsData by 1 (not just equal), if the original
        // data was not padded.
        if (static_cast<uint32_t>(sizePsData) > sizeFront + sizeOldData) {
            append(psBlob, record + sizeOldData,
                   sizePsData - sizeFront - sizeOldData);
        }
        if (psBlob.size() > 0) rc = DataBuf(&psBlob[0], static_cast<long>(psBlob.size()));
#ifdef DEBUG
        std::cerr << "IRB block at the end of Photoshop::setIptcIrb\n";
        if (rc.size_ == 0) std::cerr << "  None.\n";
        else hexdump(std::cerr, rc.pData_, rc.size_);
#endif
        return rc;

    } // Photoshop::setIptcIrb
Exemple #7
0
void processRemove(const std::string& line, int num)
{
    std::string::size_type keyStart = line.find_first_not_of(" \t", 1);

    if (keyStart == std::string::npos) {
        std::ostringstream os;
        os << "Invalid \'r\' command at line " << num;
        throw Error(os.str());
    }

    const std::string key( line.substr(keyStart) );
    std::pair<uint16, uint16> p = IptcDataSets::decomposeKey(key);
    if (p.first == 0xffff) throw Error("Invalid key" + key);
    if (p.second == IptcDataSets::invalidRecord) throw Error("Invalid key" + key);

    IptcData::iterator iter = g_iptcData.findId(p.first, p.second);
    if (iter != g_iptcData.end()) {
        g_iptcData.erase(iter);
    }
}
Exemple #8
0
    ByteOrder ExifParser::decode(
              ExifData& exifData,
        const byte*     pData,
              uint32_t  size
    )
    {
        IptcData iptcData;
        XmpData  xmpData;
        ByteOrder bo = TiffParser::decode(exifData,
                                          iptcData,
                                          xmpData,
                                          pData,
                                          size);
#ifndef SUPPRESS_WARNINGS
        if (!iptcData.empty()) {
            EXV_WARNING << "Ignoring IPTC information encoded in the Exif data.\n";
        }
        if (!xmpData.empty()) {
            EXV_WARNING << "Ignoring XMP information encoded in the Exif data.\n";
        }
#endif
        return bo;
    } // ExifParser::decode
Exemple #9
0
DataBuf IptcParser::encode(const IptcData& iptcData)
{
    DataBuf buf(iptcData.size());
    byte *pWrite = buf.pData_;

    // Copy the iptc data sets and sort them by record but preserve the order of datasets
    IptcMetadata sortedIptcData;
    std::copy(iptcData.begin(), iptcData.end(), std::back_inserter(sortedIptcData));
    std::stable_sort(sortedIptcData.begin(), sortedIptcData.end(), cmpIptcdataByRecord);

    IptcData::const_iterator iter = sortedIptcData.begin();
    IptcData::const_iterator end = sortedIptcData.end();
    for ( ; iter != end; ++iter) {
        // marker, record Id, dataset num
        *pWrite++ = marker_;
        *pWrite++ = static_cast<byte>(iter->record());
        *pWrite++ = static_cast<byte>(iter->tag());

        // extended or standard dataset?
        long dataSize = iter->size();
        if (dataSize > 32767) {
            // always use 4 bytes for extended length
            uint16_t sizeOfSize = 4 | 0x8000;
            us2Data(pWrite, sizeOfSize, bigEndian);
            pWrite += 2;
            ul2Data(pWrite, dataSize, bigEndian);
            pWrite += 4;
        }
        else {
            us2Data(pWrite, static_cast<uint16_t>(dataSize), bigEndian);
            pWrite += 2;
        }
        pWrite += iter->value().copy(pWrite, bigEndian);
    }

    return buf;
} // IptcParser::encode
Exemple #10
0
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
{
    try {

        if (argc != 2) {
            std::cout << "Usage: " << argv[0] << " image\n";
            std::cout << "Commands read from stdin.\n";
            return 1;
        }

        int rc = g_iptcData.read(argv[1]);
        if (rc) {
            std::string error = IptcData::strError(rc, argv[1]);
            throw Error(error);
        }

        std::string line;
        int num = 0;
        std::getline(std::cin, line);
        while (line.length() && processLine(line, ++num)) {
            std::getline(std::cin, line);
        }
     
        rc = g_iptcData.write(argv[1]);
        if (rc) {
            std::string error = IptcData::strError(rc, argv[1]);
            throw Error(error);
        }

        return rc;
    }
    catch (Error& e) {
        std::cout << "Caught Exiv2 exception '" << e << "'\n";
        return -1;
    }
}
Exemple #11
0
int IptcParser::decode(
    IptcData& iptcData,
    const byte*     pData,
    uint32_t  size
)
{
#ifdef DEBUG
    std::cerr << "IptcParser::decode, size = " << size << "\n";
#endif
    const byte* pRead = pData;
    iptcData.clear();

    uint16_t record = 0;
    uint16_t dataSet = 0;
    uint32_t sizeData = 0;
    byte extTest = 0;

    while (pRead + 3 < pData + size) {
        // First byte should be a marker. If it isn't, scan forward and skip
        // the chunk bytes present in some images. This deviates from the
        // standard, which advises to treat such cases as errors.
        if (*pRead++ != marker_) continue;
        record = *pRead++;
        dataSet = *pRead++;

        extTest = *pRead;
        if (extTest & 0x80) {
            // extended dataset
            uint16_t sizeOfSize = (getUShort(pRead, bigEndian) & 0x7FFF);
            if (sizeOfSize > 4) return 5;
            pRead += 2;
            sizeData = 0;
            for (; sizeOfSize > 0; --sizeOfSize) {
                sizeData |= *pRead++ << (8 *(sizeOfSize-1));
            }
        }
        else {
            // standard dataset
            sizeData = getUShort(pRead, bigEndian);
            pRead += 2;
        }
        if (pRead + sizeData <= pData + size) {
            int rc = 0;
            if ((rc = readData(iptcData, dataSet, record, pRead, sizeData)) != 0) {
#ifndef SUPPRESS_WARNINGS
                EXV_WARNING << "Failed to read IPTC dataset "
                            << IptcKey(dataSet, record)
                            << " (rc = " << rc << "); skipped.\n";
#endif
            }
        }
#ifndef SUPPRESS_WARNINGS
        else {
            EXV_WARNING << "IPTC dataset " << IptcKey(dataSet, record)
                        << " has invalid size " << sizeData << "; skipped.\n";
        }
#endif
        pRead += sizeData;
    }

    return 0;
} // IptcParser::decode