@@ -90,41 +90,88 @@ typedef struct tagSUNHEADER {
9090// Internal functions
9191// ==========================================================
9292
93- static void
94- ReadData (FreeImageIO *io, fi_handle handle, uint8_t *buf, uint32_t length, FIBOOL rle) {
93+ class CachedIO {
94+ public:
95+ CachedIO (FreeImageIO *io, fi_handle handle) : io_{ io }, handle_{ handle } {
96+ }
97+
98+ bool getByte (uint8_t &res) {
99+ if (sz_ <= pos_) {
100+ sz_ = io_->read_proc (cache_, 1 , std::size (cache_), handle_);
101+ if (sz_ < 1 ) {
102+ return false ;
103+ }
104+ pos_ = 0 ;
105+ }
106+ res = cache_[pos_++];
107+ return true ;
108+ }
109+
110+ bool read_proc (void *buffer, unsigned size, unsigned count) {
111+ return 0 < io_->read_proc (buffer, size, count, handle_);
112+ }
113+
114+ private:
115+ uint8_t cache_[1024 ];
116+ FreeImageIO *io_{};
117+ fi_handle handle_{};
118+ uint32_t pos_{}, sz_{};
119+ };
120+
121+ static bool
122+ ReadData (CachedIO &cio, uint8_t *buf, uint32_t length, FIBOOL rle) {
95123 // Read either Run-Length Encoded or normal image data
96124
97- static uint8_t repchar, remaining= 0 ;
125+ static uint8_t repchar{};
126+ static uint32_t remaining{};
98127
99128 if (rle) {
100129 // Run-length encoded read
101130
102- while (length-- ) {
131+ while (length) {
103132 if (remaining) {
104- remaining--;
105- *(buf++)= repchar;
133+ const auto len{ std::min (remaining, length) };
134+ std::memset (buf, repchar, len);
135+ buf += len;
136+ length -= len;
137+ remaining -= len;
106138 } else {
107- io->read_proc (&repchar, 1 , 1 , handle);
139+ if (!cio.getByte (repchar)) {
140+ break ;
141+ }
108142
109143 if (repchar == RESC) {
110- io->read_proc (&remaining, 1 , 1 , handle);
144+ uint8_t tmp{};
145+ if (!cio.getByte (tmp)) {
146+ break ;
147+ }
111148
112- if (remaining == 0 ) {
149+ if (0 == tmp ) {
113150 *(buf++)= RESC;
151+ --length;
114152 } else {
115- io->read_proc (&repchar, 1 , 1 , handle);
116-
117- *(buf++)= repchar;
153+ if (!cio.getByte (repchar)) {
154+ break ;
155+ }
156+
157+ remaining = tmp + 1 ;
158+ const auto len{ std::min (remaining, length) };
159+ std::memset (buf, repchar, len);
160+ buf += len;
161+ length -= len;
162+ remaining -= len;
118163 }
119164 } else {
120165 *(buf++)= repchar;
166+ --length;
121167 }
122168 }
123169 }
170+ return 0 == length;
124171 } else {
125172 // Normal read
126173
127- io-> read_proc (buf, length, 1 , handle );
174+ return cio. read_proc (buf, length, 1 );
128175 }
129176}
130177
@@ -195,8 +242,8 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
195242 SUNHEADER header; // Sun file header
196243 uint16_t linelength; // Length of raster line in bytes
197244 uint16_t fill; // Number of fill bytes per raster line
198- FIBOOL rle; // TRUE if RLE file
199- FIBOOL isRGB; // TRUE if file type is RT_FORMAT_RGB
245+ bool rle{} ; // true if RLE file
246+ bool isRGB{} ; // true if file type is RT_FORMAT_RGB
200247 uint8_t fillchar;
201248
202249 uint8_t *bits{}; // Pointer to dib data
@@ -206,7 +253,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
206253 return nullptr ;
207254 }
208255
209- FIBOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
256+ const bool header_only{ (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS } ;
210257
211258 try {
212259 // Read SUN raster header
@@ -231,9 +278,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
231278 if (header.magic != RAS_MAGIC) {
232279 throw FI_MSG_ERROR_MAGIC_NUMBER;
233280 }
234- if (header.width > 65500 || header.height > 65500 ) {
235- throw FI_MSG_ERROR_DIB_MEMORY;
236- }
281+ if (header.width > 65500 || header.height > 65500 ) {
282+ throw FI_MSG_ERROR_DIB_MEMORY;
283+ }
237284
238285 // Allocate a new DIB
239286 std::unique_ptr<FIBITMAP, decltype (&FreeImage_Unload)> dib (nullptr , &FreeImage_Unload);
@@ -244,10 +291,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
244291 break ;
245292
246293 case 24 :
247- dib.reset (FreeImage_AllocateHeader (header_only, header.width , header.height , header.depth , FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK));
248- break ;
249-
250- case 32 :
294+ case 32 :
251295 dib.reset (FreeImage_AllocateHeader (header_only, header.width , header.height , header.depth , FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK));
252296 break ;
253297 }
@@ -258,9 +302,6 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
258302
259303 // Check the file format
260304
261- rle = FALSE ;
262- isRGB = FALSE ;
263-
264305 switch (header.type ) {
265306 case RT_OLD:
266307 case RT_STANDARD:
@@ -271,11 +312,11 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
271312 break ;
272313
273314 case RT_BYTE_ENCODED:
274- rle = TRUE ;
315+ rle = true ;
275316 break ;
276317
277318 case RT_FORMAT_RGB:
278- isRGB = TRUE ;
319+ isRGB = true ;
279320 break ;
280321
281322 default :
@@ -360,21 +401,26 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
360401 linelength = (uint16_t )header.width ;
361402 }
362403
363- fill = ( linelength % 2 ) ? 1 : 0 ;
404+ fill = linelength & 1 ;
364405
365406 // Read the image data
366407
367408 switch (header.depth ) {
368409 case 1 :
369410 case 8 :
370411 {
412+ CachedIO cio (io, handle);
371413 for (y = 0 ; y < header.height ; y++) {
372414 bits = FreeImage_GetScanLine (dib.get (), header.height - 1 - y);
373415
374- ReadData (io, handle, bits, linelength, rle);
416+ if (!ReadData (cio, bits, linelength, rle)) {
417+ break ;
418+ }
375419
376420 if (fill) {
377- ReadData (io, handle, &fillchar, fill, rle);
421+ if (!ReadData (cio, &fillchar, fill, rle)) {
422+ break ;
423+ }
378424 }
379425 }
380426
@@ -385,10 +431,13 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
385431 {
386432 auto buf = std::make_unique<uint8_t []>(header.width * 3 );
387433
434+ CachedIO cio (io, handle);
388435 for (y = 0 ; y < header.height ; y++) {
389436 bits = FreeImage_GetScanLine (dib.get (), header.height - 1 - y);
390437
391- ReadData (io, handle, buf.get (), header.width * 3 , rle);
438+ if (!ReadData (cio, buf.get (), header.width * 3 , rle)) {
439+ break ;
440+ }
392441
393442 const auto *bp = buf.get ();
394443
@@ -411,7 +460,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
411460 }
412461
413462 if (fill) {
414- ReadData (io, handle, &fillchar, fill, rle);
463+ if (!ReadData (cio, &fillchar, fill, rle)) {
464+ return nullptr ;
465+ }
415466 }
416467 }
417468
@@ -422,10 +473,13 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
422473 {
423474 auto buf = std::make_unique<uint8_t []>(header.width * 4 );
424475
476+ CachedIO cio (io, handle);
425477 for (y = 0 ; y < header.height ; y++) {
426478 bits = FreeImage_GetScanLine (dib.get (), header.height - 1 - y);
427479
428- ReadData (io, handle, buf.get (), header.width * 4 , rle);
480+ if (!ReadData (cio, buf.get (), header.width * 4 , rle)) {
481+ break ;
482+ }
429483
430484 const auto *bp = buf.get ();
431485
@@ -450,10 +504,6 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
450504 bp += 4 ;
451505 }
452506 }
453-
454- if (fill) {
455- ReadData (io, handle, &fillchar, fill, rle);
456- }
457507 }
458508
459509 break ;
0 commit comments