Skip to content

Commit f0fb665

Browse files
committed
Merge pull request opencv#9376 from alalek:imgcodecs_refactoring
2 parents cc5b99c + 78a3106 commit f0fb665

File tree

12 files changed

+281
-129
lines changed

12 files changed

+281
-129
lines changed

modules/imgcodecs/src/bitstrm.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ int RLByteStream::getByte()
209209
current = m_current;
210210
}
211211

212+
CV_Assert(current < m_end);
213+
212214
val = *((uchar*)current);
213215
m_current = current + 1;
214216
return val;

modules/imgcodecs/src/bitstrm.hpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,20 @@
4848
namespace cv
4949
{
5050

51-
enum
52-
{
53-
RBS_THROW_EOS=-123, // <end of stream> exception code
54-
RBS_THROW_FORB=-124, // <forrbidden huffman code> exception code
55-
RBS_HUFF_FORB=2047, // forrbidden huffman code "value"
56-
RBS_BAD_HEADER=-125 // invalid header
51+
#define DECLARE_RBS_EXCEPTION(name) \
52+
class RBS_ ## name ## _Exception : public cv::Exception \
53+
{ \
54+
public: \
55+
RBS_ ## name ## _Exception(int code_, const String& err_, const String& func_, const String& file_, int line_) : \
56+
cv::Exception(code_, err_, func_, file_, line_) \
57+
{} \
5758
};
59+
DECLARE_RBS_EXCEPTION(THROW_EOS)
60+
#define RBS_THROW_EOS RBS_THROW_EOS_Exception(cv::Error::StsError, "Unexpected end of input stream", CV_Func, __FILE__, __LINE__)
61+
DECLARE_RBS_EXCEPTION(THROW_FORB)
62+
#define RBS_THROW_FORB RBS_THROW_FORB_Exception(cv::Error::StsError, "Forrbidden huffman code", CV_Func, __FILE__, __LINE__)
63+
DECLARE_RBS_EXCEPTION(BAD_HEADER)
64+
#define RBS_BAD_HEADER RBS_BAD_HEADER_Exception(cv::Error::StsError, "Invalid header", CV_Func, __FILE__, __LINE__)
5865

5966
typedef unsigned long ulong;
6067

modules/imgcodecs/src/grfmt_bmp.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ bool BmpDecoder::readHeader()
118118

119119
if( m_bpp <= 8 )
120120
{
121-
memset( m_palette, 0, sizeof(m_palette));
122-
m_strm.getBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
121+
CV_Assert(clrused < 256);
122+
memset(m_palette, 0, sizeof(m_palette));
123+
m_strm.getBytes(m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
123124
iscolor = IsColorPalette( m_palette, m_bpp );
124125
}
125126
else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
@@ -290,7 +291,9 @@ bool BmpDecoder::readData( Mat& img )
290291
else if( code > 2 ) // absolute mode
291292
{
292293
if( data + code*nch > line_end ) goto decode_rle4_bad;
293-
m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 );
294+
int sz = (((code + 1)>>1) + 1) & (~1);
295+
CV_Assert((size_t)sz < _src.size());
296+
m_strm.getBytes(src, sz);
294297
if( color )
295298
data = FillColorRow4( data, src, code, m_palette );
296299
else
@@ -379,7 +382,9 @@ decode_rle4_bad: ;
379382

380383
if( data + code3 > line_end )
381384
goto decode_rle8_bad;
382-
m_strm.getBytes( src, (code + 1) & -2 );
385+
int sz = (code + 1) & (~1);
386+
CV_Assert((size_t)sz < _src.size());
387+
m_strm.getBytes(src, sz);
383388
if( color )
384389
data = FillColorRow8( data, src, code, m_palette );
385390
else

modules/imgcodecs/src/grfmt_pxm.cpp

Lines changed: 75 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -43,50 +43,58 @@
4343
#include "precomp.hpp"
4444
#include "utils.hpp"
4545
#include "grfmt_pxm.hpp"
46+
#include <iostream>
4647

4748
namespace cv
4849
{
4950

5051
///////////////////////// P?M reader //////////////////////////////
5152

52-
static int ReadNumber( RLByteStream& strm, int maxdigits )
53+
static int ReadNumber(RLByteStream& strm, int maxdigits = 0)
5354
{
5455
int code;
55-
int val = 0;
56+
int64 val = 0;
5657
int digits = 0;
5758

5859
code = strm.getByte();
5960

60-
if( !isdigit(code))
61+
while (!isdigit(code))
6162
{
62-
do
63+
if (code == '#' )
6364
{
64-
if( code == '#' )
65+
do
6566
{
66-
do
67-
{
68-
code = strm.getByte();
69-
}
70-
while( code != '\n' && code != '\r' );
67+
code = strm.getByte();
7168
}
72-
69+
while (code != '\n' && code != '\r');
7370
code = strm.getByte();
74-
75-
while( isspace(code))
71+
}
72+
else if (isspace(code))
73+
{
74+
while (isspace(code))
7675
code = strm.getByte();
7776
}
78-
while( !isdigit( code ));
77+
else
78+
{
79+
#if 1
80+
CV_ErrorNoReturn_(Error::StsError, ("PXM: Unexpected code in ReadNumber(): 0x%x (%d)", code, code));
81+
#else
82+
code = strm.getByte();
83+
#endif
84+
}
7985
}
8086

8187
do
8288
{
83-
val = val*10 + code - '0';
84-
if( ++digits >= maxdigits ) break;
89+
val = val*10 + (code - '0');
90+
CV_Assert(val <= INT_MAX && "PXM: ReadNumber(): result is too large");
91+
digits++;
92+
if (maxdigits != 0 && digits >= maxdigits) break;
8593
code = strm.getByte();
8694
}
87-
while( isdigit(code));
95+
while (isdigit(code));
8896

89-
return val;
97+
return (int)val;
9098
}
9199

92100

@@ -122,13 +130,13 @@ ImageDecoder PxMDecoder::newDecoder() const
122130
return makePtr<PxMDecoder>();
123131
}
124132

125-
void PxMDecoder::close()
133+
void PxMDecoder::close()
126134
{
127135
m_strm.close();
128136
}
129137

130138

131-
bool PxMDecoder::readHeader()
139+
bool PxMDecoder::readHeader()
132140
{
133141
bool result = false;
134142

@@ -158,10 +166,10 @@ bool PxMDecoder::readHeader()
158166
m_binary = code >= '4';
159167
m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;
160168

161-
m_width = ReadNumber( m_strm, INT_MAX );
162-
m_height = ReadNumber( m_strm, INT_MAX );
169+
m_width = ReadNumber(m_strm);
170+
m_height = ReadNumber(m_strm);
163171

164-
m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX );
172+
m_maxval = m_bpp == 1 ? 1 : ReadNumber(m_strm);
165173
if( m_maxval > 65535 )
166174
throw RBS_BAD_HEADER;
167175

@@ -175,8 +183,14 @@ bool PxMDecoder::readHeader()
175183
result = true;
176184
}
177185
}
178-
catch(...)
186+
catch (const cv::Exception&)
187+
{
188+
throw;
189+
}
190+
catch (...)
179191
{
192+
std::cerr << "PXM::readHeader(): unknown C++ exception" << std::endl << std::flush;
193+
throw;
180194
}
181195

182196
if( !result )
@@ -189,33 +203,28 @@ bool PxMDecoder::readHeader()
189203
}
190204

191205

192-
bool PxMDecoder::readData( Mat& img )
206+
bool PxMDecoder::readData( Mat& img )
193207
{
194208
int color = img.channels() > 1;
195209
uchar* data = img.ptr();
196210
PaletteEntry palette[256];
197211
bool result = false;
198-
int bit_depth = CV_ELEM_SIZE1(m_type)*8;
199-
int src_pitch = (m_width*m_bpp*bit_depth/8 + 7)/8;
212+
const int bit_depth = CV_ELEM_SIZE1(m_type)*8;
213+
const int src_pitch = divUp(m_width*m_bpp*(bit_depth/8), 8);
200214
int nch = CV_MAT_CN(m_type);
201215
int width3 = m_width*nch;
202-
int i, x, y;
203216

204217
if( m_offset < 0 || !m_strm.isOpened())
205218
return false;
206219

207-
AutoBuffer<uchar> _src(src_pitch + 32);
208-
uchar* src = _src;
209-
AutoBuffer<uchar> _gray_palette;
210-
uchar* gray_palette = _gray_palette;
220+
uchar gray_palette[256] = {0};
211221

212222
// create LUT for converting colors
213223
if( bit_depth == 8 )
214224
{
215-
_gray_palette.allocate(m_maxval + 1);
216-
gray_palette = _gray_palette;
225+
CV_Assert(m_maxval < 256);
217226

218-
for( i = 0; i <= m_maxval; i++ )
227+
for (int i = 0; i <= m_maxval; i++)
219228
gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0));
220229

221230
FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 );
@@ -229,12 +238,16 @@ bool PxMDecoder::readData( Mat& img )
229238
{
230239
////////////////////////// 1 BPP /////////////////////////
231240
case 1:
241+
CV_Assert(CV_MAT_DEPTH(m_type) == CV_8U);
232242
if( !m_binary )
233243
{
234-
for( y = 0; y < m_height; y++, data += img.step )
244+
AutoBuffer<uchar> _src(m_width);
245+
uchar* src = _src;
246+
247+
for (int y = 0; y < m_height; y++, data += img.step)
235248
{
236-
for( x = 0; x < m_width; x++ )
237-
src[x] = ReadNumber( m_strm, 1 ) != 0;
249+
for (int x = 0; x < m_width; x++)
250+
src[x] = ReadNumber(m_strm, 1) != 0;
238251

239252
if( color )
240253
FillColorRow8( data, src, m_width, palette );
@@ -244,7 +257,10 @@ bool PxMDecoder::readData( Mat& img )
244257
}
245258
else
246259
{
247-
for( y = 0; y < m_height; y++, data += img.step )
260+
AutoBuffer<uchar> _src(src_pitch);
261+
uchar* src = _src;
262+
263+
for (int y = 0; y < m_height; y++, data += img.step)
248264
{
249265
m_strm.getBytes( src, src_pitch );
250266

@@ -260,13 +276,17 @@ bool PxMDecoder::readData( Mat& img )
260276
////////////////////////// 8 BPP /////////////////////////
261277
case 8:
262278
case 24:
263-
for( y = 0; y < m_height; y++, data += img.step )
279+
{
280+
AutoBuffer<uchar> _src(std::max<size_t>(width3*2, src_pitch));
281+
uchar* src = _src;
282+
283+
for (int y = 0; y < m_height; y++, data += img.step)
264284
{
265285
if( !m_binary )
266286
{
267-
for( x = 0; x < width3; x++ )
287+
for (int x = 0; x < width3; x++)
268288
{
269-
int code = ReadNumber( m_strm, INT_MAX );
289+
int code = ReadNumber(m_strm);
270290
if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval;
271291
if( bit_depth == 8 )
272292
src[x] = gray_palette[code];
@@ -279,7 +299,7 @@ bool PxMDecoder::readData( Mat& img )
279299
m_strm.getBytes( src, src_pitch );
280300
if( bit_depth == 16 && !isBigEndian() )
281301
{
282-
for( x = 0; x < width3; x++ )
302+
for (int x = 0; x < width3; x++)
283303
{
284304
uchar v = src[x * 2];
285305
src[x * 2] = src[x * 2 + 1];
@@ -290,7 +310,7 @@ bool PxMDecoder::readData( Mat& img )
290310

291311
if( img.depth() == CV_8U && bit_depth == 16 )
292312
{
293-
for( x = 0; x < width3; x++ )
313+
for (int x = 0; x < width3; x++)
294314
{
295315
int v = ((ushort *)src)[x];
296316
src[x] = (uchar)(v >> 8);
@@ -331,12 +351,19 @@ bool PxMDecoder::readData( Mat& img )
331351
}
332352
result = true;
333353
break;
354+
}
334355
default:
335-
assert(0);
356+
CV_ErrorNoReturn(Error::StsError, "m_bpp is not supported");
336357
}
337358
}
338-
catch(...)
359+
catch (const cv::Exception&)
360+
{
361+
throw;
362+
}
363+
catch (...)
339364
{
365+
std::cerr << "PXM::readData(): unknown exception" << std::endl << std::flush;
366+
throw;
340367
}
341368

342369
return result;
@@ -412,8 +439,9 @@ bool PxMEncoder::write( const Mat& img, const std::vector<int>& params )
412439
char* buffer = _buffer;
413440

414441
// write header;
415-
sprintf( buffer, "P%c\n%d %d\n%d\n",
442+
sprintf( buffer, "P%c\n# Generated by OpenCV %s\n%d %d\n%d\n",
416443
'2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0),
444+
CV_VERSION,
417445
width, height, (1 << depth) - 1 );
418446

419447
strm.putBytes( buffer, (int)strlen(buffer) );

0 commit comments

Comments
 (0)