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