~noskcaj/ubuntu/trusty/libextractor/merge

« back to all changes in this revision

Viewing changes to src/plugins/exiv2/jpgimage.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-11-17 20:27:32 UTC
  • mfrom: (1.10.4 upstream) (5.2.5 sid)
  • Revision ID: james.westby@ubuntu.com-20091117202732-ipm2h3gks5bdw2vx
Tags: 0.5.23+dfsg-3
* Building against libltdl7.
* Updating to standards version 3.8.3.
* Adding maintainer homepage field to control.
* Marking maintainer homepage field to be also included in binary
  packages and changelog.
* Adding README.source.
* Simplifying autotools handling in rules.
* Updating README.source.
* Moving maintainer homepage field from control to copyright.
* Dropping la files.
* Simplyfing debhelper install files.
* Bumping versioned build-depends on debhelper.
* Adding depends to dpkg install info.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// ***************************************************************** -*- C++ -*-
2
 
/*
3
 
 * Copyright (C) 2004, 2005 Andreas Huggel <ahuggel@gmx.net>
4
 
 *
5
 
 * This program is part of the Exiv2 distribution.
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU General Public License
9
 
 * as published by the Free Software Foundation; either version 2
10
 
 * of the License, or (at your option) any later version.
11
 
 *
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 * GNU General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program; if not, write to the Free Software
19
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
 
 */
21
 
/*
22
 
  File:      jpgimage.cpp
23
 
  Version:   $Rev: 563 $
24
 
  Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
25
 
             Brad Schick (brad) <brad@robotbattle.com>
26
 
  History:   15-Jan-05, brad: split out from image.cpp
27
 
 
28
 
 */
29
 
// *****************************************************************************
30
 
#include "rcsid.hpp"
31
 
EXIV2_RCSID("@(#) $Id: jpgimage.cpp 563 2005-04-21 07:21:53Z ahuggel $");
32
 
 
33
 
// *****************************************************************************
34
 
// included header files
35
 
#ifdef _MSC_VER
36
 
# include "exv_msvc.h"
37
 
#else
38
 
# include "exv_conf.h"
39
 
#endif
40
 
 
41
 
#include "jpgimage.hpp"
42
 
#include "error.hpp"
43
 
#include "futils.hpp"
44
 
 
45
 
// + standard includes
46
 
#include <cstring>
47
 
#include <cassert>
48
 
 
49
 
// *****************************************************************************
50
 
// class member definitions
51
 
namespace Exiv2 {
52
 
 
53
 
    // Local functions. These could be static private functions on Image
54
 
    // subclasses but then ImageFactory needs to be made a friend.
55
 
    /*!
56
 
      @brief Create a new ExvImage instance and return an auto-pointer to it.
57
 
             Caller owns the returned object and the auto-pointer ensures that
58
 
             it will be deleted.
59
 
     */
60
 
    Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create);
61
 
    //! Check if the file iIo is an EXV file
62
 
    bool isExvType(BasicIo& iIo, bool advance);
63
 
    /*!
64
 
      @brief Create a new JpegImage instance and return an auto-pointer to it.
65
 
             Caller owns the returned object and the auto-pointer ensures that
66
 
             it will be deleted.
67
 
     */
68
 
    Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create);
69
 
    //! Check if the file iIo is a JPEG image.
70
 
    bool isJpegType(BasicIo& iIo, bool advance);
71
 
 
72
 
    const byte JpegBase::sos_    = 0xda;
73
 
    const byte JpegBase::eoi_    = 0xd9;
74
 
    const byte JpegBase::app0_   = 0xe0;
75
 
    const byte JpegBase::app1_   = 0xe1;
76
 
    const byte JpegBase::app13_  = 0xed;
77
 
    const byte JpegBase::com_    = 0xfe;
78
 
    const uint16_t JpegBase::iptc_ = 0x0404;
79
 
    const char JpegBase::exifId_[] = "Exif\0\0";
80
 
    const char JpegBase::jfifId_[] = "JFIF\0";
81
 
    const char JpegBase::ps3Id_[]  = "Photoshop 3.0\0";
82
 
    const char JpegBase::bimId_[]  = "8BIM";
83
 
 
84
 
    JpegBase::JpegBase(BasicIo::AutoPtr io, bool create,
85
 
                       const byte initData[], long dataSize)
86
 
        : io_(io)
87
 
    {
88
 
        if (create) {
89
 
            initImage(initData, dataSize);
90
 
        }
91
 
    }
92
 
 
93
 
    int JpegBase::initImage(const byte initData[], long dataSize)
94
 
    {
95
 
        if (io_->open() != 0) {
96
 
            return 4;
97
 
        }
98
 
        IoCloser closer(*io_);
99
 
        if (io_->write(initData, dataSize) != dataSize) {
100
 
            return 4;
101
 
        }
102
 
        return 0;
103
 
    }
104
 
 
105
 
    bool JpegBase::good() const
106
 
    {
107
 
        if (io_->open() != 0) return false;
108
 
        IoCloser closer(*io_);
109
 
        return isThisType(*io_, false);
110
 
    }
111
 
 
112
 
    void JpegBase::clearMetadata()
113
 
    {
114
 
        clearIptcData();
115
 
        clearExifData();
116
 
        clearComment();
117
 
    }
118
 
 
119
 
    void JpegBase::clearIptcData()
120
 
    {
121
 
        iptcData_.clear();
122
 
    }
123
 
 
124
 
    void JpegBase::clearExifData()
125
 
    {
126
 
        exifData_.clear();
127
 
    }
128
 
 
129
 
    void JpegBase::clearComment()
130
 
    {
131
 
        comment_.erase();
132
 
    }
133
 
 
134
 
    void JpegBase::setExifData(const ExifData& exifData)
135
 
    {
136
 
        exifData_ = exifData;
137
 
    }
138
 
 
139
 
    void JpegBase::setIptcData(const IptcData& iptcData)
140
 
    {
141
 
        iptcData_ = iptcData;
142
 
    }
143
 
 
144
 
    void JpegBase::setComment(const std::string& comment)
145
 
    {
146
 
        comment_ = comment;
147
 
    }
148
 
 
149
 
    void JpegBase::setMetadata(const Image& image)
150
 
    {
151
 
        setIptcData(image.iptcData());
152
 
        setExifData(image.exifData());
153
 
        setComment(image.comment());
154
 
    }
155
 
 
156
 
    int JpegBase::advanceToMarker() const
157
 
    {
158
 
        int c = -1;
159
 
        // Skips potential padding between markers
160
 
        while ((c=io_->getb()) != 0xff) {
161
 
            if (c == EOF) return -1;
162
 
        }
163
 
 
164
 
        // Markers can start with any number of 0xff
165
 
        while ((c=io_->getb()) == 0xff) {
166
 
            if (c == EOF) return -1;
167
 
        }
168
 
        return c;
169
 
    }
170
 
 
171
 
    void JpegBase::readMetadata()
172
 
    {
173
 
        if (io_->open() != 0) {
174
 
            throw Error(9, io_->path(), strError());
175
 
        }
176
 
        IoCloser closer(*io_);
177
 
        // Ensure that this is the correct image type
178
 
        if (!isThisType(*io_, true)) {
179
 
            if (io_->error() || io_->eof()) throw Error(14);
180
 
            throw Error(15);
181
 
        }
182
 
        clearMetadata();
183
 
        int search = 3;
184
 
        const long bufMinSize = 16;
185
 
        long bufRead = 0;
186
 
        DataBuf buf(bufMinSize);
187
 
 
188
 
        // Read section marker
189
 
        int marker = advanceToMarker();
190
 
        if (marker < 0) throw Error(15);
191
 
 
192
 
        while (marker != sos_ && marker != eoi_ && search > 0) {
193
 
            // Read size and signature (ok if this hits EOF)
194
 
            bufRead = io_->read(buf.pData_, bufMinSize);
195
 
            if (io_->error()) throw Error(14);
196
 
            uint16_t size = getUShort(buf.pData_, bigEndian);
197
 
 
198
 
            if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
199
 
                if (size < 8) throw Error(15);
200
 
                // Seek to begining and read the Exif data
201
 
                io_->seek(8-bufRead, BasicIo::cur);
202
 
                long sizeExifData = size - 8;
203
 
                DataBuf rawExif(sizeExifData);
204
 
                io_->read(rawExif.pData_, sizeExifData);
205
 
                if (io_->error() || io_->eof()) throw Error(14);
206
 
                if (exifData_.load(rawExif.pData_, sizeExifData)) throw Error(15);
207
 
                --search;
208
 
            }
209
 
            else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) == 0) {
210
 
                if (size < 16) throw Error(15);
211
 
                // Read the rest of the APP13 segment
212
 
                // needed if bufMinSize!=16: io_->seek(16-bufRead, BasicIo::cur);
213
 
                DataBuf psData(size - 16);
214
 
                io_->read(psData.pData_, psData.size_);
215
 
                if (io_->error() || io_->eof()) throw Error(14);
216
 
                const byte *record = 0;
217
 
                uint16_t sizeIptc = 0;
218
 
                uint16_t sizeHdr = 0;
219
 
                // Find actual Iptc data within the APP13 segment
220
 
                if (!locateIptcData(psData.pData_, psData.size_, &record,
221
 
                            &sizeHdr, &sizeIptc)) {
222
 
                    assert(sizeIptc);
223
 
                    if (iptcData_.load(record + sizeHdr, sizeIptc)) throw Error(15);
224
 
                }
225
 
                --search;
226
 
            }
227
 
            else if (marker == com_ && comment_.empty())
228
 
            {
229
 
                if (size < 2) throw Error(15);
230
 
                // Jpegs can have multiple comments, but for now only read
231
 
                // the first one (most jpegs only have one anyway). Comments
232
 
                // are simple single byte ISO-8859-1 strings.
233
 
                io_->seek(2-bufRead, BasicIo::cur);
234
 
                buf.alloc(size-2);
235
 
                io_->read(buf.pData_, size-2);
236
 
                if (io_->error() || io_->eof()) throw Error(14);
237
 
                comment_.assign(reinterpret_cast<char*>(buf.pData_), size-2);
238
 
                while (   comment_.length()
239
 
                       && comment_.at(comment_.length()-1) == '\0') {
240
 
                    comment_.erase(comment_.length()-1);
241
 
                }
242
 
                --search;
243
 
            }
244
 
            else {
245
 
                if (size < 2) throw Error(15);
246
 
                // Skip the remainder of the unknown segment
247
 
                if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(15);
248
 
            }
249
 
            // Read the beginning of the next segment
250
 
            marker = advanceToMarker();
251
 
            if (marker < 0) throw Error(15);
252
 
        }
253
 
    } // JpegBase::readMetadata
254
 
 
255
 
 
256
 
    // Operates on raw data (rather than file streams) to simplify reuse
257
 
    int JpegBase::locateIptcData(const byte *pPsData,
258
 
                                 long sizePsData,
259
 
                                 const byte **record,
260
 
                                 uint16_t *const sizeHdr,
261
 
                                 uint16_t *const sizeIptc) const
262
 
    {
263
 
        assert(record);
264
 
        assert(sizeHdr);
265
 
        assert(sizeIptc);
266
 
        // Used for error checking
267
 
        long position = 0;
268
 
 
269
 
        // Data should follow Photoshop format, if not exit
270
 
        while (position <= (sizePsData - 14) &&
271
 
                memcmp(pPsData + position, bimId_, 4)==0) {
272
 
            const byte *hrd = pPsData + position;
273
 
            position += 4;
274
 
            uint16_t type = getUShort(pPsData+ position, bigEndian);
275
 
            position += 2;
276
 
 
277
 
            // Pascal string is padded to have an even size (including size byte)
278
 
            byte psSize = pPsData[position] + 1;
279
 
            psSize += (psSize & 1);
280
 
            position += psSize;
281
 
            if (position >= sizePsData) return -2;
282
 
 
283
 
            // Data is also padded to be even
284
 
            long dataSize = getULong(pPsData + position, bigEndian);
285
 
            position += 4;
286
 
            if (dataSize > sizePsData - position) return -2;
287
 
 
288
 
            if (type == iptc_) {
289
 
                *sizeIptc = static_cast<uint16_t>(dataSize);
290
 
                *sizeHdr = psSize + 10;
291
 
                *record = hrd;
292
 
                return 0;
293
 
            }
294
 
            position += dataSize + (dataSize & 1);
295
 
        }
296
 
        return 3;
297
 
    } // JpegBase::locateIptcData
298
 
 
299
 
    void JpegBase::writeMetadata()
300
 
    {
301
 
        if (io_->open() != 0) {
302
 
            throw Error(9, io_->path(), strError());
303
 
        }
304
 
        IoCloser closer(*io_);
305
 
        BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
306
 
        assert (tempIo.get() != 0);
307
 
 
308
 
        doWriteMetadata(*tempIo); // may throw
309
 
        io_->close();
310
 
        io_->transfer(*tempIo); // may throw
311
 
    } // JpegBase::writeMetadata
312
 
 
313
 
    void JpegBase::doWriteMetadata(BasicIo& outIo)
314
 
    {
315
 
        if (!io_->isopen()) throw Error(20);
316
 
        if (!outIo.isopen()) throw Error(21);
317
 
 
318
 
        // Ensure that this is the correct image type
319
 
        if (!isThisType(*io_, true)) {
320
 
            if (io_->error() || io_->eof()) throw Error(20);
321
 
            throw Error(22);
322
 
        }
323
 
 
324
 
        const long bufMinSize = 16;
325
 
        long bufRead = 0;
326
 
        DataBuf buf(bufMinSize);
327
 
        const long seek = io_->tell();
328
 
        int count = 0;
329
 
        int search = 0;
330
 
        int insertPos = 0;
331
 
        int skipApp1Exif = -1;
332
 
        int skipApp13Ps3 = -1;
333
 
        int skipCom = -1;
334
 
        DataBuf psData;
335
 
 
336
 
        // Write image header
337
 
        if (writeHeader(outIo)) throw Error(21);
338
 
 
339
 
        // Read section marker
340
 
        int marker = advanceToMarker();
341
 
        if (marker < 0) throw Error(22);
342
 
 
343
 
        // First find segments of interest. Normally app0 is first and we want
344
 
        // to insert after it. But if app0 comes after com, app1 and app13 then
345
 
        // don't bother.
346
 
        while (marker != sos_ && marker != eoi_ && search < 3) {
347
 
            // Read size and signature (ok if this hits EOF)
348
 
            bufRead = io_->read(buf.pData_, bufMinSize);
349
 
            if (io_->error()) throw Error(20);
350
 
            uint16_t size = getUShort(buf.pData_, bigEndian);
351
 
 
352
 
            if (marker == app0_) {
353
 
                if (size < 2) throw Error(22);
354
 
                insertPos = count + 1;
355
 
                if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
356
 
            }
357
 
            else if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
358
 
                if (size < 8) throw Error(22);
359
 
                skipApp1Exif = count;
360
 
                ++search;
361
 
                if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
362
 
            }
363
 
            else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) == 0) {
364
 
                if (size < 16) throw Error(22);
365
 
                skipApp13Ps3 = count;
366
 
                ++search;
367
 
                // needed if bufMinSize!=16: io_->seek(16-bufRead, BasicIo::cur);
368
 
                psData.alloc(size - 16);
369
 
                // Load PS data now to allow reinsertion at any point
370
 
                io_->read(psData.pData_, psData.size_);
371
 
                if (io_->error() || io_->eof()) throw Error(20);
372
 
            }
373
 
            else if (marker == com_ && skipCom == -1) {
374
 
                if (size < 2) throw Error(22);
375
 
                // Jpegs can have multiple comments, but for now only handle
376
 
                // the first one (most jpegs only have one anyway).
377
 
                skipCom = count;
378
 
                ++search;
379
 
                if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
380
 
            }
381
 
            else {
382
 
                if (size < 2) throw Error(22);
383
 
                if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
384
 
            }
385
 
            marker = advanceToMarker();
386
 
            if (marker < 0) throw Error(22);
387
 
            ++count;
388
 
        }
389
 
 
390
 
        if (exifData_.count() > 0) ++search;
391
 
        if (iptcData_.count() > 0) ++search;
392
 
        if (!comment_.empty()) ++search;
393
 
 
394
 
        io_->seek(seek, BasicIo::beg);
395
 
        count = 0;
396
 
        marker = advanceToMarker();
397
 
        if (marker < 0) throw Error(22);
398
 
 
399
 
        // To simplify this a bit, new segments are inserts at either the start
400
 
        // or right after app0. This is standard in most jpegs, but has the
401
 
        // potential to change segment ordering (which is allowed).
402
 
        // Segments are erased if there is no assigned metadata.
403
 
        while (marker != sos_ && search > 0) {
404
 
            // Read size and signature (ok if this hits EOF)
405
 
            bufRead = io_->read(buf.pData_, bufMinSize);
406
 
            if (io_->error()) throw Error(20);
407
 
            // Careful, this can be a meaningless number for empty
408
 
            // images with only an eoi_ marker
409
 
            uint16_t size = getUShort(buf.pData_, bigEndian);
410
 
 
411
 
            if (insertPos == count) {
412
 
                byte tmpBuf[18];
413
 
                if (!comment_.empty()) {
414
 
                    // Write COM marker, size of comment, and string
415
 
                    tmpBuf[0] = 0xff;
416
 
                    tmpBuf[1] = com_;
417
 
                    us2Data(tmpBuf + 2,
418
 
                            static_cast<uint16_t>(comment_.length()+3), bigEndian);
419
 
                    if (outIo.write(tmpBuf, 4) != 4) throw Error(21);
420
 
                    if (outIo.write((byte*)comment_.data(), (long)comment_.length())
421
 
                        != (long)comment_.length()) throw Error(21);
422
 
                    if (outIo.putb(0)==EOF) throw Error(21);
423
 
                    if (outIo.error()) throw Error(21);
424
 
                    --search;
425
 
                }
426
 
                if (exifData_.count() > 0) {
427
 
                    // Write APP1 marker, size of APP1 field, Exif id and Exif data
428
 
                    DataBuf rawExif(exifData_.copy());
429
 
                    tmpBuf[0] = 0xff;
430
 
                    tmpBuf[1] = app1_;
431
 
                    us2Data(tmpBuf + 2,
432
 
                            static_cast<uint16_t>(rawExif.size_+8),
433
 
                            bigEndian);
434
 
                    memcpy(tmpBuf + 4, exifId_, 6);
435
 
                    if (outIo.write(tmpBuf, 10) != 10) throw Error(21);
436
 
                    if (outIo.write(rawExif.pData_, rawExif.size_)
437
 
                        != rawExif.size_) throw Error(21);
438
 
                    if (outIo.error()) throw Error(21);
439
 
                    --search;
440
 
                }
441
 
 
442
 
                const byte *record = psData.pData_;
443
 
                uint16_t sizeIptc = 0;
444
 
                uint16_t sizeHdr = 0;
445
 
                // Safe to call with zero psData.size_
446
 
                locateIptcData(psData.pData_, psData.size_, &record, &sizeHdr, &sizeIptc);
447
 
 
448
 
                // Data is rounded to be even
449
 
                const int sizeOldData = sizeHdr + sizeIptc + (sizeIptc & 1);
450
 
                if (psData.size_ > sizeOldData || iptcData_.count() > 0) {
451
 
                    // rawIptc may have size of zero.
452
 
                    DataBuf rawIptc(iptcData_.copy());
453
 
                    // write app13 marker, new size, and ps3Id
454
 
                    tmpBuf[0] = 0xff;
455
 
                    tmpBuf[1] = app13_;
456
 
                    const int sizeNewData = rawIptc.size_ ?
457
 
                            rawIptc.size_ + (rawIptc.size_ & 1) + 12 : 0;
458
 
                    us2Data(tmpBuf + 2,
459
 
                            static_cast<uint16_t>(psData.size_-sizeOldData+sizeNewData+16),
460
 
                            bigEndian);
461
 
                    memcpy(tmpBuf + 4, ps3Id_, 14);
462
 
                    if (outIo.write(tmpBuf, 18) != 18) throw Error(21);
463
 
                    if (outIo.error()) throw Error(21);
464
 
 
465
 
                    const long sizeFront = (long)(record - psData.pData_);
466
 
                    const long sizeEnd = psData.size_ - sizeFront - sizeOldData;
467
 
                    // write data before old record.
468
 
                    if (outIo.write(psData.pData_, sizeFront) != sizeFront) throw Error(21);
469
 
 
470
 
                    // write new iptc record if we have it
471
 
                    if (iptcData_.count() > 0) {
472
 
                        memcpy(tmpBuf, bimId_, 4);
473
 
                        us2Data(tmpBuf+4, iptc_, bigEndian);
474
 
                        tmpBuf[6] = 0;
475
 
                        tmpBuf[7] = 0;
476
 
                        ul2Data(tmpBuf + 8, rawIptc.size_, bigEndian);
477
 
                        if (outIo.write(tmpBuf, 12) != 12) throw Error(21);
478
 
                        if (outIo.write(rawIptc.pData_, rawIptc.size_)
479
 
                            != rawIptc.size_) throw Error(21);
480
 
                        // data is padded to be even (but not included in size)
481
 
                        if (rawIptc.size_ & 1) {
482
 
                            if (outIo.putb(0)==EOF) throw Error(21);
483
 
                        }
484
 
                        if (outIo.error()) throw Error(21);
485
 
                        --search;
486
 
                    }
487
 
 
488
 
                    // write existing stuff after record
489
 
                    if (outIo.write(record+sizeOldData, sizeEnd)
490
 
                        != sizeEnd) throw Error(21);
491
 
                    if (outIo.error()) throw Error(21);
492
 
                }
493
 
            }
494
 
            if (marker == eoi_) {
495
 
                break;
496
 
            }
497
 
            else if (skipApp1Exif==count || skipApp13Ps3==count || skipCom==count) {
498
 
                --search;
499
 
                io_->seek(size-bufRead, BasicIo::cur);
500
 
            }
501
 
            else {
502
 
                if (size < 2) throw Error(22);
503
 
                buf.alloc(size+2);
504
 
                io_->seek(-bufRead-2, BasicIo::cur);
505
 
                io_->read(buf.pData_, size+2);
506
 
                if (io_->error() || io_->eof()) throw Error(20);
507
 
                if (outIo.write(buf.pData_, size+2) != size+2) throw Error(21);
508
 
                if (outIo.error()) throw Error(21);
509
 
            }
510
 
 
511
 
            // Next marker
512
 
            marker = advanceToMarker();
513
 
            if (marker < 0) throw Error(22);
514
 
            ++count;
515
 
        }
516
 
 
517
 
        // Copy rest of the Io
518
 
        io_->seek(-2, BasicIo::cur);
519
 
        buf.alloc(4096);
520
 
        long readSize = 0;
521
 
        while ((readSize=io_->read(buf.pData_, buf.size_))) {
522
 
            if (outIo.write(buf.pData_, readSize) != readSize) throw Error(21);
523
 
        }
524
 
        if (outIo.error()) throw Error(21);
525
 
 
526
 
    } // JpegBase::doWriteMetadata
527
 
 
528
 
 
529
 
    const byte JpegImage::soi_ = 0xd8;
530
 
    const byte JpegImage::blank_[] = {
531
 
        0xFF,0xD8,0xFF,0xDB,0x00,0x84,0x00,0x10,0x0B,0x0B,0x0B,0x0C,0x0B,0x10,0x0C,0x0C,
532
 
        0x10,0x17,0x0F,0x0D,0x0F,0x17,0x1B,0x14,0x10,0x10,0x14,0x1B,0x1F,0x17,0x17,0x17,
533
 
        0x17,0x17,0x1F,0x1E,0x17,0x1A,0x1A,0x1A,0x1A,0x17,0x1E,0x1E,0x23,0x25,0x27,0x25,
534
 
        0x23,0x1E,0x2F,0x2F,0x33,0x33,0x2F,0x2F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
535
 
        0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x01,0x11,0x0F,0x0F,0x11,0x13,0x11,0x15,0x12,
536
 
        0x12,0x15,0x14,0x11,0x14,0x11,0x14,0x1A,0x14,0x16,0x16,0x14,0x1A,0x26,0x1A,0x1A,
537
 
        0x1C,0x1A,0x1A,0x26,0x30,0x23,0x1E,0x1E,0x1E,0x1E,0x23,0x30,0x2B,0x2E,0x27,0x27,
538
 
        0x27,0x2E,0x2B,0x35,0x35,0x30,0x30,0x35,0x35,0x40,0x40,0x3F,0x40,0x40,0x40,0x40,
539
 
        0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0xC0,0x00,0x11,0x08,0x00,0x01,0x00,
540
 
        0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,0x01,0xFF,0xC4,0x00,0x4B,0x00,
541
 
        0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
542
 
        0x00,0x07,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
543
 
        0x00,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
544
 
        0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
545
 
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xDA,0x00,0x0C,0x03,0x01,0x00,0x02,
546
 
        0x11,0x03,0x11,0x00,0x3F,0x00,0xA0,0x00,0x0F,0xFF,0xD9 };
547
 
 
548
 
    JpegImage::JpegImage(BasicIo::AutoPtr io, bool create)
549
 
        : JpegBase(io, create, blank_, sizeof(blank_))
550
 
    {
551
 
    }
552
 
 
553
 
    //! @cond IGNORE
554
 
    JpegImage::JpegRegister::JpegRegister()
555
 
    {
556
 
        ImageFactory::registerImage(
557
 
            Image::jpeg, newJpegInstance, isJpegType);
558
 
    }
559
 
    //! @endcond
560
 
 
561
 
    int JpegImage::writeHeader(BasicIo& outIo) const
562
 
    {
563
 
        // Jpeg header
564
 
        byte tmpBuf[2];
565
 
        tmpBuf[0] = 0xff;
566
 
        tmpBuf[1] = soi_;
567
 
        if (outIo.write(tmpBuf, 2) != 2) return 4;
568
 
        if (outIo.error()) return 4;
569
 
        return 0;
570
 
    }
571
 
 
572
 
    bool JpegImage::isThisType(BasicIo& iIo, bool advance) const
573
 
    {
574
 
        return isJpegType(iIo, advance);
575
 
    }
576
 
 
577
 
    Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create)
578
 
    {
579
 
        Image::AutoPtr image = Image::AutoPtr(new JpegImage(io, create));
580
 
        if (!image->good()) {
581
 
            image.reset();
582
 
        }
583
 
        return image;
584
 
    }
585
 
 
586
 
    bool isJpegType(BasicIo& iIo, bool advance)
587
 
    {
588
 
        bool result = true;
589
 
        byte tmpBuf[2];
590
 
        iIo.read(tmpBuf, 2);
591
 
        if (iIo.error() || iIo.eof()) return false;
592
 
 
593
 
        if (0xff!=tmpBuf[0] || JpegImage::soi_!=tmpBuf[1]) {
594
 
            result = false;
595
 
        }
596
 
        if (!advance || !result ) iIo.seek(-2, BasicIo::cur);
597
 
        return result;
598
 
    }
599
 
 
600
 
    const char ExvImage::exiv2Id_[] = "Exiv2";
601
 
    const byte ExvImage::blank_[] = { 0xff,0x01,'E','x','i','v','2',0xff,0xd9 };
602
 
 
603
 
    ExvImage::ExvImage(BasicIo::AutoPtr io, bool create)
604
 
        : JpegBase(io, create, blank_, sizeof(blank_))
605
 
    {
606
 
    }
607
 
 
608
 
    //! @cond IGNORE
609
 
    ExvImage::ExvRegister::ExvRegister()
610
 
    {
611
 
        ImageFactory::registerImage(
612
 
            Image::exv, newExvInstance, isExvType);
613
 
    }
614
 
    //! @endcond
615
 
 
616
 
    int ExvImage::writeHeader(BasicIo& outIo) const
617
 
    {
618
 
        // Exv header
619
 
        byte tmpBuf[7];
620
 
        tmpBuf[0] = 0xff;
621
 
        tmpBuf[1] = 0x01;
622
 
        memcpy(tmpBuf + 2, exiv2Id_, 5);
623
 
        if (outIo.write(tmpBuf, 7) != 7) return 4;
624
 
        if (outIo.error()) return 4;
625
 
        return 0;
626
 
    }
627
 
 
628
 
    bool ExvImage::isThisType(BasicIo& iIo, bool advance) const
629
 
    {
630
 
        return isExvType(iIo, advance);
631
 
    }
632
 
 
633
 
    Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create)
634
 
    {
635
 
        Image::AutoPtr image;
636
 
        if (create) {
637
 
            image = Image::AutoPtr(new ExvImage(io, true));
638
 
        }
639
 
        else {
640
 
            image = Image::AutoPtr(new ExvImage(io, false));
641
 
        }
642
 
        if (!image->good()) image.reset();
643
 
        return image;
644
 
    }
645
 
 
646
 
    bool isExvType(BasicIo& iIo, bool advance)
647
 
    {
648
 
        bool result = true;
649
 
        byte tmpBuf[7];
650
 
        iIo.read(tmpBuf, 7);
651
 
        if (iIo.error() || iIo.eof()) return false;
652
 
 
653
 
        if (   0xff != tmpBuf[0] || 0x01 != tmpBuf[1]
654
 
            || memcmp(tmpBuf + 2, ExvImage::exiv2Id_, 5) != 0) {
655
 
            result = false;
656
 
        }
657
 
        if (!advance || !result ) iIo.seek(-7, BasicIo::cur);
658
 
        return result;
659
 
    }
660
 
 
661
 
}                                       // namespace Exiv2