Krita Source Code Documentation
Loading...
Searching...
No Matches
xcf-general.c
Go to the documentation of this file.
1/* Generic functions for reading XCF files
2 *
3 * This file was written by Henning Makholm <henning@makholm.net>
4 * It is hereby in the public domain.
5 *
6 * In jurisdictions that do not recognise grants of copyright to the
7 * public domain: I, the author and (presumably, in those jurisdictions)
8 * copyright holder, hereby permit anyone to distribute and use this code,
9 * in source code or binary form, with or without modifications. This
10 * permission is world-wide and irrevocable.
11 *
12 * Of course, I will not be liable for any errors or shortcomings in the
13 * code, since I give it away without asking any compenstations.
14 *
15 * If you use or distribute this code, I would appreciate receiving
16 * credit for writing it, in whichever way you find proper and customary.
17 */
18
19#include "xcftools.h"
20#include <string.h>
21#include <errno.h>
22#include <limits.h>
23#ifdef HAVE_ICONV
24# include <iconv.h>
25#elif !defined(ICONV_CONST)
26# define ICONV_CONST const
27#endif
28
29uint8_t *xcf_file = 0 ;
30size_t xcf_length ;
31int use_utf8 = 0 ;
32
33int
34xcfOffset(uint32_t addr,int spaceafter, uint32_t* apparent)
35{
36 if (!apparent) {
37 return XCF_ERROR;
38 }
39 if(xcfCheckspace(addr,4,"(xcfOffset)") != XCF_OK) {
40 return XCF_ERROR;
41 }
42 *apparent = xcfL(addr);
43 if (xcfCheckspace(*apparent,spaceafter,
44 "Too large offset (%" PRIX32 ") at position %" PRIX32,
45 *apparent,addr) != XCF_OK) {
46 return XCF_ERROR;
47 }
48 return XCF_OK;
49}
50
51int
52xcfNextprop(uint32_t *master,uint32_t *body, PropType *typeOut)
53{
54 int response;
55
56 if (typeOut == 0) {
57 return XCF_ERROR;
58 }
59
60 uint32_t ptr, length, total, minlength ;
61 PropType type ;
62 ptr = *master ;
63 if ((response = xcfCheckspace(ptr,8,"(property header)")) != XCF_OK) {
64 return XCF_ERROR;
65 }
66 type = xcfL(ptr);
67 length = xcfL(ptr+4);
68 *body = ptr+8 ;
69
70 switch(type) {
71 case PROP_COLORMAP:
72 {
73 uint32_t ncolors ;
74 if ((response = xcfCheckspace(ptr+8,4,"(colormap length)")) != XCF_OK) {
75 return XCF_ERROR;
76 }
77 ncolors = xcfL(ptr+8) ;
78 if( ncolors > 256 ) {
79 FatalBadXCF("Colormap has %" PRIu32 " entries",ncolors);
80 return XCF_ERROR;
81 }
82
83 /* Surprise! Some older version of the Gimp computed the wrong length
84 * word, and the _reader_ always just reads three bytes per color
85 * and ignores the length tag! Duplicate this so we too can read
86 * the buggy XCF files.
87 */
88 length = minlength = 4+3*ncolors;
89 break;
90 }
91 case PROP_COMPRESSION: minlength = 1; break;
92 case PROP_OPACITY: minlength = 4; break;
93 case PROP_APPLY_MASK: minlength = 4; break;
94 case PROP_OFFSETS: minlength = 8; break;
95 case PROP_MODE: minlength = 4; break;
96 default: minlength = 0; break;
97 }
98 if( length < minlength ) {
99 FatalBadXCF("Short %s property at %" PRIX32 " (%" PRIu32 "<%" PRIu32 ")",
100 showPropType(type),ptr,length,minlength);
101 return XCF_ERROR;
102 }
103 *master = ptr+8+length ;
104 total = 8 + length + (type != PROP_END ? 8 : 0) ;
105 if( total < length ) { /* Check overwrap */
106 FatalBadXCF("Overlong property at %" PRIX32, ptr);
107 return XCF_ERROR;
108 }
109 if((response = xcfCheckspace(ptr,total,"Overlong property at %" PRIX32,ptr)) != 0) {
110 return XCF_ERROR;
111 }
112 *typeOut = type;
113 return XCF_OK;
114}
115
116const char*
117xcfString(uint32_t ptr,uint32_t *after)
118{
119 uint32_t length ;
120 unsigned i ;
121 ICONV_CONST char *utf8master ;
122
123 if (xcfCheckspace(ptr,4,"(string length)") != XCF_OK) {
124 return XCF_PTR_EMPTY;
125 }
126 length = xcfL(ptr) ;
127 ptr += 4 ;
128 if (xcfCheckspace(ptr,length,"(string)") != XCF_OK) {
129 return XCF_PTR_EMPTY;
130 }
131 utf8master = (ICONV_CONST char*)(xcf_file+ptr) ;
132 if( after ) *after = ptr + length ;
133 if( length == 0 || utf8master[length-1] != 0 ) {
134 FatalBadXCF("String at %" PRIX32 " not zero-terminated",ptr-4);
135 return XCF_PTR_EMPTY;
136 }
137 length-- ;
138
139 if( use_utf8 ) return utf8master ;
140
141 /* We assume that the local character set includes ASCII...
142 * Check if conversion is needed at all
143 */
144 for( i=0 ; ; i++ ) {
145 if( i == length )
146 return utf8master ; /* Only ASCII after all */
147 if( utf8master[i] == 0 ) {
148 FatalBadXCF("String at %" PRIX32 " has embedded zeroes",ptr-4);
149 return XCF_PTR_EMPTY;
150 }
151 if( (int8_t) utf8master[i] < 0 )
152 break ;
153 }
154#ifdef HAVE_ICONV
155 {
156 size_t targetsize = length+1 ;
157 int sloppy_translation = 0 ;
158 iconv_t cd = iconv_open("//TRANSLIT","UTF-8");
159 if( cd == (iconv_t) -1 ) {
160 cd = iconv_open("","UTF-8");
161 sloppy_translation = 1 ;
162 }
163 if( cd == (iconv_t) -1 )
164 iconv_close(cd) ; /* Give up; perhaps iconv doesn't know UTF-8 */
165 else
166 while(1) {
167 char *buffer = xcfmalloc(targetsize) ;
168 ICONV_CONST char *inbuf = utf8master ;
169 char *outbuf = buffer ;
170 size_t incount = length ;
171 size_t outcount = targetsize ;
172 while(1) { /* Loop for systems without //ICONV support */
173 size_t result = iconv(cd,&inbuf,&incount,&outbuf,&outcount) ;
174 if( result == (size_t)-1 && errno == EILSEQ &&
175 sloppy_translation && outcount > 0 ) {
176 *outbuf++ = '?' ;
177 outcount-- ;
178 while( (int8_t)*inbuf < 0 ) inbuf++, incount-- ;
179 continue ;
180 }
181 if( result != (size_t)-1 ) {
182 if( outcount == 0 )
183 errno = E2BIG ;
184 else {
185 *outbuf = 0 ;
186 iconv_close(cd) ;
187 return buffer ;
188 }
189 }
190 break ;
191 }
192 if( errno == EILSEQ || errno == EINVAL ) {
193 FatalBadXCF("Bad UTF-8 encoding '%s' at %" PRIXPTR,
194 inbuf,(uintptr_t)((inbuf-utf8master)+ptr));
195 return XCF_PTR_EMPTY;
196 }
197 if( errno == E2BIG ) {
198 targetsize += 1+incount ;
199 xcffree(buffer) ;
200 continue ;
201 }
202 FatalUnexpected("!iconv on layer name at %" PRIX32, ptr);
203 return XCF_PTR_EMPTY:
204 }
205 }
206#endif
207 {
208 static int warned = 0 ;
209 if( !warned ) {
210 fprintf(stderr,_("Warning: one or more layer names could not be\n"
211 " translated to the local character set.\n"));
212 warned = 1 ;
213 }
214 }
215 return utf8master ;
216}
217
218/* ****************************************************************** */
219
221{
222 // [ CVE-2019-5086 and CVE-2019-5087 ]
223 // This part of code is the check to prevent integer overflow, see CVE-2019-5086 and CVE-2019-5087
224
225 if ((d->c.l + d->width) * 4 > INT_MAX) {
226 FatalBadXCF(("Width is too large (%d)! Stopping execution...\n"), (d->c.l + d->width));
227 return XCF_ERROR;
228 }
229
230 if ((d->c.t + d->height) * 4 > INT_MAX) {
231 FatalBadXCF(("Height is too large (%d)! Stopping execution...\n"), (d->c.t + d->height));
232 return XCF_ERROR;
233 }
234 // [ CVE-2019-5086 and CVE-2019-5087 ]
235
236 d->c.r = d->c.l + d->width ;
237 d->c.b = d->c.t + d->height ;
238 d->tilesx = (d->width+TILE_WIDTH-1)/TILE_WIDTH ;
239 d->tilesy = (d->height+TILE_HEIGHT-1)/TILE_HEIGHT ;
240 d->ntiles = d->tilesx * d->tilesy ;
241
242 return XCF_OK;
243}
244
245struct xcfImage XCF ;
246
247int
249{
250 uint32_t ptr, data, layerfile ;
251 PropType type ;
252 int i, j ;
253
254 int errorStatus;
255 uint32_t ptrout;
256
257 if (xcfCheckspace(0,14+7*4,"(very short)") != XCF_OK) {
258 return XCF_ERROR;
259 }
260
261 if( strcmp((char*)xcf_file,"gimp xcf file") == 0 )
262 XCF.version = 0 ;
263 else if( xcf_file[13] == 0 &&
264 sscanf((char*)xcf_file,"gimp xcf v%d",&XCF.version) == 1 )
265 ;
266 else {
267 FatalBadXCF(_("Not an XCF file at all (magic not recognized)"));
268 return XCF_ERROR;
269 }
270
271 if (XCF.version < 0 || XCF.version > 2) {
272 fprintf(stderr, _("Warning: XCF version %d not supported (trying anyway...)\n"), XCF.version);
273 }
274
276 XCF.colormapptr = 0 ;
277
278 ptr = 14 ;
279 XCF.width = xcfL(ptr); ptr += 4 ;
280 XCF.height = xcfL(ptr); ptr += 4 ;
281 XCF.type = xcfL(ptr); ptr += 4 ;
282 while( (errorStatus = xcfNextprop(&ptr,&data, &type)) != XCF_ERROR && type != PROP_END ) {
283 if (errorStatus != XCF_OK) {
284 return XCF_ERROR;
285 }
286
287 switch(type) {
288 case PROP_COLORMAP:
289 XCF.colormapptr = data ;
290 break ;
291 case PROP_COMPRESSION:
292 XCF.compression = xcf_file[data] ;
293 break ;
294 default:
295 /* Ignore unknown properties */
296 break ;
297 }
298 }
299
300 layerfile = ptr ;
301 XCF.numLayers = 0;
302 while (1) {
303 errorStatus = xcfOffset(ptr,8*4, &ptrout);
304 if (errorStatus != XCF_OK) {
305 return XCF_ERROR;
306 }
307 if (!ptrout) {
308 break;
309 }
310 XCF.numLayers++;
311 ptr+=4;
312 }
313 XCF.layers = xcfmalloc(XCF.numLayers * sizeof(struct xcfLayer)) ;
314 for( i = 0 ; i < XCF.numLayers ; i++ ) {
315 struct xcfLayer *L = XCF.layers + i ;
316 ptr = xcfL(layerfile+4*(XCF.numLayers-1-i)) ;
317
319 L->opacity = 255 ;
320 L->isVisible = 1 ;
321 L->hasMask = 0 ;
322 L->dim.width = xcfL(ptr); ptr+=4 ;
323 L->dim.height = xcfL(ptr); ptr+=4 ;
324 L->type = xcfL(ptr); ptr+=4 ;
325 L->name = xcfString(ptr,&ptr);
326 if (L->name == XCF_PTR_EMPTY) {
327 return XCF_ERROR;
328 }
329 L->propptr = ptr ;
330
331 L->isGroup = 0;
332 L->pathLength = 0;
333 L->path = NULL;
334
335 while( (errorStatus = xcfNextprop(&ptr,&data, &type)) != XCF_ERROR && type != PROP_END ) {
336 if (errorStatus != XCF_OK) {
339 return XCF_ERROR;
340 }
341 switch(type) {
342 case PROP_OPACITY:
343 L->opacity = xcfL(data);
344 if( L->opacity > 255 )
345 L->opacity = 255 ;
346 break ;
347 case PROP_VISIBLE:
348 L->isVisible = xcfL(data) != 0 ;
349 break ;
350 case PROP_APPLY_MASK:
351 L->hasMask = xcfL(data) != 0 ;
352 break ;
353 case PROP_OFFSETS:
354 L->dim.c.l = (int32_t)(xcfL(data )) ;
355 L->dim.c.t = (int32_t)(xcfL(data+4)) ;
356 break ;
357 case PROP_MODE:
358 L->mode = xcfL(data);
359 break ;
360 case PROP_GROUP_ITEM:
361 L->isGroup = 1 ;
362 break;
363 case PROP_ITEM_PATH:
364 L->pathLength = (ptr - data - 2) / 4 ;
365
366 if ( L->pathLength != 0 ) {
367
368 L->path = xcfmalloc( L->pathLength * sizeof(unsigned) ) ;
369
370 for ( j = 0; j!=L->pathLength; j++ )
371 *(L->path + j) = (unsigned)xcfL(data + 4 * j);
372 }
373 break;
374 default:
375 /* Ignore unknown properties */
376 break ;
377 }
378 }
379 if ((errorStatus = xcfCheckspace(ptr,8,"(end of layer %s)",L->name)) != XCF_OK) {
382 return XCF_ERROR;
383 }
384 L->pixels.tileptrs = 0 ;
385 if (xcfOffset(ptr , 4*4, &(L->pixels.hierarchy)) != XCF_OK) {
388 return XCF_ERROR;
389 }
390 L->mask.tileptrs = 0 ;
391 if (xcfOffset(ptr+4, 4*4, &(L->mask.hierarchy)) != XCF_OK) {
394 return XCF_ERROR;
395 }
396
397 if (computeDimensions(&L->dim) != XCF_OK) {
398 return XCF_ERROR;
399 }
400 }
401 return XCF_OK;
402}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
const char * showPropType(PropType x)
Definition enums.c:69
@ GIMP_NORMAL_MODE
Definition enums.h:9
@ COMPRESS_NONE
Definition enums.h:97
PropType
Definition enums.h:59
@ PROP_MODE
Definition enums.h:67
@ PROP_ITEM_PATH
Definition enums.h:90
@ PROP_VISIBLE
Definition enums.h:68
@ PROP_COMPRESSION
Definition enums.h:77
@ PROP_COLORMAP
Definition enums.h:61
@ PROP_GROUP_ITEM
Definition enums.h:89
@ PROP_OPACITY
Definition enums.h:66
@ PROP_APPLY_MASK
Definition enums.h:71
@ PROP_OFFSETS
Definition enums.h:75
@ PROP_END
Definition enums.h:60
int l
Definition xcftools.h:130
int t
Definition xcftools.h:130
struct rect c
Definition xcftools.h:166
unsigned height
Definition xcftools.h:167
unsigned width
Definition xcftools.h:167
GimpImageBaseType type
Definition xcftools.h:198
XcfCompressionType compression
Definition xcftools.h:199
unsigned height
Definition xcftools.h:197
unsigned width
Definition xcftools.h:197
int numLayers
Definition xcftools.h:200
struct xcfLayer * layers
Definition xcftools.h:201
int version
Definition xcftools.h:196
uint32_t colormapptr
Definition xcftools.h:202
unsigned int opacity
Definition xcftools.h:185
unsigned pathLength
Definition xcftools.h:191
int isVisible
Definition xcftools.h:186
GimpLayerModeEffects mode
Definition xcftools.h:183
struct xcfTiles pixels
Definition xcftools.h:188
int isGroup
Definition xcftools.h:190
int hasMask
Definition xcftools.h:186
uint32_t propptr
Definition xcftools.h:187
struct tileDimensions dim
Definition xcftools.h:181
unsigned * path
Definition xcftools.h:192
const char * name
Definition xcftools.h:182
GimpImageType type
Definition xcftools.h:184
struct xcfTiles mask
Definition xcftools.h:189
uint32_t hierarchy
Definition xcftools.h:177
uint32_t * tileptrs
Definition xcftools.h:176
void * xcfmalloc(size_t size)
Definition utils.c:114
void xcffree(void *block)
Definition utils.c:125
void FatalUnexpected(const char *format,...)
Definition utils.c:56
void FatalBadXCF(const char *format,...)
Definition utils.c:66
int xcfCheckspace(uint32_t addr, int spaceafter, const char *format,...)
Definition utils.c:75
int use_utf8
Definition xcf-general.c:31
int xcfOffset(uint32_t addr, int spaceafter, uint32_t *apparent)
Definition xcf-general.c:34
int getBasicXcfInfo(void)
int xcfNextprop(uint32_t *master, uint32_t *body, PropType *typeOut)
Definition xcf-general.c:52
#define ICONV_CONST
Definition xcf-general.c:26
struct xcfImage XCF
const char * xcfString(uint32_t ptr, uint32_t *after)
int computeDimensions(struct tileDimensions *d)
size_t xcf_length
Definition xcf-general.c:30
uint8_t * xcf_file
Definition xcf-general.c:29
#define TILE_HEIGHT
Definition xcftools.h:155
#define TILE_WIDTH
Definition xcftools.h:154
#define xcfL(a)
Definition xcftools.h:91
#define XCF_OK
Definition xcftools.h:106
#define XCF_ERROR
Definition xcftools.h:105
#define XCF_PTR_EMPTY
Definition xcftools.h:107
#define _(s)
Definition xcftools.h:32