Author: post
Date: 2009-08-16 21:53:28 +0200 (Sun, 16 Aug 2009)
New Revision: 116
Modified:
RawSpeed/Cr2Decoder.cpp
RawSpeed/DngDecoder.cpp
RawSpeed/DngDecoderSlices.cpp
RawSpeed/DngDecoderSlices.h
RawSpeed/FileMap.cpp
RawSpeed/FileMap.h
RawSpeed/LJpegDecompressor.cpp
RawSpeed/LJpegPlain.cpp
RawSpeed/LJpegPlain.h
RawSpeed/NefDecoder.cpp
RawSpeed/NikonDecompressor.cpp
RawSpeed/OrfDecoder.cpp
RawSpeed/PefDecoder.cpp
RawSpeed/PentaxDecompressor.cpp
RawSpeed/RawImage.cpp
RawSpeed/RawSpeed.cpp
RawSpeed/TiffEntry.cpp
RawSpeed/TiffEntry.h
RawSpeed/TiffEntryBE.cpp
RawSpeed/TiffIFD.cpp
RawSpeed/TiffIFDBE.cpp
Log:
- Hardened reader, by creating randomly corrupted files and attempting to read
them. Test framework reads a file and tries 50 permutations, where 1000 random
bytes are changed each time. Changes are:
* DNG with large tiles/slices are read faster.
* Subsampled images must be created by the decoder, to avoid race condition,
where it it changed on the fly.
* Sizes are correctly validated in TIFF tags (unsigned <-> signed collision)
* Clarified some error messages.
* Slice width is copied to separate array to enable stateless multiple decode,
if another SOF should follow the active.
* Nikon/Pentax/Sony is better checked for out-of-file reads. Decoder silently
aborts to return decoded data.
* Nikon checks if values are valid before linearization table lookup.
* Excessively large images cannot be created (currently max width/height is
65525 pixels.
* IFD offsets are checked before they are accessed.
Modified: RawSpeed/Cr2Decoder.cpp
===================================================================
--- RawSpeed/Cr2Decoder.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/Cr2Decoder.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -80,9 +80,19 @@
mRaw->bpp = 2;
mRaw->dim = iPoint2D(slices[0].w, completeH);
+
+ if(raw->hasEntry((TiffTag)0xc6c5)) {
+ gushort ss = raw->getEntry((TiffTag)0xc6c5)->getInt();
+ // sRaw
+ if (ss == 4) {
+ mRaw->dim.x /= 3;
+ mRaw->setCpp(3);
+ mRaw->isCFA = false;
+ }
+ }
+
mRaw->createData();
-
vector<int> s_width;
if (raw->hasEntry(CANONCR2SLICE)) {
const gushort *ss = raw->getEntry(CANONCR2SLICE)->getShortArray();
@@ -108,6 +118,9 @@
// These may just be single slice error - store the error and move on
errors.push_back(_strdup(e.what()));
}
+ catch (IOException e) {
+ // Let's try to ignore this - it might be truncated data, so something
might be useful.
+ }
offY += slice.w;
}
Modified: RawSpeed/DngDecoder.cpp
===================================================================
--- RawSpeed/DngDecoder.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/DngDecoder.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -225,6 +225,7 @@
for (guint y=0; y< tilesY; y++) {
for (guint x=0; x< tilesX; x++) {
DngSliceElement e(offsets[x+y*tilesX], counts[x+y*tilesX],
tilew*x, tileh*y);
+ e.mUseBigtable = tilew*tileh > 1024*1024;
slices.addSlice(e);
}
}
@@ -243,6 +244,7 @@
guint offY = 0;
for (guint s = 0; s<TEcounts->count; s++) {
DngSliceElement e(offsets[s], counts[s], 0, offY);
+ e.mUseBigtable = yPerSlice*mRaw->dim.y > 1024*1024;
offY +=yPerSlice;
if (mFile->isValid(e.byteOffset+e.byteCount)) // Only decode if
size is valid
Modified: RawSpeed/DngDecoderSlices.cpp
===================================================================
--- RawSpeed/DngDecoderSlices.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/DngDecoderSlices.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -79,11 +79,16 @@
t->slices.pop();
try {
l.startDecoder(e.byteOffset, e.byteCount, e.offX, e.offY);
- } catch (RawDecoderException e) {
+ } catch (RawDecoderException err) {
pthread_mutex_lock(&errMutex);
- errors.push_back(_strdup(e.what()));
+ errors.push_back(_strdup(err.what()));
pthread_mutex_unlock(&errMutex);
}
+ catch (IOException err) {
+ pthread_mutex_lock(&errMutex);
+ errors.push_back("DngDecoderSlices::decodeSlice: IO error occurred,
probably attempted to read past end of file.");
+ pthread_mutex_unlock(&errMutex);
+ }
}
}
Modified: RawSpeed/DngDecoderSlices.h
===================================================================
--- RawSpeed/DngDecoderSlices.h 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/DngDecoderSlices.h 2009-08-16 19:53:28 UTC (rev 116)
@@ -29,12 +29,13 @@
{
public:
DngSliceElement(guint off, guint count, guint offsetX, guint offsetY) :
- byteOffset(off), byteCount(count), offX(offsetX), offY(offsetY) {};
+ byteOffset(off), byteCount(count), offX(offsetX), offY(offsetY),
mUseBigtable(false) {};
~DngSliceElement(void) {};
const guint byteOffset;
const guint byteCount;
const guint offX;
const guint offY;
+ gboolean mUseBigtable;
};
class DngDecoderSlices;
Modified: RawSpeed/FileMap.cpp
===================================================================
--- RawSpeed/FileMap.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/FileMap.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -44,3 +44,18 @@
data = 0;
size = 0;
}
+
+FileMap* FileMap::clone()
+{
+ FileMap *new_map = new FileMap(size);
+ memcpy(new_map->data, data, size);
+ return new_map;
+}
+
+void FileMap::corrupt( int errors )
+{
+ for (int i = 0; i < errors; i++) {
+ guint pos = ( rand() | (rand()<<15) ) % size;
+ data[pos] = rand()&0xff;
+ }
+}
\ No newline at end of file
Modified: RawSpeed/FileMap.h
===================================================================
--- RawSpeed/FileMap.h 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/FileMap.h 2009-08-16 19:53:28 UTC (rev 116)
@@ -39,6 +39,8 @@
guchar* getDataWrt(guint offset) {return &data[offset];}
guint getSize() {return size;}
gboolean isValid(guint offset) {return offset<=size;}
+ FileMap* clone();
+ void corrupt(int errors);
private:
guchar* data;
guint size;
Modified: RawSpeed/LJpegDecompressor.cpp
===================================================================
--- RawSpeed/LJpegDecompressor.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/LJpegDecompressor.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -104,7 +104,7 @@
void LJpegDecompressor::getSOF( SOFInfo* sof, guint offset, guint size )
{
if (!mFile->isValid(offset+size-1))
- ThrowRDE("LJpegDecompressor::getSOF: Max offset before out of file,
invalid data");
+ ThrowRDE("LJpegDecompressor::getSOF: Start offset plus size is longer than
file. Truncated file.");
try {
input = new ByteStream(mFile->getData(offset), size);
@@ -129,7 +129,7 @@
void LJpegDecompressor::startDecoder(guint offset, guint size, guint offsetX,
guint offsetY) {
if (!mFile->isValid(offset+size-1))
- ThrowRDE("LJpegDecompressor::startDecoder: Max offset before out of file,
invalid data");
+ ThrowRDE("LJpegDecompressor::startDecoder: Start offset plus size is
longer than file. Truncated file.");
if ((gint)offsetX>=mRaw->dim.x)
ThrowRDE("LJpegDecompressor::startDecoder: X offset outside of image");
if ((gint)offsetY>=mRaw->dim.y)
@@ -187,7 +187,7 @@
}
} catch (IOException) {
- ThrowRDE("LJpegDecompressor: Bitpump exception, read outside file. Corrupt
File.");
+ throw;
}
}
@@ -248,18 +248,16 @@
ThrowRDE("LJpegDecompressor::parseSOS: Invalid Huffman table selection,
not defined.");
frame.compInfo[count].dcTblNo = td;
-// _RPT2(0,"Component Selector:%u, Table Dest:%u\n",cs, td);
}
+ // Get predictor
pred = input->getByte();
-// _RPT1(0,"Predictor:%u, ",pred);
if (pred>7)
ThrowRDE("LJpegDecompressor::parseSOS: Invalid predictor mode.");
input->skipBytes(1); // Se + Ah Not used in LJPEG
guint b = input->getByte();
Pt = b&0xf; // Point Transform
-// _RPT1(0,"Point transform:%u\n",Pt);
guint cheadersize = 3+frame.cps * 2 + 3;
_ASSERTE(cheadersize == headerLength);
@@ -288,7 +286,6 @@
guint Th = b&0xf;
if (Th>3)
ThrowRDE("LJpegDecompressor::parseDHT: Invalid huffman table
destination id.");
-// _RPT1(0, "Decoding Table:%u\n",Th);
guint acc = 0;
HuffmanTable* t = &huff[Th];
@@ -564,7 +561,7 @@
*/
if (l > frame.prec || htbl->valptr[l] == 0xff) {
- ThrowRDE("Corrupt JPEG data: bad Huffman code:%u\n",l);
+ ThrowRDE("Corrupt JPEG data: bad Huffman code:%u",l);
} else {
rv = htbl->huffval[htbl->valptr[l] +
((int)(code - htbl->mincode[l]))];
@@ -582,7 +579,10 @@
* Figure F.12: extend sign bit
*/
if ((rv+l)>24) // Ensure we have enough bits
- bits->fill();
+ if (rv>16) // There is no values above 16 bits.
+ ThrowRDE("Corrupt JPEG data: Too many bits requested.");
+ else
+ bits->fill();
if (rv) {
gint x = bits->getBitsNoFill(rv);
Modified: RawSpeed/LJpegPlain.cpp
===================================================================
--- RawSpeed/LJpegPlain.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/LJpegPlain.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -1,38 +1,43 @@
#include "StdAfx.h"
#include "LJpegPlain.h"
/*
- RawSpeed - RAW file decoder.
+RawSpeed - RAW file decoder.
- Copyright (C) 2009 Klaus Post
+Copyright (C) 2009 Klaus Post
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- http://www.klauspost.com
+http://www.klauspost.com
*/
LJpegPlain::LJpegPlain( FileMap* file, RawImage img ) :
- LJpegDecompressor(file,img)
+LJpegDecompressor(file,img)
{
offset = 0;
+ slice_width = 0;
}
LJpegPlain::~LJpegPlain(void)
{
if (offset)
delete(offset);
+ offset = 0;
+ if (slice_width)
+ delete(slice_width);
+ slice_width = 0;
}
void LJpegPlain::decodeScan() {
@@ -44,15 +49,15 @@
if (slicesW.empty())
slicesW.push_back(frame.w*frame.cps);
-
+
for (guint i = 0; i < frame.cps; i++) {
- if (frame.compInfo[i].superH != 1 || frame.compInfo[i].superV != 1) {
- mRaw->destroyData();
- mRaw->dim.x /= frame.cps;
- mRaw->setCpp(frame.cps);
- mRaw->isCFA = false;
- mRaw->createData();
+ if (frame.compInfo[i].superH != 1 || frame.compInfo[i].superV != 1) {
+ if (mRaw->isCFA)
+ ThrowRDE("LJpegDecompressor::decodeScan: Cannot decode subsampled
image to CFA data");
+ if (mRaw->getCpp() != frame.cps)
+ ThrowRDE("LJpegDecompressor::decodeScan: Subsampled component count
does not match image.");
+
if (pred == 1) {
if (frame.compInfo[0].superH == 2 && frame.compInfo[0].superV == 2 &&
frame.compInfo[1].superH == 1 && frame.compInfo[1].superV == 1 &&
@@ -62,12 +67,12 @@
decodeScanLeft4_2_0();
return;
} else if (frame.compInfo[0].superH == 2 && frame.compInfo[0].superV
== 1 &&
- frame.compInfo[1].superH == 1 && frame.compInfo[1].superV == 1 &&
- frame.compInfo[2].superH == 1 && frame.compInfo[2].superV == 1)
- {
- // Something like Cr2 sRaw2, use fast decoder
- decodeScanLeft4_2_2();
- return;
+ frame.compInfo[1].superH == 1 && frame.compInfo[1].superV == 1 &&
+ frame.compInfo[2].superH == 1 && frame.compInfo[2].superV == 1)
+ {
+ // Something like Cr2 sRaw2, use fast decoder
+ decodeScanLeft4_2_2();
+ return;
} else {
decodeScanLeftGeneric();
return;
@@ -93,18 +98,18 @@
}
/**
- * CR2 Slice handling:
- * In the following code, canon slices are handled in-place, to avoid having
to
- * copy the entire frame afterwards.
- * The "offset" array is created to easily map slice positions on to the
output image.
- * The offset array size is the number of slices multiplied by height.
- * Each of these offsets are an offset into the destination image, and it
also contains the
- * slice number (shifted up 28 bits), so it is possible to retrieve the width
of each slice.
- * Every time "components" pixels has been processed the slice size is
tested, and output offset
- * is adjusted if needed. This makes slice handling very "light", since it
involves a single
- * counter, and a predictable branch.
- * For unsliced images, add one slice with the width of the image.
- **/
+* CR2 Slice handling:
+* In the following code, canon slices are handled in-place, to avoid having to
+* copy the entire frame afterwards.
+* The "offset" array is created to easily map slice positions on to the
output image.
+* The offset array size is the number of slices multiplied by height.
+* Each of these offsets are an offset into the destination image, and it also
contains the
+* slice number (shifted up 28 bits), so it is possible to retrieve the width
of each slice.
+* Every time "components" pixels has been processed the slice size is tested,
and output offset
+* is adjusted if needed. This makes slice handling very "light", since it
involves a single
+* counter, and a predictable branch.
+* For unsliced images, add one slice with the width of the image.
+**/
void LJpegPlain::decodeScanLeftGeneric() {
_ASSERTE(slicesW.size()<16); // We only have 4 bits for slice number.
@@ -114,8 +119,8 @@
HuffmanTable *dctbl[4]; // Tables for up to 4 components
gushort *predict; // Prediction pointer
/* Fast access to supersampling component settings
- * this is the number of components in a given block.
- */
+ * this is the number of components in a given block.
+ */
guint samplesH[4];
guint samplesV[4];
@@ -151,10 +156,11 @@
guint t_s = 0;
guint slice = 0;
guint pitch_s = mRaw->pitch/2; // Pitch in shorts
+ slice_width = new int[slices];
// This is divided by comps, since comps pixels are processed at the time
for (guint i = 0 ; i < slicesW.size(); i++)
- slicesW[i] /= pixGroup/maxSuperH; // This is a guess, but works for
sRaw1+2.
+ slice_width[i] = slicesW[i] / pixGroup/maxSuperH; // This is a guess,
but works for sRaw1+2.
for (slice = 0; slice< slices; slice++) {
offset[slice] = ((t_x+offX)*mRaw->bpp+((offY+t_y)*mRaw->pitch)) |
(t_s<<28);
@@ -162,13 +168,13 @@
t_y += maxSuperV;
if (t_y >= (frame.h-skipY)) {
t_y = 0;
- t_x += slicesW[t_s++];
+ t_x += slice_width[t_s++];
}
}
offset[slices] = offset[slices-1]; // Extra offset to avoid branch in
loop.
if (skipX)
- slicesW[slicesW.size()-1] -= skipX;
+ slice_width[slicesW.size()-1] -= skipX;
// Predictors for components
gint p[4];
@@ -176,7 +182,7 @@
// Always points to next slice
slice = 1;
- guint pixInSlice = slicesW[0];
+ guint pixInSlice = slice_width[0];
// Initialize predictors and decode one group.
guint x = 0;
@@ -213,7 +219,7 @@
guint o = offset[slice++];
dest = (gushort*)&draw[o&0x0fffffff]; // Adjust destination for next
pixel
_ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
- pixInSlice = slicesW[o>>28];
+ pixInSlice = slice_width[o>>28];
// If new are at the start of a new line, also update predictors.
if (x == 0)
@@ -221,14 +227,14 @@
}
for (guint i = 0; i < comps; i++) {
- for (guint y2 = 0; y2 < samplesV[i]; y2++) {
- for (guint x2 = 0; x2 < samplesH[i]; x2++) {
- p[i] += HuffDecode(dctbl[i]);
- _ASSERTE(p[i]>=0 && p[i]<65536);
- dest[x2*comps+y2*pitch_s] = p[i];
- }
- }
- dest++;
+ for (guint y2 = 0; y2 < samplesV[i]; y2++) {
+ for (guint x2 = 0; x2 < samplesH[i]; x2++) {
+ p[i] += HuffDecode(dctbl[i]);
+ _ASSERTE(p[i]>=0 && p[i]<65536);
+ dest[x2*comps+y2*pitch_s] = p[i];
+ }
+ }
+ dest++;
}
dest += (maxSuperH*comps) - comps;
pixInSlice -= maxSuperH;
@@ -293,10 +299,11 @@
guint t_s = 0;
guint slice = 0;
guint pitch_s = mRaw->pitch/2; // Pitch in shorts
+ slice_width = new int[slices];
// This is divided by comps, since comps pixels are processed at the time
for (guint i = 0 ; i < slicesW.size(); i++)
- slicesW[i] /= COMPS;
+ slice_width[i] = slicesW[i] / COMPS;
for (slice = 0; slice< slices; slice++) {
offset[slice] = ((t_x+offX)*mRaw->bpp+((offY+t_y)*mRaw->pitch)) |
(t_s<<28);
@@ -304,20 +311,20 @@
t_y += 2;
if (t_y >= (frame.h-skipY)) {
t_y = 0;
- t_x += slicesW[t_s++];
+ t_x += slice_width[t_s++];
}
}
offset[slices] = offset[slices-1]; // Extra offset to avoid branch in
loop.
if (skipX)
- slicesW[slicesW.size()-1] -= skipX;
+ slice_width[slicesW.size()-1] -= skipX;
// Predictors for components
gushort *dest = (gushort*)&draw[offset[0]&0x0fffffff];
// Always points to next slice
slice = 1;
- guint pixInSlice = slicesW[0];
+ guint pixInSlice = slice_width[0];
// Initialize predictors and decode one group.
guint x = 0;
@@ -348,7 +355,7 @@
guint o = offset[slice++];
dest = (gushort*)&draw[o&0x0fffffff]; // Adjust destination for next
pixel
_ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
- pixInSlice = slicesW[o>>28];
+ pixInSlice = slice_width[o>>28];
// If new are at the start of a new line, also update predictors.
if (x == 0) {
@@ -418,10 +425,11 @@
guint t_x = 0;
guint t_s = 0;
guint slice = 0;
+ slice_width = new int[slices];
// This is divided by comps, since comps pixels are processed at the time
for (guint i = 0 ; i < slicesW.size(); i++)
- slicesW[i] /= 2;
+ slice_width[i] = slicesW[i]/2;
for (slice = 0; slice< slices; slice++) {
offset[slice] = ((t_x+offX)*mRaw->bpp+((offY+t_y)*mRaw->pitch)) |
(t_s<<28);
@@ -429,20 +437,20 @@
t_y ++;
if (t_y >= (frame.h-skipY)) {
t_y = 0;
- t_x += slicesW[t_s++];
+ t_x += slice_width[t_s++];
}
}
offset[slices] = offset[slices-1]; // Extra offset to avoid branch in
loop.
if (skipX)
- slicesW[slicesW.size()-1] -= skipX;
+ slice_width[slicesW.size()-1] -= skipX;
// Predictors for components
gushort *dest = (gushort*)&draw[offset[0]&0x0fffffff];
// Always points to next slice
slice = 1;
- guint pixInSlice = slicesW[0];
+ guint pixInSlice = slice_width[0];
// Initialize predictors and decode one group.
guint x = 0;
@@ -471,7 +479,7 @@
guint o = offset[slice++];
dest = (gushort*)&draw[o&0x0fffffff]; // Adjust destination for next
pixel
_ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
- pixInSlice = slicesW[o>>28];
+ pixInSlice = slice_width[o>>28];
// If new are at the start of a new line, also update predictors.
if (x == 0) {
@@ -521,6 +529,7 @@
guint t_x = 0;
guint t_s = 0;
guint slice = 0;
+ guint cw = (frame.w-skipX);
for (slice = 0; slice< slices; slice++) {
offset[slice] = ((t_x+offX)*mRaw->bpp+((offY+t_y)*mRaw->pitch)) |
(t_s<<28);
_ASSERTE((offset[slice]&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
@@ -532,13 +541,15 @@
}
offset[slices] = offset[slices-1]; // Extra offset to avoid branch in
loop.
- if (skipX)
- slicesW[slicesW.size()-1] -= skipX*frame.cps;
+ slice_width = new int[slices];
// This is divided by comps, since comps pixels are processed at the time
for (guint i = 0 ; i < slicesW.size(); i++)
- slicesW[i] /= COMPS;
+ slice_width[i] = slicesW[i] / COMPS;
+ if (skipX)
+ slice_width[slicesW.size()-1] -= skipX;
+
// First pixels are obviously not predicted
gint p1;
gint p2;
@@ -547,20 +558,17 @@
*dest++ = p1 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl1);
*dest++ = p2 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl2);
- slices = (guint)slicesW.size();
slice = 1; // Always points to next slice
- guint pixInSlice = slicesW[0]-1; // Skip first pixel
+ guint pixInSlice = slice_width[0]-1; // Skip first pixel
- guint cw = (frame.w-skipX);
guint x = 1; // Skip first pixels on first line.
-
for (guint y=0;y<(frame.h-skipY);y++) {
for (; x < cw ; x++) {
gint diff = HuffDecode(dctbl1);
p1 += diff;
*dest++ = (gushort)p1;
_ASSERTE(p1>=0 && p1<65536);
-
+
diff = HuffDecode(dctbl2);
p2 += diff;
*dest++ = (gushort)p2;
@@ -570,16 +578,18 @@
guint o = offset[slice++];
dest = (gushort*)&draw[o&0x0fffffff]; // Adjust destination for next
pixel
_ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
- pixInSlice = slicesW[o>>28];
+ pixInSlice = slice_width[o>>28];
}
bits->checkPos();
}
+
if (skipX) {
for (guint i = 0; i < skipX; i++) {
HuffDecode(dctbl1);
HuffDecode(dctbl2);
}
}
+
p1 = predict[0]; // Predictors for next row
p2 = predict[1];
predict = dest; // Adjust destination for next prediction
@@ -614,15 +624,18 @@
t_x += slicesW[t_s++];
}
}
+
offset[slices] = offset[slices-1]; // Extra offset to avoid branch in
loop.
- if (skipX)
- slicesW[slicesW.size()-1] -= skipX*frame.cps;
+ slice_width = new int[slices];
// This is divided by comps, since comps pixels are processed at the time
for (guint i = 0 ; i < slicesW.size(); i++)
- slicesW[i] /= COMPS;
+ slice_width[i] = slicesW[i] / COMPS;
+ if (skipX)
+ slice_width[slicesW.size()-1] -= skipX;
+
// First pixels are obviously not predicted
gint p1;
gint p2;
@@ -633,9 +646,8 @@
*dest++ = p2 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl2);
*dest++ = p3 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl3);
- slices = (guint)slicesW.size();
slice = 1;
- guint pixInSlice = slicesW[0]-1;
+ guint pixInSlice = slice_width[0]-1;
guint cw = (frame.w-skipX);
guint x = 1; // Skip first pixels on first line.
@@ -654,11 +666,13 @@
if (0 == --pixInSlice) { // Next slice
guint o = offset[slice++];
dest = (gushort*)&draw[o&0x0fffffff]; // Adjust destination for next
pixel
- _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
- pixInSlice = slicesW[o>>28];
+ _ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
+ _ASSERTE((o>>28) < slicesW.size());
+ pixInSlice = slice_width[o>>28];
}
bits->checkPos();
}
+
if (skipX) {
for (guint i = 0; i < skipX; i++) {
HuffDecode(dctbl1);
@@ -666,6 +680,7 @@
HuffDecode(dctbl3);
}
}
+
p1 = predict[0]; // Predictors for next row
p2 = predict[1];
p3 = predict[2]; // Predictors for next row
@@ -704,8 +719,14 @@
}
offset[slices] = offset[slices-1]; // Extra offset to avoid branch in
loop.
+ slice_width = new int[slices];
+
+ // This is divided by comps, since comps pixels are processed at the time
+ for (guint i = 0 ; i < slicesW.size(); i++)
+ slice_width[i] = slicesW[i] / COMPS;
+
if (skipX)
- slicesW[slicesW.size()-1] -= skipX*frame.cps;
+ slice_width[slicesW.size()-1] -= skipX;
// First pixels are obviously not predicted
gint p1;
@@ -719,13 +740,8 @@
*dest++ = p3 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl3);
*dest++ = p4 = (1<<(frame.prec-Pt-1)) + HuffDecode(dctbl4);
- // This is divided by comps, since comps pixels are processed at the time
- for (guint i = 0 ; i < slicesW.size(); i++)
- slicesW[i] /= COMPS;
-
- slices = (guint)slicesW.size();
slice = 1;
- guint pixInSlice = slicesW[0]-1;
+ guint pixInSlice = slice_width[0]-1;
guint cw = (frame.w-skipX);
guint x = 1; // Skip first pixels on first line.
@@ -748,7 +764,7 @@
guint o = offset[slice++];
dest = (gushort*)&draw[o&0x0fffffff]; // Adjust destination for next
pixel
_ASSERTE((o&0x0fffffff)<mRaw->pitch*mRaw->dim.y);
- pixInSlice = slicesW[o>>28];
+ pixInSlice = slice_width[o>>28];
}
bits->checkPos();
}
Modified: RawSpeed/LJpegPlain.h
===================================================================
--- RawSpeed/LJpegPlain.h 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/LJpegPlain.h 2009-08-16 19:53:28 UTC (rev 116)
@@ -43,4 +43,5 @@
void decodeScanLeft4_2_0();
void decodeScanLeft4_2_2();
guint *offset;
+ int* slice_width;
};
Modified: RawSpeed/NefDecoder.cpp
===================================================================
--- RawSpeed/NefDecoder.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/NefDecoder.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -107,9 +107,12 @@
}
ByteStream metadata(meta->getData(), meta->count);
-
- NikonDecompressor decompressor(mFile,mRaw);
- decompressor.DecompressNikon(metadata, width, height,
bitPerPixel,offsets->getInt(),counts->getInt());
+ try {
+ NikonDecompressor decompressor(mFile,mRaw);
+ decompressor.DecompressNikon(metadata, width, height,
bitPerPixel,offsets->getInt(),counts->getInt());
+ } catch (IOException e) {
+ // Let's ignore it, it may have delivered somewhat useful data.
+ }
return mRaw;
}
Modified: RawSpeed/NikonDecompressor.cpp
===================================================================
--- RawSpeed/NikonDecompressor.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/NikonDecompressor.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -123,6 +123,8 @@
for (x=1; x < cw; x++) {
pLeft1 += HuffDecodeNikon();
pLeft2 += HuffDecodeNikon();
+ if (pLeft1 < 0 || pLeft1 > 65535 || pLeft2 < 0 || pLeft2 > 65535)
+ ThrowRDE("DecompressNikon: Image value out of range. Corrupt image.");
dest[x] = curve[pLeft1] | (curve[pLeft2]<<16);
}
}
Modified: RawSpeed/OrfDecoder.cpp
===================================================================
--- RawSpeed/OrfDecoder.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/OrfDecoder.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -86,8 +86,15 @@
if (oly->type == TIFF_UNDEFINED)
ThrowRDE("ORF Decoder: Unsupported compression");
- ByteStream s(mFile->getData(offsets->getInt()),counts->getInt());
- decodeCompressed(s, width, height);
+ // We add 3 bytes slack, since the bitpump might be a few bytes ahead.
+ ByteStream s(mFile->getData(offsets->getInt()),counts->getInt()+3);
+
+ try {
+ decodeCompressed(s, width, height);
+ } catch (IOException) {
+ // Let's ignore it, it may have delivered somewhat useful data.
+ }
+
return mRaw;
}
@@ -106,6 +113,7 @@
memset (acarry, 0, sizeof acarry);
gushort* dest = (gushort*)&data[y*pitch];
for (guint x=0; x < w; x++) {
+ bits.checkPos();
bits.fill();
carry = acarry[x & 1];
i = 2 * (carry[2] < 3);
Modified: RawSpeed/PefDecoder.cpp
===================================================================
--- RawSpeed/PefDecoder.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/PefDecoder.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -62,9 +62,12 @@
mRaw->dim = iPoint2D(width, height);
mRaw->bpp = 2;
mRaw->createData();
-
- PentaxDecompressor l(mFile,mRaw);
- l.decodePentax(offsets->getInt(), counts->getInt());
+ try {
+ PentaxDecompressor l(mFile,mRaw);
+ l.decodePentax(offsets->getInt(), counts->getInt());
+ } catch (IOException e) {
+ // Let's ignore it, it may have delivered somewhat useful data.
+ }
return mRaw;
}
Modified: RawSpeed/PentaxDecompressor.cpp
===================================================================
--- RawSpeed/PentaxDecompressor.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/PentaxDecompressor.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -67,6 +67,7 @@
gint pLeft2 = 0;
for (guint y=0;y<h;y++) {
+ pentaxBits->checkPos();
dest = (gushort*)&draw[y*mRaw->pitch]; // Adjust destination
pUp1[y&1] += HuffDecodePentax();
pUp2[y&1] += HuffDecodePentax();
Modified: RawSpeed/RawImage.cpp
===================================================================
--- RawSpeed/RawImage.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/RawImage.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -53,7 +53,9 @@
}
-void RawImageData::createData() {
+void RawImageData::createData() {
+ if (dim.x > 65535 || dim.y > 65535)
+ ThrowRDE("RawImageData: Dimensions too large for allocation.");
if (data)
ThrowRDE("RawImageData: Duplicate data allocation in createData.");
pitch = (((dim.x*bpp) + 15)/16)*16;
Modified: RawSpeed/RawSpeed.cpp
===================================================================
--- RawSpeed/RawSpeed.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/RawSpeed.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -25,7 +25,7 @@
#include "RawDecoder.h"
#include "CameraMetaData.h"
-#define _USE_GFL_
+//#define _USE_GFL_
#ifdef _USE_GFL_
#include "libgfl.h"
#pragma comment(lib, "libgfl.lib")
@@ -35,6 +35,9 @@
int startTime;
+// Open file, or test corrupt file
+#if 1
+// Open file and save as tiff
void OpenFile(FileReader f, CameraMetaData *meta) {
RawDecoder *d = 0;
FileMap* m = 0;
@@ -47,6 +50,7 @@
startTime = GetTickCount();
try {
+
d->decodeRaw();
d->decodeMetaData(meta);
RawImage r = d->mRaw;
@@ -57,11 +61,11 @@
r->scaleBlackWhite();
for (guint i = 0; i < d->errors.size(); i++) {
- printf("Error Encoutered:%s", d->errors[i]);
+ printf("Error Encountered:%s", d->errors[i]);
}
if (r->isCFA) {
-// printf("DCRAW filter:%x\n",r->cfa.getDcrawFilter());
-// printf(r->cfa.asString().c_str());
+ printf("DCRAW filter:%x\n",r->cfa.getDcrawFilter());
+ printf(r->cfa.asString().c_str());
}
#ifdef _USE_GFL_
@@ -105,6 +109,58 @@
}
+#else
+
+// Test single file multiple times in corrupted state
+// Used to test for states that might crash the app.
+
+void OpenFile(FileReader f, CameraMetaData *meta) {
+ RawDecoder *d = 0;
+ FileMap* m = 0;
+ wprintf(L"Opening:%s\n",f.Filename());
+ m = f.readFile();
+ srand(0xC0CAC01A); // Hardcoded seed for re-producability (on the same
platform)
+
+ int tests = 50;
+ // Try 50 permutations
+ for (int i = 0 ; i < tests; i++) {
+ FileMap *m2 = m->clone();
+ try {
+ // Insert 1000 random errors in file
+ m2->corrupt(1000);
+ TiffParser t(m2);
+ t.parseData();
+ d = t.getDecompressor();
+
+ startTime = GetTickCount();
+
+ d->decodeRaw();
+ d->decodeMetaData(meta);
+ RawImage r = d->mRaw;
+
+ guint time = GetTickCount()-startTime;
+ float mpps = (float)r->dim.x * (float)r->dim.y * (float)r->getCpp() /
(1000.0f * (float)time);
+ wprintf(L"(%d/%d) Decoding %s took: %u ms, %4.2f Mpixel/s\n", i+1,
tests, f.Filename(), time, mpps);
+ for (guint i = 0; i < d->errors.size(); i++) {
+ printf("Error Encountered:%s\n", d->errors[i]);
+ }
+ } catch (RawDecoderException e) {
+ wchar_t uni[1024];
+ MultiByteToWideChar(CP_ACP, 0, e.what(), -1, uni, 1024);
+ wprintf(L"Raw Decoder Exception:%s\n",uni);
+ } catch (TiffParserException e) {
+ wchar_t uni[1024];
+ MultiByteToWideChar(CP_ACP, 0, e.what(), -1, uni, 1024);
+ wprintf(L"Tiff Parser Exception:%s\n",uni);
+ }
+ delete m2;
+ if (d)
+ delete d;
+ d = 0;
+ }
+}
+#endif
+
int wmain(int argc, _TCHAR* argv[])
{
if (1) { // for memory detection
@@ -118,28 +174,27 @@
#endif
CameraMetaData meta("..\\cameras.xml");
//meta.dumpXML();
-// OpenFile(FileReader(L"..\\testimg\\dng\\Panasonic_LX3(300109).dng"),&meta);
- //OpenFile(FileReader(L"..\\testimg\\Panasonic_LX3.rw2"),&meta);
-/*
- OpenFile(FileReader(L"..\\testimg\\camera_dngs\\K7FARI0200.DNG"),&meta);
- OpenFile(FileReader(L"..\\testimg\\camera_dngs\\K7FARI6400.DNG"),&meta);
- OpenFile(FileReader(L"..\\testimg\\camera_dngs\\K7hMULTII0200.DNG"),&meta);
- OpenFile(FileReader(L"..\\testimg\\camera_dngs\\K7hVFAO.DNG"),&meta);*/
+
+
OpenFile(FileReader(L"..\\testimg\\camera_dngs\\Pentax-K7FARI0200.DNG"),&meta);
+
OpenFile(FileReader(L"..\\testimg\\camera_dngs\\Pentax-K7FARI6400.DNG"),&meta);
+
OpenFile(FileReader(L"..\\testimg\\camera_dngs\\Pentax-K7hMULTII0200.DNG"),&meta);
+ OpenFile(FileReader(L"..\\testimg\\camera_dngs\\Pentax-K7hVFAO.DNG"),&meta);
OpenFile(FileReader(L"..\\testimg\\camera_dngs\\Leica_M8.dng"),&meta);
OpenFile(FileReader(L"..\\testimg\\camera_dngs\\Leica_M_8.dng"),&meta);
-/*
+
OpenFile(FileReader(L"..\\testimg\\Canon_5DMk2-sRaw2.CR2"),&meta);
+ OpenFile(FileReader(L"..\\testimg\\Canon_EOS_450D.cr2"),&meta);
OpenFile(FileReader(L"..\\testimg\\Canon_5DMk2-sRaw1.CR2"),&meta);
OpenFile(FileReader(L"..\\testimg\\Canon_EOS_5D_Mk2-ISO100_sRAW1.CR2"),&meta);
OpenFile(FileReader(L"..\\testimg\\Canon_EOS_50D-1.cr2"),&meta);
OpenFile(FileReader(L"..\\testimg\\Canon_EOS_50D-2.cr2"),&meta);
OpenFile(FileReader(L"..\\testimg\\Canon_EOS_50D-3.cr2"),&meta);
OpenFile(FileReader(L"..\\testimg\\Canon_EOS_50D-4.cr2"),&meta);
- */
-// OpenFile(FileReader(L"..\\testimg\\kp.CR2"),&meta);
+
+ OpenFile(FileReader(L"..\\testimg\\kp.CR2"),&meta);
-/*
+
OpenFile(FileReader(L"..\\testimg\\kp.CR2"),&meta);
OpenFile(FileReader(L"..\\testimg\\Canon_EOS_1Ds_Mk2.cr2"),&meta);
OpenFile(FileReader(L"..\\testimg\\5d.CR2"),&meta);
@@ -367,12 +422,12 @@
OpenFile(FileReader(L"..\\testimg\\dng\\Sony_DSLR-A350.dng"),&meta);
OpenFile(FileReader(L"..\\testimg\\dng\\Sony_DSLR-A900-2.dng"),&meta);
OpenFile(FileReader(L"..\\testimg\\dng\\Sony_DSLR-A900.dng"),&meta);
-*/
-OpenFile(FileReader(L"..\\testimg\\dng\\uncompressed.dng"),&meta);
-OpenFile(FileReader(L"..\\testimg\\dng\\uncompressed2.dng"),&meta);
-OpenFile(FileReader(L"..\\testimg\\dng\\uncompressed3.dng"),&meta);
+ OpenFile(FileReader(L"..\\testimg\\dng\\uncompressed.dng"),&meta);
+ OpenFile(FileReader(L"..\\testimg\\dng\\uncompressed2.dng"),&meta);
+ OpenFile(FileReader(L"..\\testimg\\dng\\uncompressed3.dng"),&meta);
+
MessageBox(0,L"Finished", L"Finished",0);
#ifdef _USE_GFL_
gflLibraryExit();
Modified: RawSpeed/TiffEntry.cpp
===================================================================
--- RawSpeed/TiffEntry.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/TiffEntry.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -35,7 +35,7 @@
count = *(int*)f->getData(offset+4);
if (type>13)
throw TiffParserException("Error reading TIFF structure. Unknown Type
encountered.");
- int bytesize = count << datashifts[type];
+ guint bytesize = count << datashifts[type];
if (bytesize <=4) {
data = f->getDataWrt(offset+8);
} else { // offset
Modified: RawSpeed/TiffEntry.h
===================================================================
--- RawSpeed/TiffEntry.h 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/TiffEntry.h 2009-08-16 19:53:28 UTC (rev 116)
@@ -23,15 +23,15 @@
#include "TiffParserException.h"
#include "FileMap.h"
-const int datasizes[] = {0,1,1,2,4,8,1,1,2,4, 8, 4, 8, 4};
+const guint datasizes[] = {0,1,1,2,4,8,1,1,2,4, 8, 4, 8, 4};
// 0-1-2-3-4-5-6-7-8-9-10-11-12-13
-const int datashifts[] = {0,0,0,1,2,3,0,0,1,2, 3, 2, 3, 2};
+const guint datashifts[] = {0,0,0,1,2,3,0,0,1,2, 3, 2, 3, 2};
#ifdef CHECKSIZE
#undef CHECKSIZE
#endif
-#define CHECKSIZE(A) if (A >= f->getSize()) throw TiffParserException("Error
reading TIFF structure. File Corrupt")
+#define CHECKSIZE(A) if (A >= f->getSize() || A < 1) throw
TiffParserException("Error reading TIFF structure. File Corrupt")
// 0-1-2-3-4-5-6-7-8-9-10-11-12-13
/*
Modified: RawSpeed/TiffEntryBE.cpp
===================================================================
--- RawSpeed/TiffEntryBE.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/TiffEntryBE.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -36,7 +36,7 @@
if (type>13)
throw TiffParserException("Error reading TIFF structure. Unknown Type
encountered.");
- int bytesize = count << datashifts[type];
+ guint bytesize = count << datashifts[type];
if (bytesize <=4) {
data = f->getDataWrt(offset+8);
} else { // offset
Modified: RawSpeed/TiffIFD.cpp
===================================================================
--- RawSpeed/TiffIFD.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/TiffIFD.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -38,6 +38,7 @@
guint size = f->getSize();
guint entries;
endian = big;
+ CHECKSIZE(offset);
entries = *(unsigned short*)f->getData(offset); // Directory entries in
this IFD
Modified: RawSpeed/TiffIFDBE.cpp
===================================================================
--- RawSpeed/TiffIFDBE.cpp 2009-08-11 18:01:15 UTC (rev 115)
+++ RawSpeed/TiffIFDBE.cpp 2009-08-16 19:53:28 UTC (rev 116)
@@ -31,9 +31,10 @@
{
endian = big;
int entries;
+ CHECKSIZE(offset);
- const unsigned char* data = f->getData(offset);
- entries = (unsigned short)data[0] << 8 | (unsigned short)data[1]; //
Directory entries in this IFD
+ const unsigned char* data = f->getData(offset);
+ entries = (unsigned short)data[0] << 8 | (unsigned short)data[1]; //
Directory entries in this IFD
CHECKSIZE(offset+2+entries*4);
for (int i = 0; i < entries; i++) {
_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit