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

Reply via email to