@@ -90,41 +90,92 @@ 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 1
102+ if (sz_ < 1 ) {
103+ return false ;
104+ }
105+ #else
106+ sz_ = std::size(cache_);
107+ #endif
108+ pos_ = 0 ;
109+ }
110+ res = cache_[pos_++];
111+ return true ;
112+ }
113+
114+ bool read_proc (void *buffer, unsigned size, unsigned count) {
115+ return 0 < io_->read_proc (buffer, size, count, handle_);
116+ }
117+
118+ private:
119+ uint8_t cache_[1024 ];
120+ FreeImageIO *io_{};
121+ fi_handle handle_{};
122+ uint32_t pos_{}, sz_{};
123+ };
124+
125+ static bool
126+ ReadData (CachedIO &cio, uint8_t *buf, uint32_t length, FIBOOL rle) {
95127 // Read either Run-Length Encoded or normal image data
96128
97- static uint8_t repchar, remaining= 0 ;
129+ static uint8_t repchar{};
130+ static uint32_t remaining{};
98131
99132 if (rle) {
100133 // Run-length encoded read
101134
102- while (length-- ) {
135+ while (length) {
103136 if (remaining) {
104- remaining--;
105- *(buf++)= repchar;
137+ const auto len{ std::min (remaining, length) };
138+ std::memset (buf, repchar, len);
139+ buf += len;
140+ length -= len;
141+ remaining -= len;
106142 } else {
107- io->read_proc (&repchar, 1 , 1 , handle);
143+ if (!cio.getByte (repchar)) {
144+ break ;
145+ }
108146
109147 if (repchar == RESC) {
110- io->read_proc (&remaining, 1 , 1 , handle);
148+ uint8_t tmp{};
149+ if (!cio.getByte (tmp)) {
150+ break ;
151+ }
111152
112- if (remaining == 0 ) {
153+ if (0 == tmp ) {
113154 *(buf++)= RESC;
155+ --length;
114156 } else {
115- io->read_proc (&repchar, 1 , 1 , handle);
116-
117- *(buf++)= repchar;
157+ if (!cio.getByte (repchar)) {
158+ break ;
159+ }
160+
161+ remaining = tmp + 1 ;
162+ const auto len{ std::min (remaining, length) };
163+ std::memset (buf, repchar, len);
164+ buf += len;
165+ length -= len;
166+ remaining -= len;
118167 }
119168 } else {
120169 *(buf++)= repchar;
170+ --length;
121171 }
122172 }
123173 }
174+ return 0 == length;
124175 } else {
125176 // Normal read
126177
127- io-> read_proc (buf, length, 1 , handle );
178+ return cio. read_proc (buf, length, 1 );
128179 }
129180}
130181
@@ -195,18 +246,18 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
195246 SUNHEADER header; // Sun file header
196247 uint16_t linelength; // Length of raster line in bytes
197248 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
249+ bool rle{} ; // true if RLE file
250+ bool isRGB{} ; // true if file type is RT_FORMAT_RGB
200251 uint8_t fillchar;
201252
202253 uint8_t *bits{}; // Pointer to dib data
203- uint16_t x, y;
254+ uint32_t x, y;
204255
205256 if (!handle) {
206257 return nullptr ;
207258 }
208259
209- FIBOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
260+ const bool header_only{ (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS } ;
210261
211262 try {
212263 // Read SUN raster header
@@ -231,9 +282,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
231282 if (header.magic != RAS_MAGIC) {
232283 throw FI_MSG_ERROR_MAGIC_NUMBER;
233284 }
234- if (header.width > 65500 || header.height > 65500 ) {
235- throw FI_MSG_ERROR_DIB_MEMORY;
236- }
285+ /* if (header.width > 65500 || header.height > 65500) {
286+ throw FI_MSG_ERROR_DIB_MEMORY;
287+ } */
237288
238289 // Allocate a new DIB
239290 std::unique_ptr<FIBITMAP, decltype (&FreeImage_Unload)> dib (nullptr , &FreeImage_Unload);
@@ -244,10 +295,7 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
244295 break ;
245296
246297 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 :
298+ case 32 :
251299 dib.reset (FreeImage_AllocateHeader (header_only, header.width , header.height , header.depth , FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK));
252300 break ;
253301 }
@@ -256,10 +304,10 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
256304 throw FI_MSG_ERROR_DIB_MEMORY;
257305 }
258306
259- // Check the file format
307+ header.width = FreeImage_GetWidth (dib.get ());
308+ header.height = FreeImage_GetHeight (dib.get ());
260309
261- rle = FALSE ;
262- isRGB = FALSE ;
310+ // Check the file format
263311
264312 switch (header.type ) {
265313 case RT_OLD:
@@ -271,11 +319,11 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
271319 break ;
272320
273321 case RT_BYTE_ENCODED:
274- rle = TRUE ;
322+ rle = true ;
275323 break ;
276324
277325 case RT_FORMAT_RGB:
278- isRGB = TRUE ;
326+ isRGB = true ;
279327 break ;
280328
281329 default :
@@ -360,21 +408,26 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
360408 linelength = (uint16_t )header.width ;
361409 }
362410
363- fill = (linelength % 2 ) ? 1 : 0 ;
411+ fill = (linelength & 1 ) ? 1 : 0 ;
364412
365413 // Read the image data
366414
367415 switch (header.depth ) {
368416 case 1 :
369417 case 8 :
370418 {
419+ CachedIO cio (io, handle);
371420 for (y = 0 ; y < header.height ; y++) {
372421 bits = FreeImage_GetScanLine (dib.get (), header.height - 1 - y);
373422
374- ReadData (io, handle, bits, linelength, rle);
423+ if (!ReadData (cio, bits, linelength, rle)) {
424+ break ;
425+ }
375426
376427 if (fill) {
377- ReadData (io, handle, &fillchar, fill, rle);
428+ if (!ReadData (cio, &fillchar, fill, rle)) {
429+ break ;
430+ }
378431 }
379432 }
380433
@@ -385,10 +438,13 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
385438 {
386439 auto buf = std::make_unique<uint8_t []>(header.width * 3 );
387440
441+ CachedIO cio (io, handle);
388442 for (y = 0 ; y < header.height ; y++) {
389443 bits = FreeImage_GetScanLine (dib.get (), header.height - 1 - y);
390444
391- ReadData (io, handle, buf.get (), header.width * 3 , rle);
445+ if (!ReadData (cio, buf.get (), header.width * 3 , rle)) {
446+ break ;
447+ }
392448
393449 const auto *bp = buf.get ();
394450
@@ -411,7 +467,9 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
411467 }
412468
413469 if (fill) {
414- ReadData (io, handle, &fillchar, fill, rle);
470+ if (!ReadData (cio, &fillchar, fill, rle)) {
471+ return nullptr ;
472+ }
415473 }
416474 }
417475
@@ -422,10 +480,13 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
422480 {
423481 auto buf = std::make_unique<uint8_t []>(header.width * 4 );
424482
483+ CachedIO cio (io, handle);
425484 for (y = 0 ; y < header.height ; y++) {
426485 bits = FreeImage_GetScanLine (dib.get (), header.height - 1 - y);
427486
428- ReadData (io, handle, buf.get (), header.width * 4 , rle);
487+ if (!ReadData (cio, buf.get (), header.width * 4 , rle)) {
488+ break ;
489+ }
429490
430491 const auto *bp = buf.get ();
431492
@@ -450,10 +511,6 @@ Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
450511 bp += 4 ;
451512 }
452513 }
453-
454- if (fill) {
455- ReadData (io, handle, &fillchar, fill, rle);
456- }
457514 }
458515
459516 break ;
0 commit comments