Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginXBM.cpp
Line
Count
Source (jump to first uncovered line)
1
// ==========================================================
2
// XBM Loader
3
//
4
// Design and implementation by
5
// - Hervé Drolon <drolon@infonie.fr>
6
// part of the code adapted from the netPBM package (xbmtopbm.c)
7
//
8
// This file is part of FreeImage 3
9
//
10
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
11
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
12
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
13
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
14
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
15
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
16
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
17
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
18
// THIS DISCLAIMER.
19
//
20
// Use at your own risk!
21
//
22
//
23
// ==========================================================
24
25
#include "FreeImage.h"
26
#include "Utilities.h"
27
28
// ==========================================================
29
// Internal functions
30
// ==========================================================
31
32
0
#define MAX_LINE  512
33
34
static const char *ERR_XBM_SYNTAX = "Syntax error";
35
static const char *ERR_XBM_LINE   = "Line too long";
36
static const char *ERR_XBM_DECL   = "Unable to find a line in the file containing the start of C array declaration (\"static char\" or whatever)";
37
static const char *ERR_XBM_EOFREAD  = "EOF / read error";
38
static const char *ERR_XBM_WIDTH  = "Invalid width";
39
static const char *ERR_XBM_HEIGHT = "Invalid height";
40
static const char *ERR_XBM_MEMORY = "Out of memory";
41
42
/**
43
Get a string from a stream. 
44
Read the string from the current stream to the first newline character. 
45
The result stored in str is appended with a null character.
46
@param str Storage location for data 
47
@param n Maximum number of characters to read 
48
@param io Pointer to the FreeImageIO structure
49
@param handle Handle to the stream
50
@return Returns str. NULL is returned to indicate an error or an end-of-file condition.
51
*/
52
static char* 
53
29.3k
readLine(char *str, int n, FreeImageIO *io, fi_handle handle) {
54
29.3k
  char c;
55
29.3k
  int count, i = 0;
56
204k
  do {
57
204k
    count = io->read_proc(&c, 1, 1, handle);
58
204k
    str[i++] = c;
59
204k
  } while((c != '\n') && (i < n));
60
29.3k
  if(count <= 0)
61
0
    return NULL;
62
29.3k
  str[i] = '\0';
63
29.3k
  return str;
64
29.3k
}
65
66
/**
67
Get a char from the stream
68
@param io Pointer to the FreeImageIO structure
69
@param handle Handle to the stream
70
@return Returns the next character in the stream
71
*/
72
static int 
73
0
readChar(FreeImageIO *io, fi_handle handle) {
74
0
  BYTE c;
75
0
  io->read_proc(&c, 1, 1, handle);
76
0
  return c;
77
0
}
78
79
/**
80
Read an XBM file into a buffer
81
@param io Pointer to the FreeImageIO structure
82
@param handle Handle to the stream
83
@param widthP (return value) Pointer to the bitmap width
84
@param heightP (return value) Pointer to the bitmap height
85
@param dataP (return value) Pointer to the bitmap buffer
86
@return Returns NULL if OK, returns an error message otherwise
87
*/
88
static const char* 
89
0
readXBMFile(FreeImageIO *io, fi_handle handle, int *widthP, int *heightP, char **dataP) {
90
0
  char line[MAX_LINE], name_and_type[MAX_LINE];
91
0
  char* ptr;
92
0
  char* t;
93
0
  int version = 0;
94
0
  int raster_length, v;
95
0
  int bytes, bytes_per_line, padding;
96
0
  int c1, c2, value1, value2;
97
0
  int hex_table[256];
98
0
  BOOL found_declaration;
99
  /* in scanning through the bitmap file, we have found the first
100
   line of the C declaration of the array (the "static char ..."
101
   or whatever line)
102
   */
103
0
  BOOL eof; // we've encountered end of file while searching file
104
105
0
  *widthP = *heightP = -1;
106
107
0
  found_declaration = FALSE;    // haven't found it yet; haven't even looked
108
0
  eof = FALSE;                  // haven't encountered end of file yet 
109
  
110
0
  while(!found_declaration && !eof) {
111
112
0
    if( readLine(line, MAX_LINE, io, handle) == NULL) {
113
0
      eof = TRUE;
114
0
    }
115
0
    else {
116
0
      if( strlen( line ) == MAX_LINE - 1 )
117
0
        return( ERR_XBM_LINE );
118
0
      if( sscanf(line, "#define %s %d", name_and_type, &v) == 2 ) {
119
0
        if( ( t = strrchr( name_and_type, '_' ) ) == NULL )
120
0
          t = name_and_type;
121
0
        else
122
0
          t++;
123
0
        if ( ! strcmp( "width", t ) )
124
0
          *widthP = v;
125
0
        else if ( ! strcmp( "height", t ) )
126
0
          *heightP = v;
127
0
        continue;
128
0
      }
129
130
0
      if( sscanf( line, "static short %s = {", name_and_type ) == 1 ) {
131
0
        version = 10;
132
0
        found_declaration = TRUE;
133
0
      }
134
0
      else if( sscanf( line, "static char %s = {", name_and_type ) == 1 ) {
135
0
        version = 11;
136
0
        found_declaration = TRUE;
137
0
      }
138
0
      else if(sscanf(line, "static unsigned char %s = {", name_and_type ) == 1 ) {
139
0
        version = 11;
140
0
        found_declaration = TRUE;
141
0
      }
142
0
    }
143
0
  }
144
145
0
  if(!found_declaration) 
146
0
    return( ERR_XBM_DECL );
147
148
0
  if(*widthP == -1 )
149
0
    return( ERR_XBM_WIDTH );
150
0
  if( *heightP == -1 )
151
0
    return( ERR_XBM_HEIGHT );
152
153
0
  padding = 0;
154
0
  if ( ((*widthP % 16) >= 1) && ((*widthP % 16) <= 8) && (version == 10) )
155
0
    padding = 1;
156
157
0
  bytes_per_line = (*widthP + 7) / 8 + padding;
158
159
0
  raster_length =  bytes_per_line * *heightP;
160
0
  *dataP = (char*) malloc( raster_length );
161
0
  if ( *dataP == (char*) 0 )
162
0
    return( ERR_XBM_MEMORY );
163
164
  // initialize hex_table
165
0
  for ( c1 = 0; c1 < 256; c1++ ) {
166
0
    hex_table[c1] = 256;
167
0
  }
168
0
  hex_table['0'] = 0;
169
0
  hex_table['1'] = 1;
170
0
  hex_table['2'] = 2;
171
0
  hex_table['3'] = 3;
172
0
  hex_table['4'] = 4;
173
0
  hex_table['5'] = 5;
174
0
  hex_table['6'] = 6;
175
0
  hex_table['7'] = 7;
176
0
  hex_table['8'] = 8;
177
0
  hex_table['9'] = 9;
178
0
  hex_table['A'] = 10;
179
0
  hex_table['B'] = 11;
180
0
  hex_table['C'] = 12;
181
0
  hex_table['D'] = 13;
182
0
  hex_table['E'] = 14;
183
0
  hex_table['F'] = 15;
184
0
  hex_table['a'] = 10;
185
0
  hex_table['b'] = 11;
186
0
  hex_table['c'] = 12;
187
0
  hex_table['d'] = 13;
188
0
  hex_table['e'] = 14;
189
0
  hex_table['f'] = 15;
190
191
0
  if(version == 10) {
192
0
    for( bytes = 0, ptr = *dataP; bytes < raster_length; bytes += 2 ) {
193
0
      while( ( c1 = readChar(io, handle) ) != 'x' ) {
194
0
        if ( c1 == EOF )
195
0
          return( ERR_XBM_EOFREAD );
196
0
      }
197
198
0
      c1 = readChar(io, handle);
199
0
      c2 = readChar(io, handle);
200
0
      if( c1 == EOF || c2 == EOF )
201
0
        return( ERR_XBM_EOFREAD );
202
0
      value1 = ( hex_table[c1] << 4 ) + hex_table[c2];
203
0
      if ( value1 >= 256 )
204
0
        return( ERR_XBM_SYNTAX );
205
0
      c1 = readChar(io, handle);
206
0
      c2 = readChar(io, handle);
207
0
      if( c1 == EOF || c2 == EOF )
208
0
        return( ERR_XBM_EOFREAD );
209
0
      value2 = ( hex_table[c1] << 4 ) + hex_table[c2];
210
0
      if ( value2 >= 256 )
211
0
        return( ERR_XBM_SYNTAX );
212
0
      *ptr++ = (char)value2;
213
0
      if ( ( ! padding ) || ( ( bytes + 2 ) % bytes_per_line ) )
214
0
        *ptr++ = (char)value1;
215
0
    }
216
0
  }
217
0
  else {
218
0
    for(bytes = 0, ptr = *dataP; bytes < raster_length; bytes++ ) {
219
      /*
220
      ** skip until digit is found
221
      */
222
0
      for( ; ; ) {
223
0
        c1 = readChar(io, handle);
224
0
        if ( c1 == EOF )
225
0
          return( ERR_XBM_EOFREAD );
226
0
        value1 = hex_table[c1];
227
0
        if ( value1 != 256 )
228
0
          break;
229
0
      }
230
      /*
231
      ** loop on digits
232
      */
233
0
      for( ; ; ) {
234
0
        c2 = readChar(io, handle);
235
0
        if ( c2 == EOF )
236
0
          return( ERR_XBM_EOFREAD );
237
0
        value2 = hex_table[c2];
238
0
        if ( value2 != 256 ) {
239
0
          value1 = (value1 << 4) | value2;
240
0
          if ( value1 >= 256 )
241
0
            return( ERR_XBM_SYNTAX );
242
0
        }
243
0
        else if ( c2 == 'x' || c2 == 'X' ) {
244
0
          if ( value1 == 0 )
245
0
            continue;
246
0
          else return( ERR_XBM_SYNTAX );
247
0
        }
248
0
        else break;
249
0
      }
250
0
      *ptr++ = (char)value1;
251
0
    }
252
0
  }
253
254
0
  return NULL;
255
0
}
256
257
// ==========================================================
258
// Plugin Interface
259
// ==========================================================
260
261
static int s_format_id;
262
263
// ==========================================================
264
// Plugin Implementation
265
// ==========================================================
266
267
static const char * DLL_CALLCONV
268
2
Format() {
269
2
  return "XBM";
270
2
}
271
272
static const char * DLL_CALLCONV
273
0
Description() {
274
0
  return "X11 Bitmap Format";
275
0
}
276
277
static const char * DLL_CALLCONV
278
0
Extension() {
279
0
  return "xbm";
280
0
}
281
282
static const char * DLL_CALLCONV
283
0
RegExpr() {
284
0
  return NULL;
285
0
}
286
287
static const char * DLL_CALLCONV
288
0
MimeType() {
289
0
  return "image/x-xbitmap";
290
0
}
291
292
static BOOL DLL_CALLCONV
293
29.3k
Validate(FreeImageIO *io, fi_handle handle) {
294
29.3k
  char magic[8];
295
29.3k
  if(readLine(magic, 7, io, handle)) {
296
29.3k
    if(strcmp(magic, "#define") == 0)
297
0
      return TRUE;
298
29.3k
  }
299
29.3k
  return FALSE;
300
29.3k
}
301
302
static BOOL DLL_CALLCONV
303
0
SupportsExportDepth(int depth) {
304
0
  return FALSE;
305
0
}
306
307
static BOOL DLL_CALLCONV 
308
0
SupportsExportType(FREE_IMAGE_TYPE type) {
309
0
  return FALSE;
310
0
}
311
312
// ----------------------------------------------------------
313
314
static FIBITMAP * DLL_CALLCONV
315
0
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
316
0
  char *buffer = NULL;
317
0
  int width, height;
318
0
  FIBITMAP *dib = NULL;
319
320
0
  try {
321
322
    // load the bitmap data
323
0
    const char* error = readXBMFile(io, handle, &width, &height, &buffer);
324
    // Microsoft doesn't implement throw between functions :(
325
0
    if(error) throw (char*)error;
326
327
328
    // allocate a new dib
329
0
    dib = FreeImage_Allocate(width, height, 1);
330
0
    if(!dib) throw (char*)ERR_XBM_MEMORY;
331
332
    // write the palette data
333
0
    RGBQUAD *pal = FreeImage_GetPalette(dib);
334
0
    pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
335
0
    pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
336
337
    // copy the bitmap
338
0
    BYTE *bP = (BYTE*)buffer;
339
0
    for(int y = 0; y < height; y++) {
340
0
      BYTE count = 0;
341
0
      BYTE mask = 1;
342
0
      BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
343
344
0
      for(int x = 0; x < width; x++) {
345
0
        if(count >= 8) {
346
0
          bP++;
347
0
          count = 0;
348
0
          mask = 1;
349
0
        }
350
0
        if(*bP & mask) {
351
          // Set bit(x, y) to 0
352
0
          bits[x >> 3] &= (0xFF7F >> (x & 0x7));
353
0
        } else {
354
          // Set bit(x, y) to 1
355
0
          bits[x >> 3] |= (0x80 >> (x & 0x7));
356
0
        }
357
0
        count++;
358
0
        mask <<= 1;
359
0
      }
360
0
      bP++;
361
0
    }
362
363
0
    free(buffer);
364
0
    return dib;
365
366
0
  } catch(const char *text) {
367
0
    if(buffer) free(buffer);
368
0
    if(dib)   FreeImage_Unload(dib);
369
0
    FreeImage_OutputMessageProc(s_format_id, text);
370
0
    return NULL;
371
0
  }
372
0
}
373
374
375
// ==========================================================
376
//   Init
377
// ==========================================================
378
379
void DLL_CALLCONV
380
2
InitXBM(Plugin *plugin, int format_id) {
381
2
    s_format_id = format_id;
382
383
2
  plugin->format_proc = Format;
384
2
  plugin->description_proc = Description;
385
2
  plugin->extension_proc = Extension;
386
2
  plugin->regexpr_proc = RegExpr;
387
2
  plugin->open_proc = NULL;
388
2
  plugin->close_proc = NULL;
389
2
  plugin->pagecount_proc = NULL;
390
2
  plugin->pagecapability_proc = NULL;
391
2
  plugin->load_proc = Load;
392
2
  plugin->save_proc = NULL;
393
2
  plugin->validate_proc = Validate;
394
2
  plugin->mime_proc = MimeType;
395
2
  plugin->supports_export_bpp_proc = SupportsExportDepth;
396
2
  plugin->supports_export_type_proc = SupportsExportType;
397
2
  plugin->supports_icc_profiles_proc = NULL;
398
2
}
399