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