- added integer overflow checks to many memory allocation calls
[imager.git] / img16.c
1 /*
2 =head1 NAME
3
4 img16.c - implements 16-bit images
5
6 =head1 SYNOPSIS
7
8   i_img *im = i_img_16_new(int x, int y, int channels);
9   # use like a normal image
10
11 =head1 DESCRIPTION
12
13 Implements 16-bit/sample images.
14
15 This basic implementation is required so that we have some larger 
16 sample image type to work with.
17
18 =over
19
20 =cut
21 */
22
23 #include "image.h"
24 #include "imagei.h"
25
26 static int i_ppix_d16(i_img *im, int x, int y, i_color *val);
27 static int i_gpix_d16(i_img *im, int x, int y, i_color *val);
28 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals);
29 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals);
30 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val);
31 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val);
32 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
33 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
34 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
35                        int const *chans, int chan_count);
36 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
37                         int const *chans, int chan_count);
38
39 /*
40 =item IIM_base_16bit_direct
41
42 Base structure used to initialize a 16-bit/sample image.
43
44 Internal.
45
46 =cut
47 */
48 static i_img IIM_base_16bit_direct =
49 {
50   0, /* channels set */
51   0, 0, 0, /* xsize, ysize, bytes */
52   ~0U, /* ch_mask */
53   i_16_bits, /* bits */
54   i_direct_type, /* type */
55   0, /* virtual */
56   NULL, /* idata */
57   { 0, 0, NULL }, /* tags */
58   NULL, /* ext_data */
59
60   i_ppix_d16, /* i_f_ppix */
61   i_ppixf_d16, /* i_f_ppixf */
62   i_plin_d16, /* i_f_plin */
63   i_plinf_d16, /* i_f_plinf */
64   i_gpix_d16, /* i_f_gpix */
65   i_gpixf_d16, /* i_f_gpixf */
66   i_glin_d16, /* i_f_glin */
67   i_glinf_d16, /* i_f_glinf */
68   i_gsamp_d16, /* i_f_gsamp */
69   i_gsampf_d16, /* i_f_gsampf */
70
71   NULL, /* i_f_gpal */
72   NULL, /* i_f_ppal */
73   NULL, /* i_f_addcolor */
74   NULL, /* i_f_getcolor */
75   NULL, /* i_f_colorcount */
76   NULL, /* i_f_findcolor */
77
78   NULL, /* i_f_destroy */
79 };
80
81 /* it's possible some platforms won't have a 16-bit integer type,
82    so we check for one otherwise we work by bytes directly
83
84    We do assume 8-bit char
85
86    "Compaq C V6.4-009 on Compaq Tru64 UNIX V5.1A (Rev. 1885)" says it
87    supports C99, but doesn't supply stdint.h, which is required for
88    both hosted and freestanding implementations.  So guard against it.
89 */
90 #if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
91 /* C99 should define something useful */
92 #include <stdint.h>
93 #ifdef UINT16_MAX
94 typedef uint16_t i_sample16_t;
95 #define GOT16
96 #endif
97 #endif
98
99 /* check out unsigned short */
100 #ifndef GOT16
101 #include <limits.h>
102 #if USHRT_MAX == 65535
103 typedef unsigned short i_sample16_t;
104 #define GOT16
105 #endif
106 #endif
107
108 #ifdef GOT16
109
110 /* we have a real 16-bit unsigned integer */
111 #define STORE16(bytes, offset, word) \
112    (((i_sample16_t *)(bytes))[offset] = (word))
113 #define STORE8as16(bytes, offset, byte) \
114    (((i_sample16_t *)(bytes))[offset] = (byte) * 256)
115 #define GET16(bytes, offset) \
116      (((i_sample16_t *)(bytes))[offset])
117 #define GET16as8(bytes, offset) \
118      (((i_sample16_t *)(bytes))[offset] / 256)
119
120 #else
121
122 /* we have to do this the hard way */
123 #define STORE16(bytes, offset, word) \
124    ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \
125     (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF))
126 #define STORE8as16(bytes, offset, byte) \
127    ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \
128     (((unsigned char *)(bytes))[(offset)*2+1] = 0))
129    
130 #define GET16(bytes, offset) \
131    (((unsigned char *)(bytes))[(offset)*2] * 256 \
132     + ((unsigned char *)(bytes))[(offset)*2+1])
133 #define GET16as8(bytes, offset) \
134    (((unsigned char *)(bytes))[(offset)*2] << 8)
135
136 #endif
137
138 /*
139 =item i_img_16_new(int x, int y, int ch)
140
141 Creates a new 16-bit per sample image.
142
143 =cut
144 */
145 i_img *i_img_16_new_low(i_img *im, int x, int y, int ch) {
146   int bytes, line_bytes;
147   mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
148
149   if (x < 1 || y < 1) {
150     i_push_error(0, "Image sizes must be positive");
151     return NULL;
152   }
153   if (ch < 1 || ch > MAXCHANNELS) {
154     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
155     return NULL;
156   }
157   bytes =  x * y * ch * 2;
158   if (bytes / y / ch / 2 != x) {
159     i_push_errorf(0, "integer overflow calculating image allocation");
160     return NULL;
161   }
162   
163   /* basic assumption: we can always allocate a buffer representing a
164      line from the image, otherwise we're going to have trouble
165      working with the image */
166   line_bytes = sizeof(i_fcolor) * x;
167   if (line_bytes / x != sizeof(i_fcolor)) {
168     i_push_error(0, "integer overflow calculating scanline allocation");
169     return NULL;
170   }
171
172   *im = IIM_base_16bit_direct;
173   i_tags_new(&im->tags);
174   im->xsize = x;
175   im->ysize = y;
176   im->channels = ch;
177   im->bytes = bytes;
178   im->ext_data = NULL;
179   im->idata = mymalloc(im->bytes);
180   if (im->idata) {
181     memset(im->idata, 0, im->bytes);
182   }
183   else {
184     i_tags_destroy(&im->tags);
185     im = NULL;
186   }
187   
188   return im;
189 }
190
191 i_img *i_img_16_new(int x, int y, int ch) {
192   i_img *im;
193   
194   i_clear_error();
195
196   im = mymalloc(sizeof(i_img));
197   if (im) {
198     if (!i_img_16_new_low(im, x, y, ch)) {
199       myfree(im);
200       im = NULL;
201     }
202   }
203   
204   mm_log((1, "(%p) <- i_img_16_new\n", im));
205   
206   return im;
207 }
208
209 static int i_ppix_d16(i_img *im, int x, int y, i_color *val) {
210   int off, ch;
211
212   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
213     return -1;
214
215   off = (x + y * im->xsize) * im->channels;
216   if (I_ALL_CHANNELS_WRITABLE(im)) {
217     for (ch = 0; ch < im->channels; ++ch)
218       STORE8as16(im->idata, off+ch, val->channel[ch]);
219   }
220   else {
221     for (ch = 0; ch < im->channels; ++ch)
222       if (im->ch_mask & (1 << ch))
223         STORE8as16(im->idata, off+ch, val->channel[ch]);
224   }
225
226   return 0;
227 }
228
229 static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
230   int off, ch;
231
232   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
233     return -1;
234
235   off = (x + y * im->xsize) * im->channels;
236   for (ch = 0; ch < im->channels; ++ch)
237     val->channel[ch] = GET16as8(im->idata, off+ch);
238
239   return 0;
240 }
241
242 static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val) {
243   int off, ch;
244
245   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
246     return -1;
247
248   off = (x + y * im->xsize) * im->channels;
249   if (I_ALL_CHANNELS_WRITABLE(im)) {
250     for (ch = 0; ch < im->channels; ++ch)
251       STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
252   }
253   else {
254     for (ch = 0; ch < im->channels; ++ch)
255       if (im->ch_mask & (1 << ch))
256         STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
257   }
258
259   return 0;
260 }
261
262 static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
263   int off, ch;
264
265   if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize) 
266     return -1;
267
268   off = (x + y * im->xsize) * im->channels;
269   for (ch = 0; ch < im->channels; ++ch)
270     val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
271
272   return 0;
273 }
274
275 static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
276   int ch, count, i;
277   int off;
278   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
279     if (r > im->xsize)
280       r = im->xsize;
281     off = (l+y*im->xsize) * im->channels;
282     count = r - l;
283     for (i = 0; i < count; ++i) {
284       for (ch = 0; ch < im->channels; ++ch) {
285         vals[i].channel[ch] = GET16as8(im->idata, off);
286         ++off;
287       }
288     }
289     return count;
290   }
291   else {
292     return 0;
293   }
294 }
295
296 static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals) {
297   int ch, count, i;
298   int off;
299   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
300     if (r > im->xsize)
301       r = im->xsize;
302     off = (l+y*im->xsize) * im->channels;
303     count = r - l;
304     if (I_ALL_CHANNELS_WRITABLE(im)) {
305       for (i = 0; i < count; ++i) {
306         for (ch = 0; ch < im->channels; ++ch) {
307           STORE8as16(im->idata, off, vals[i].channel[ch]);
308           ++off;
309         }
310       }
311     }
312     else {
313       for (i = 0; i < count; ++i) {
314         for (ch = 0; ch < im->channels; ++ch) {
315           if (im->ch_mask & (1 << ch))
316             STORE8as16(im->idata, off, vals[i].channel[ch]);
317           ++off;
318         }
319       }
320     }
321     return count;
322   }
323   else {
324     return 0;
325   }
326 }
327
328 static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
329   int ch, count, i;
330   int off;
331   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
332     if (r > im->xsize)
333       r = im->xsize;
334     off = (l+y*im->xsize) * im->channels;
335     count = r - l;
336     for (i = 0; i < count; ++i) {
337       for (ch = 0; ch < im->channels; ++ch) {
338         vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
339         ++off;
340       }
341     }
342     return count;
343   }
344   else {
345     return 0;
346   }
347 }
348
349 static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
350   int ch, count, i;
351   int off;
352   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
353     if (r > im->xsize)
354       r = im->xsize;
355     off = (l+y*im->xsize) * im->channels;
356     count = r - l;
357     if (I_ALL_CHANNELS_WRITABLE(im)) {
358       for (i = 0; i < count; ++i) {
359         for (ch = 0; ch < im->channels; ++ch) {
360           STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
361           ++off;
362         }
363       }
364     }
365     else {
366       for (i = 0; i < count; ++i) {
367         for (ch = 0; ch < im->channels; ++ch) {
368           if (im->ch_mask & (1 << ch))
369             STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
370           ++off;
371         }
372       }
373     }
374     return count;
375   }
376   else {
377     return 0;
378   }
379 }
380
381 static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, 
382                        int const *chans, int chan_count) {
383   int ch, count, i, w;
384   int off;
385
386   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
387     if (r > im->xsize)
388       r = im->xsize;
389     off = (l+y*im->xsize) * im->channels;
390     w = r - l;
391     count = 0;
392
393     if (chans) {
394       /* make sure we have good channel numbers */
395       for (ch = 0; ch < chan_count; ++ch) {
396         if (chans[ch] < 0 || chans[ch] >= im->channels) {
397           i_push_errorf(0, "No channel %d in this image", chans[ch]);
398           return 0;
399         }
400       }
401       for (i = 0; i < w; ++i) {
402         for (ch = 0; ch < chan_count; ++ch) {
403           *samps++ = GET16as8(im->idata, off+chans[ch]);
404           ++count;
405         }
406         off += im->channels;
407       }
408     }
409     else {
410       for (i = 0; i < w; ++i) {
411         for (ch = 0; ch < chan_count; ++ch) {
412           *samps++ = GET16as8(im->idata, off+ch);
413           ++count;
414         }
415         off += im->channels;
416       }
417     }
418
419     return count;
420   }
421   else {
422     return 0;
423   }
424 }
425
426 static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, 
427                         int const *chans, int chan_count) {
428   int ch, count, i, w;
429   int off;
430
431   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
432     if (r > im->xsize)
433       r = im->xsize;
434     off = (l+y*im->xsize) * im->channels;
435     w = r - l;
436     count = 0;
437
438     if (chans) {
439       /* make sure we have good channel numbers */
440       for (ch = 0; ch < chan_count; ++ch) {
441         if (chans[ch] < 0 || chans[ch] >= im->channels) {
442           i_push_errorf(0, "No channel %d in this image", chans[ch]);
443           return 0;
444         }
445       }
446       for (i = 0; i < w; ++i) {
447         for (ch = 0; ch < chan_count; ++ch) {
448           *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
449           ++count;
450         }
451         off += im->channels;
452       }
453     }
454     else {
455       for (i = 0; i < w; ++i) {
456         for (ch = 0; ch < chan_count; ++ch) {
457           *samps++ = Sample16ToF(GET16(im->idata, off+ch));
458           ++count;
459         }
460         off += im->channels;
461       }
462     }
463
464     return count;
465   }
466   else {
467     return 0;
468   }
469 }
470
471 /*
472 =back
473
474 =head1 AUTHOR
475
476 Tony Cook <tony@develop-help.com>
477
478 =head1 SEE ALSO
479
480 Imager(3)
481
482 =cut
483 */