ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/color.c
Revision: 2.26
Committed: Sat Jul 1 01:31:17 2023 UTC (10 months, 2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4
Changes since 2.25: +6 -9 lines
Log Message:
fix: Better fix to potential vulnerability from malicious/corrupted image

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: color.c,v 2.25 2023/06/30 15:00:32 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 = 0;
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 i = scanline[0][EXP] << rshift;
142 while (i--) {
143 copycolr(scanline[0], scanline[-1]);
144 if (--len <= 0)
145 return(0);
146 scanline++;
147 }
148 rshift += 8;
149 } else {
150 scanline++;
151 len--;
152 rshift = 0;
153 }
154 }
155 return(0);
156 }
157
158 /*
159 * There are two scanline formats: old and new. The old format
160 * compresses runs of RGBE or XYZE four-byte real pixels; the new
161 * format breaks the pixels into R, G, B, and E lines (or XYZE lines)
162 * which are individually run-length encoded.
163 *
164 * An old-format scanline always begins with a valid real pixel; at
165 * least one of the RGB (or XYZ) values will have its high-order bit
166 * set. A new-format scanline begins with four bytes which are not a
167 * valid real pixel: (2, 2, lenhigh, lenlow) where lenhigh is always
168 * less than 128 and hence never has a high-order bit set.
169 *
170 * A new-format scanline is broken into its RGBE or XYZE components.
171 * Each is output and run-length encoded separately so that a scanline
172 * is broken into four records. In turn, each record is organized
173 * into chunks of up to 128 characters, which begin with a count byte.
174 * If the count byte is greater than 128, the following data byte is
175 * repeated (count-128) times. If not, the count byte is followed by
176 * that many data bytes.
177 */
178 int
179 freadcolrs( /* read in an encoded colr scanline */
180 COLR *scanline,
181 int len,
182 FILE *fp
183 )
184 {
185 int i, j;
186 int code, val;
187 /* determine scanline type */
188 if (len <= 0)
189 return(0);
190 if ((i = getc(fp)) == EOF)
191 return(-1);
192 scanline[0][RED] = i;
193 scanline[0][GRN] = getc(fp);
194 scanline[0][BLU] = getc(fp);
195 if ((i = getc(fp)) == EOF)
196 return(-1);
197 if ((scanline[0][RED] != 2) | (scanline[0][GRN] != 2) |
198 (scanline[0][BLU] & 0x80)) {
199 scanline[0][EXP] = i;
200 return(oldreadcolrs(scanline+1, len-1, fp));
201 }
202 if ((scanline[0][BLU]<<8 | i) != len)
203 return(-1); /* length mismatch! */
204 /* read each component */
205 for (i = 0; i < 4; i++)
206 for (j = 0; j < len; ) {
207 if ((code = getc(fp)) == EOF)
208 return(-1);
209 if (code > 128) { /* run */
210 code &= 127;
211 if ((val = getc(fp)) == EOF)
212 return -1;
213 if (j + code > len)
214 return -1; /* overrun */
215 while (code--)
216 scanline[j++][i] = val;
217 } else { /* non-run */
218 if (j + code > len)
219 return -1; /* overrun */
220 while (code--) {
221 if ((val = getc(fp)) == EOF)
222 return -1;
223 scanline[j++][i] = val;
224 }
225 }
226 }
227 return(0);
228 }
229
230
231 int
232 fwritescan( /* write out a scanline */
233 COLOR *scanline,
234 int len,
235 FILE *fp
236 )
237 {
238 COLR *clrscan;
239 int n;
240 COLR *sp;
241 /* get scanline buffer */
242 if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
243 return(-1);
244 clrscan = sp;
245 /* convert scanline */
246 n = len;
247 while (n-- > 0) {
248 setcolr(sp[0], scanline[0][RED],
249 scanline[0][GRN],
250 scanline[0][BLU]);
251 scanline++;
252 sp++;
253 }
254 return(fwritecolrs(clrscan, len, fp));
255 }
256
257
258 int
259 freadscan( /* read in a scanline */
260 COLOR *scanline,
261 int len,
262 FILE *fp
263 )
264 {
265 COLR *clrscan;
266
267 if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
268 return(-1);
269 if (freadcolrs(clrscan, len, fp) < 0)
270 return(-1);
271 /* convert scanline */
272 colr_color(scanline[0], clrscan[0]);
273 while (--len > 0) {
274 scanline++; clrscan++;
275 if (clrscan[0][GRN] == clrscan[-1][GRN] &&
276 (clrscan[0][RED] == clrscan[-1][RED]) &
277 (clrscan[0][BLU] == clrscan[-1][BLU]) &
278 (clrscan[0][EXP] == clrscan[-1][EXP]))
279 copycolor(scanline[0], scanline[-1]);
280 else
281 colr_color(scanline[0], clrscan[0]);
282 }
283 return(0);
284 }
285
286
287 void
288 setcolr( /* assign a short color value */
289 COLR clr,
290 double r,
291 double g,
292 double b
293 )
294 {
295 double d;
296 int e;
297
298 d = r > g ? r : g;
299 if (b > d) d = b;
300
301 if (d <= 1e-32) {
302 clr[RED] = clr[GRN] = clr[BLU] = 0;
303 clr[EXP] = 0;
304 return;
305 }
306
307 d = frexp(d, &e) * 256.0 / d;
308
309 if (r > 0.0)
310 clr[RED] = r * d;
311 else
312 clr[RED] = 0;
313 if (g > 0.0)
314 clr[GRN] = g * d;
315 else
316 clr[GRN] = 0;
317 if (b > 0.0)
318 clr[BLU] = b * d;
319 else
320 clr[BLU] = 0;
321
322 clr[EXP] = e + COLXS;
323 }
324
325
326 void
327 colr_color( /* convert short to float color */
328 COLOR col,
329 COLR clr
330 )
331 {
332 double f;
333
334 if (clr[EXP] == 0)
335 col[RED] = col[GRN] = col[BLU] = 0.0;
336 else {
337 f = ldexp(1.0, (int)clr[EXP]-(COLXS+8));
338 col[RED] = (clr[RED] + 0.5)*f;
339 col[GRN] = (clr[GRN] + 0.5)*f;
340 col[BLU] = (clr[BLU] + 0.5)*f;
341 }
342 }
343
344
345 int
346 bigdiff( /* c1 delta c2 > md? */
347 COLOR c1,
348 COLOR c2,
349 double md
350 )
351 {
352 int i;
353
354 for (i = 0; i < 3; i++)
355 if (colval(c1,i)-colval(c2,i) > md*colval(c2,i) ||
356 colval(c2,i)-colval(c1,i) > md*colval(c1,i))
357 return(1);
358 return(0);
359 }