~ubuntu-branches/debian/lenny/exiv2/lenny

« back to all changes in this revision

Viewing changes to src/jp2image.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2008-06-21 08:23:53 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20080621082353-b1n4w08trwfwbfl4
Tags: 0.17.1-1
* New upstream release
  - Library transition cleared on debian-release/ d-d-a
* Version 0.17 also fixes:
  - CVE-2008-2696: DoS via metadata in images (Closes: #486328)
  - crashes when fed with wrong file (Closes: #485670)
* Urgency medium for CVE fix
* debian/patches/gcc4.3.diff unecessary for gcc-4.3
* Add /usr/share/bug/exiv2/presubj message for reportbug(1)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ***************************************************************** -*- C++ -*-
 
2
/*
 
3
 * Copyright (C) 2004-2008 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
 
20
 */
 
21
/*
 
22
  File:      jp2image.cpp
 
23
  Version:   $Rev$
 
24
  Author(s): Marco Piovanelli, Ovolab (marco)
 
25
  History:   12-Mar-2007, marco: created
 
26
 */
 
27
// *****************************************************************************
 
28
#include "rcsid.hpp"
 
29
EXIV2_RCSID("@(#) $Id$")
 
30
 
 
31
//#define DEBUG 1
 
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
#include "jp2image.hpp"
 
41
#include "image.hpp"
 
42
#include "basicio.hpp"
 
43
#include "error.hpp"
 
44
#include "futils.hpp"
 
45
 
 
46
// + standard includes
 
47
#include <string>
 
48
#include <cstring>
 
49
#include <iostream>
 
50
 
 
51
// JPEG-2000 box types
 
52
const uint32_t kJp2BoxTypeJp2Header   = 0x6a703268; // 'jp2h'
 
53
const uint32_t kJp2BoxTypeImageHeader = 0x69686472; // 'ihdr'
 
54
const uint32_t kJp2BoxTypeUuid        = 0x75756964; // 'uuid'
 
55
 
 
56
// JPEG-2000 UUIDs for embedded metadata
 
57
//
 
58
// See http://www.jpeg.org/public/wg1n2600.doc for information about embedding IPTC-NAA data in JPEG-2000 files
 
59
// See http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf for information about embedding XMP data in JPEG-2000 files
 
60
const char* const kJp2UuidExif = "JpgTiffExif->JP2";
 
61
const char* const kJp2UuidIptc = "\x33\xc7\xa4\xd2\xb8\x1d\x47\x23\xa0\xba\xf1\xa3\xe0\x97\xad\x38";
 
62
const char* const kJp2UuidXmp  = "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac";
 
63
 
 
64
//! @cond IGNORE
 
65
struct Jp2BoxHeader {
 
66
    uint32_t boxLength;
 
67
    uint32_t boxType;
 
68
};
 
69
 
 
70
struct Jp2ImageHeaderBox {
 
71
    uint32_t imageHeight;
 
72
    uint32_t imageWidth;
 
73
    uint16_t componentCount;
 
74
    uint8_t  bitsPerComponent;
 
75
    uint8_t  compressionType;
 
76
    uint8_t  colorspaceIsUnknown;
 
77
    uint8_t  intellectualPropertyFlag;
 
78
    uint16_t compressionTypeProfile;
 
79
};
 
80
 
 
81
struct Jp2UuidBox {
 
82
    uint8_t  uuid[16];
 
83
};
 
84
//! @endcond
 
85
 
 
86
// *****************************************************************************
 
87
// class member definitions
 
88
namespace Exiv2 {
 
89
 
 
90
    Jp2Image::Jp2Image(BasicIo::AutoPtr io)
 
91
        : Image(ImageType::jp2, mdExif | mdIptc | mdXmp, io)
 
92
    {
 
93
    } // Jp2Image::Jp2Image
 
94
 
 
95
    void Jp2Image::setExifData(const ExifData& /*exifData*/)
 
96
    {
 
97
        // Todo: implement me!
 
98
        throw(Error(32, "Exif metadata", "JP2"));
 
99
    }
 
100
 
 
101
    void Jp2Image::setIptcData(const IptcData& /*iptcData*/)
 
102
    {
 
103
        // Todo: implement me!
 
104
        throw(Error(32, "IPTC metadata", "JP2"));
 
105
    }
 
106
 
 
107
    void Jp2Image::setComment(const std::string& /*comment*/)
 
108
    {
 
109
        // Todo: implement me!
 
110
        throw(Error(32, "Image comment", "JP2"));
 
111
    }
 
112
 
 
113
    void Jp2Image::readMetadata()
 
114
    {
 
115
#ifdef DEBUG
 
116
        std::cerr << "Exiv2::Jp2Image::readMetadata: Reading JPEG-2000 file " << io_->path() << "\n";
 
117
#endif
 
118
        if (io_->open() != 0) 
 
119
        {
 
120
            throw Error(9, io_->path(), strError());
 
121
        }
 
122
        IoCloser closer(*io_);
 
123
        // Ensure that this is the correct image type
 
124
        if (!isJp2Type(*io_, true)) 
 
125
        {
 
126
            if (io_->error() || io_->eof()) throw Error(14);
 
127
            throw Error(3, "JPEG-2000");
 
128
        }
 
129
 
 
130
        Jp2BoxHeader      box       = {0,0};
 
131
        Jp2BoxHeader      subBox    = {0,0};
 
132
        Jp2ImageHeaderBox ihdr      = {0,0,0,0,0,0,0,0};
 
133
        Jp2UuidBox        uuid      = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
 
134
        long              curOffset = io_->tell();
 
135
 
 
136
        while (io_->read((byte*)&box, sizeof(box)) == sizeof(box))
 
137
        {
 
138
            box.boxLength = getLong((byte*)&box.boxLength, bigEndian);
 
139
            box.boxType = getLong((byte*)&box.boxType, bigEndian);
 
140
 
 
141
            if (box.boxLength == 0)
 
142
            {
 
143
                break;
 
144
            }
 
145
 
 
146
            switch(box.boxType)
 
147
            {
 
148
                case kJp2BoxTypeJp2Header:
 
149
                {
 
150
                    if (io_->read((byte*)&subBox, sizeof(subBox)) == sizeof(subBox))
 
151
                    {
 
152
                        subBox.boxLength = getLong((byte*)&subBox.boxLength, bigEndian);
 
153
                        subBox.boxType = getLong((byte*)&subBox.boxType, bigEndian);
 
154
 
 
155
                        if((subBox.boxType == kJp2BoxTypeImageHeader) && (io_->read((byte*)&ihdr, sizeof(ihdr)) == sizeof(ihdr)))
 
156
                        {
 
157
                            ihdr.imageHeight = getLong((byte*)&ihdr.imageHeight, bigEndian);
 
158
                            ihdr.imageWidth = getLong((byte*)&ihdr.imageWidth, bigEndian);
 
159
                            ihdr.componentCount = getShort((byte*)&ihdr.componentCount, bigEndian);
 
160
                            ihdr.compressionTypeProfile = getShort((byte*)&ihdr.compressionTypeProfile, bigEndian);
 
161
 
 
162
                            pixelWidth_ = ihdr.imageWidth;
 
163
                            pixelHeight_ = ihdr.imageHeight;
 
164
                        }
 
165
                    }
 
166
                    break;
 
167
                }
 
168
 
 
169
                case kJp2BoxTypeUuid:
 
170
                {
 
171
                    if (io_->read((byte*)&uuid, sizeof(uuid)) == sizeof(uuid))
 
172
                    {
 
173
                        if(memcmp(uuid.uuid, kJp2UuidExif, sizeof(uuid)) == 0)
 
174
                        {
 
175
                            // we've hit an embedded Exif block
 
176
                            DataBuf rawExif(box.boxLength - (sizeof(box) + sizeof(uuid)));
 
177
                            io_->read(rawExif.pData_, rawExif.size_);
 
178
                            if (io_->error() || io_->eof()) throw Error(14);
 
179
                            if (exifData_.load(rawExif.pData_, rawExif.size_)) {
 
180
#ifndef SUPPRESS_WARNINGS
 
181
                                std::cerr << "Warning: Failed to decode Exif metadata.\n";
 
182
#endif
 
183
                                exifData_.clear();
 
184
                            }
 
185
                        }
 
186
                        else if(memcmp(uuid.uuid, kJp2UuidIptc, sizeof(uuid)) == 0)
 
187
                        {
 
188
                            // we've hit an embedded IPTC block
 
189
                            DataBuf rawIPTC(box.boxLength - (sizeof(box) + sizeof(uuid)));
 
190
                            io_->read(rawIPTC.pData_, rawIPTC.size_);
 
191
                            if (io_->error() || io_->eof()) throw Error(14);
 
192
                            if (iptcData_.load(rawIPTC.pData_, rawIPTC.size_)) {
 
193
#ifndef SUPPRESS_WARNINGS
 
194
                                std::cerr << "Warning: Failed to decode IPTC metadata.\n";
 
195
#endif
 
196
                                iptcData_.clear();
 
197
                            }
 
198
                        }
 
199
                        else if(memcmp(uuid.uuid, kJp2UuidXmp, sizeof(uuid)) == 0)
 
200
                        {
 
201
                            // we've hit an embedded XMP block
 
202
                            DataBuf xmpPacket(box.boxLength - (sizeof(box) + sizeof(uuid)));
 
203
                            io_->read(xmpPacket.pData_, xmpPacket.size_);
 
204
                            if (io_->error() || io_->eof()) throw Error(14);
 
205
                            xmpPacket_.assign(reinterpret_cast<char *>(xmpPacket.pData_), xmpPacket.size_);
 
206
                            if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) {
 
207
#ifndef SUPPRESS_WARNINGS
 
208
                                std::cerr << "Warning: Failed to decode XMP metadata.\n";
 
209
#endif
 
210
                            }
 
211
                        }
 
212
                    }
 
213
                    break;
 
214
                }
 
215
 
 
216
                default:
 
217
                {
 
218
                    break;
 
219
                }
 
220
            }
 
221
 
 
222
            curOffset += box.boxLength;
 
223
            if(io_->seek(curOffset, BasicIo::beg) != 0)
 
224
            {
 
225
                break;        // Todo: should throw an error here
 
226
            }
 
227
        }
 
228
    } // Jp2Image::readMetadata
 
229
 
 
230
    void Jp2Image::writeMetadata()
 
231
    {
 
232
        // Todo: implement me!
 
233
        throw(Error(31, "JP2"));
 
234
    } // Jp2Image::writeMetadata
 
235
 
 
236
    // *************************************************************************
 
237
    // free functions
 
238
    Image::AutoPtr newJp2Instance(BasicIo::AutoPtr io, bool /*create*/)
 
239
    {
 
240
        Image::AutoPtr image(new Jp2Image(io));
 
241
        if (!image->good()) 
 
242
        {
 
243
            image.reset();
 
244
        }
 
245
        return image;
 
246
    }
 
247
 
 
248
    bool isJp2Type(BasicIo& iIo, bool advance)
 
249
    {
 
250
        // see section B.1.1 (JPEG 2000 Signature box) of JPEG-2000 specification
 
251
        const int32_t len = 12;
 
252
        const unsigned char Jp2Header[len] = { 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a };
 
253
        byte buf[len];
 
254
        iIo.read(buf, len);
 
255
        if (iIo.error() || iIo.eof()) 
 
256
        {
 
257
            return false;
 
258
        }
 
259
        bool matched = (memcmp(buf, Jp2Header, len) == 0);
 
260
        if (!advance || !matched) 
 
261
        {
 
262
            iIo.seek(-len, BasicIo::cur);
 
263
        }
 
264
        return matched;
 
265
    }
 
266
}                                       // namespace Exiv2