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