ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/color.c
Revision: 2.24
Committed: Fri Jun 30 00:58:47 2023 UTC (11 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.23: +4 -3 lines
Log Message:
fix: protection against malicious or corrupted input

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: color.c,v 2.23 2022/12/03 21:37:26 greg Exp $";
3 #endif
4 /*
5 * color.c - routines for color calculations.
6 *
7 * Externals declared in color.h
8 */
9
10 #include "copyright.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <math.h>
15 #include "color.h"
16
17 #ifdef getc_unlocked /* avoid horrendous overhead of flockfile */
18 #undef getc
19 #undef putc
20 #undef ferror
21 #define getc getc_unlocked
22 #define putc putc_unlocked
23 #define ferror ferror_unlocked
24 #endif
25
26 #define MINELEN 8 /* minimum scanline length for encoding */
27 #define MAXELEN 0x7fff /* maximum scanline length for encoding */
28 #define MINRUN 4 /* minimum run length */
29
30
31 void *
32 tempbuffer( /* get a temporary buffer */
33 unsigned int len
34 )
35 {
36 static void *tempbuf = NULL;
37 static unsigned int tempbuflen = 0;
38
39 if (!len) { /* call to free */
40 if (tempbuflen) {
41 free(tempbuf);
42 tempbuf = NULL;
43 tempbuflen = 0;
44 }
45 return(NULL);
46 }
47 if (len <= tempbuflen) /* big enough already? */
48 return(tempbuf);
49 /* else free & reallocate */
50 if (tempbuflen)
51 free(tempbuf);
52 tempbuf = malloc(len);
53 tempbuflen = len*(tempbuf != NULL);
54 return(tempbuf);
55 }
56
57
58 int
59 fwritecolrs( /* write out a colr scanline */
60 COLR *scanline,
61 int len,
62 FILE *fp
63 )
64 {
65 int i, j, beg, cnt = 1;
66 int c2;
67
68 if ((len < MINELEN) | (len > MAXELEN)) /* OOBs, write out flat */
69 return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len);
70 /* put magic header */
71 putc(2, fp);
72 putc(2, fp);
73 putc(len>>8, fp);
74 putc(len&0xff, fp);
75 /* put components seperately */
76 for (i = 0; i < 4; i++) {
77 for (j = 0; j < len; j += cnt) { /* find next run */
78 for (beg = j; beg < len; beg += cnt) {
79 for (cnt = 1; (cnt < 127) & (beg+cnt < len) &&
80 scanline[beg+cnt][i] == scanline[beg][i]; cnt++)
81 ;
82 if (cnt >= MINRUN)
83 break; /* long enough */
84 }
85 if ((beg-j > 1) & (beg-j < MINRUN)) {
86 c2 = j+1;
87 while (scanline[c2++][i] == scanline[j][i])
88 if (c2 == beg) { /* short run */
89 putc(128+beg-j, fp);
90 putc(scanline[j][i], fp);
91 j = beg;
92 break;
93 }
94 }
95 while (j < beg) { /* write out non-run */
96 if ((c2 = beg-j) > 128) c2 = 128;
97 putc(c2, fp);
98 while (c2--)
99 putc(scanline[j++][i], fp);
100 }
101 if (cnt >= MINRUN) { /* write out run */
102 putc(128+cnt, fp);
103 putc(scanline[beg][i], fp);
104 } else
105 cnt = 0;
106 }
107 }
108 return(ferror(fp) ? -1 : 0);
109 }
110
111 /*
112 * An old-format scanline is either a stream of valid RGBE or XYZE real
113 * pixels or at least one real pixel followed by some number of
114 * invalid real pixels of the form (1,1,1,n), where n is a count.
115 * These can themselves be repeated to create a multibyte repeat
116 * count, with the least significant byte first (little-endian order.)
117 * Repeat counts are limited by the size of an int; if a repetition
118 * leads to an overrun, the rest of the the repetition will be
119 * silently ignored.
120 */
121 static int
122 oldreadcolrs( /* read in an old-style colr scanline */
123 COLR *scanline,
124 int len,
125 FILE *fp
126 )
127 {
128 int rshift = -1;
129 int i;
130
131 while (len > 0) {
132 scanline[0][RED] = getc(fp);
133 scanline[0][GRN] = getc(fp);
134 scanline[0][BLU] = getc(fp);
135 scanline[0][EXP] = i = getc(fp);
136 if (i == EOF)
137 return(-1);
138 if (scanline[0][GRN] == 1 &&
139 (scanline[0][RED] == 1) &
140 (scanline[0][BLU] == 1) &&
141 rshift >= 0) {
142 i = scanline[0][EXP] << rshift;
143 while (i--) {
144 copycolr(scanline[0], scanline[-1]);
145 if (--len <= 0)
146 return(0);
147 scanline++;
148 }
149 rshift += 8;
150 } else {
151 scanline++;
152 len--;
153 rshift = 0;
154 }
155 }
156 return(0);
157 }
158
159 /*
160 * There are two scanline formats: old and new. The old format
161 * compresses runs of RGBE or XYZE four-byte real pixels; the new
162 * format breaks the pixels into R, G, B, and E lines (or XYZE lines)
163 * which are individually run-length encoded.
164 *
165 * An old-format scanline always begins with a valid real pixel; at
166 * least one of the RGB (or XYZ) values will have its high-order bit
167 * set. A new-format scanline begins with four bytes which are not a
168 * valid real pixel: (2, 2, lenhigh, lenlow) where lenhigh is always
169 * less than 128 and hence never has a high-order bit set.
170 *
171 * A new-format scanline is broken into its RGBE or XYZE components.
172 * Each is output and run-length encoded separately so that a scanline
173 * is broken into four records. In turn, each record is organized
174 * into chunks of up to 128 characters, which begin with a count byte.
175 * If the count byte is greater than 128, the following data byte is
176 * repeated (count-128) times. If not, the count byte is followed by
177 * that many data bytes.
178 */
179 int
180 freadcolrs( /* read in an encoded colr scanline */
181 COLR *scanline,
182 int len,
183 FILE *fp
184 )
185 {
186 int i, j;
187 int code, val;
188 /* determine scanline type */
189 if ((len < MINELEN) | (len > MAXELEN))
190 return(oldreadcolrs(scanline, len, fp));
191 if ((i = getc(fp)) == EOF)
192 return(-1);
193 if (i != 2) {
194 ungetc(i, fp);
195 return(oldreadcolrs(scanline, len, fp));
196 }
197 scanline[0][GRN] = getc(fp);
198 scanline[0][BLU] = getc(fp);
199 if ((i = getc(fp)) == EOF)
200 return(-1);
201 if ((scanline[0][GRN] != 2) | ((scanline[0][BLU] & 0x80) != 0)) {
202 scanline[0][RED] = 2;
203 scanline[0][EXP] = i;
204 return(oldreadcolrs(scanline+1, len-1, fp));
205 }
206 if ((scanline[0][BLU]<<8 | i) != len)
207 return(-1); /* length mismatch! */
208 /* read each component */
209 for (i = 0; i < 4; i++)
210 for (j = 0; j < len; ) {
211 if ((code = getc(fp)) == EOF)
212 return(-1);
213 if (code > 128) { /* run */
214 code &= 127;
215 if ((val = getc(fp)) == EOF)
216 return -1;
217 if (j + code > len)
218 return -1; /* overrun */
219 while (code--)
220 scanline[j++][i] = val;
221 } else { /* non-run */
222 if (j + code > len)
223 return -1; /* overrun */
224 while (code--) {
225 if ((val = getc(fp)) == EOF)
226 return -1;
227 scanline[j++][i] = val;
228 }
229 }
230 }
231 return(0);
232 }
233
234
235 int
236 fwritescan( /* write out a scanline */
237 COLOR *scanline,
238 int len,
239 FILE *fp
240 )
241 {
242 COLR *clrscan;
243 int n;
244 COLR *sp;
245 /* get scanline buffer */
246 if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
247 return(-1);
248 clrscan = sp;
249 /* convert scanline */
250 n = len;
251 while (n-- > 0) {
252 setcolr(sp[0], scanline[0][RED],
253 scanline[0][GRN],
254 scanline[0][BLU]);
255 scanline++;
256 sp++;
257 }
258 return(fwritecolrs(clrscan, len, fp));
259 }
260
261
262 int
263 freadscan( /* read in a scanline */
264 COLOR *scanline,
265 int len,
266 FILE *fp
267 )
268 {
269 COLR *clrscan;
270
271 if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
272 return(-1);
273 if (freadcolrs(clrscan, len, fp) < 0)
274 return(-1);
275 /* convert scanline */
276 colr_color(scanline[0], clrscan[0]);
277 while (--len > 0) {
278 scanline++; clrscan++;
279 if (clrscan[0][GRN] == clrscan[-1][GRN] &&
280 (clrscan[0][RED] == clrscan[-1][RED]) &
281 (clrscan[0][BLU] == clrscan[-1][BLU]) &
282 (clrscan[0][EXP] == clrscan[-1][EXP]))
283 copycolor(scanline[0], scanline[-1]);
284 else
285 colr_color(scanline[0], clrscan[0]);
286 }
287 return(0);
288 }
289
290
291 void
292 setcolr( /* assign a short color value */
293 COLR clr,
294 double r,
295 double g,
296 double b
297 )
298 {
299 double d;
300 int e;
301
302 d = r > g ? r : g;
303 if (b > d) d = b;
304
305 if (d <= 1e-32) {
306 clr[RED] = clr[GRN] = clr[BLU] = 0;
307 clr[EXP] = 0;
308 return;
309 }
310
311 d = frexp(d, &e) * 256.0 / d;
312
313 if (r > 0.0)
314 clr[RED] = r * d;
315 else
316 clr[RED] = 0;
317 if (g > 0.0)
318 clr[GRN] = g * d;
319 else
320 clr[GRN] = 0;
321 if (b > 0.0)
322 clr[BLU] = b * d;
323 else
324 clr[BLU] = 0;
325
326 clr[EXP] = e + COLXS;
327 }
328
329
330 void
331 colr_color( /* convert short to float color */
332 COLOR col,
333 COLR clr
334 )
335 {
336 double f;
337
338 if (clr[EXP] == 0)
339 col[RED] = col[GRN] = col[BLU] = 0.0;
340 else {
341 f = ldexp(1.0, (int)clr[EXP]-(COLXS+8));
342 col[RED] = (clr[RED] + 0.5)*f;
343 col[GRN] = (clr[GRN] + 0.5)*f;
344 col[BLU] = (clr[BLU] + 0.5)*f;
345 }
346 }
347
348
349 int
350 bigdiff( /* c1 delta c2 > md? */
351 COLOR c1,
352 COLOR c2,
353 double md
354 )
355 {
356 int i;
357
358 for (i = 0; i < 3; i++)
359 if (colval(c1,i)-colval(c2,i) > md*colval(c2,i) ||
360 colval(c2,i)-colval(c1,i) > md*colval(c1,i))
361 return(1);
362 return(0);
363 }