switch to using size_t and i_img_dim strictly
[imager.git] / limits.c
1 /*
2 =head1 NAME
3
4 limits.c - manages data/functions for limiting the sizes of images read from files.
5
6 =head1 SYNOPSIS
7
8   // user code
9   if (!i_set_image_file_limits(max_width, max_height, max_bytes)) {
10     // error
11   }
12   i_get_image_file_limits(&max_width, &max_height, &max_bytes);
13
14   // file reader implementations
15   if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
16     // error handling
17   }
18
19 =head1 DESCRIPTION
20
21 Manage limits for image files read by Imager.
22
23 Setting a value of zero means that limit will be ignored.
24   
25  */
26
27 #include "imageri.h"
28
29 static i_img_dim max_width, max_height;
30 static size_t max_bytes = 0x40000000;
31
32 /*
33 =item i_set_image_file_limits(width, height, bytes)
34
35 =category Files
36 =synopsis i_set_image_file_limits(500, 500, 1000000);
37
38 Set limits on the sizes of images read by Imager.
39
40 Setting a limit to 0 means that limit is ignored.
41
42 Negative limits result in failure.
43
44 Parameters:
45
46 =over
47
48 =item *
49
50 i_img_dim width, height - maximum width and height.
51
52 =item *
53
54 size_t bytes - maximum size in memory in bytes
55
56 =back
57
58 Returns non-zero on success.
59
60 =cut
61 */
62
63 int
64 i_set_image_file_limits(i_img_dim width, i_img_dim height, size_t bytes) {
65   i_clear_error();
66
67   if (width < 0) {
68     i_push_error(0, "width must be non-negative");
69     return 0;
70   }
71   if (height < 0) {
72     i_push_error(0, "height must be non-negative");
73     return 0;
74   }
75   if (bytes < 0) {
76     i_push_error(0, "bytes must be non-negative");
77     return 0;
78   }
79
80   max_width = width;
81   max_height = height;
82   max_bytes = bytes;
83
84   return 1;
85 }
86
87 /*
88 =item i_get_image_file_limits(&width, &height, &bytes)
89
90 =category Files
91 =synopsis i_get_image_file_limits(&width, &height, &bytes)
92
93 Retrieves the file limits set by i_set_image_file_limits().
94
95 =over
96
97 =item *
98
99 i_img_dim *width, *height - the maximum width and height of the image.
100
101 =item *
102
103 size_t *bytes - size in memory of the image in bytes.
104
105 =back
106
107 =cut
108 */
109
110 int
111 i_get_image_file_limits(i_img_dim *width, i_img_dim *height, size_t *bytes) {
112   i_clear_error();
113
114   *width = max_width;
115   *height = max_height;
116   *bytes = max_bytes;
117
118   return 1;
119 }
120
121 /*
122 =item i_int_check_image_file_limits(width, height, channels, sample_size)
123
124 =category Files
125 =synopsis i_i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))
126
127 Checks the size of a file in memory against the configured image file
128 limits.
129
130 This also range checks the values to those permitted by Imager and
131 checks for overflows in calculating the size.
132
133 Returns non-zero if the file is within limits.
134
135 This function is intended to be called by image file read functions.
136
137 =cut
138 */
139
140 int
141 i_int_check_image_file_limits(i_img_dim width, i_img_dim height, int channels, size_t sample_size) {
142   size_t bytes;
143   i_clear_error();
144   
145   if (width <= 0) {
146     i_push_errorf(0, "file size limit - image width of %" i_DF " is not positive",
147                   i_DFc(width));
148     return 0;
149   }
150   if (max_width && width > max_width) {
151     i_push_errorf(0, "file size limit - image width of %" i_DF " exceeds limit of %" i_DF,
152                   i_DFc(width), i_DFc(max_width));
153     return 0;
154   }
155
156   if (height <= 0) {
157     i_push_errorf(0, "file size limit - image height %" i_DF " is not positive",
158                   i_DFc(height));
159     return 0;
160   }
161
162   if (max_height && height > max_height) {
163     i_push_errorf(0, "file size limit - image height of %" i_DF
164                   " exceeds limit of %" i_DF, i_DFc(height), i_DFc(max_height));
165     return 0;
166   }
167
168   if (channels < 1 || channels > MAXCHANNELS) {
169     i_push_errorf(0, "file size limit - channels %d out of range",
170                   channels);
171     return 0;
172   }
173   
174   if (sample_size < 1 || sample_size > sizeof(long double)) {
175     i_push_errorf(0, "file size limit - sample_size %ld out of range",
176                   (long)sample_size);
177     return 0;
178   }
179
180   /* This overflow check is a bit more paranoid than usual.
181      We don't protect it under max_bytes since we always want to check 
182      for overflow.
183   */
184   bytes = width * height * channels * sample_size;
185   if (bytes / width != height * channels * sample_size
186       || bytes / height != width * channels * sample_size) {
187     i_push_error(0, "file size limit - integer overflow calculating storage");
188     return 0;
189   }
190   if (max_bytes) {
191     if (bytes > max_bytes) {
192       i_push_errorf(0, "file size limit - storage size of %lu "
193                     "exceeds limit of %lu", (unsigned long)bytes,
194                     (unsigned long)max_bytes);
195       return 0;
196     }
197   }
198
199   return 1;
200 }