source: mainline/uspace/lib/gfximage/src/tga.c

Last change on this file was 69d4aba, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 11 months ago

libgfximage: Fix integer multiplication overflow in TGA parser

  • Property mode set to 100644
File size: 7.1 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
3 * Copyright (c) 2011 Petr Koupy
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libgfximage
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <stdlib.h>
38#include <byteorder.h>
39#include <align.h>
40#include <stdbool.h>
41#include <pixconv.h>
42#include <gfx/bitmap.h>
43#include <gfximage/tga.h>
44#include <io/pixelmap.h>
45
46typedef struct {
47 uint8_t id_length;
48 uint8_t cmap_type;
49 uint8_t img_type;
50
51 uint16_t cmap_first_entry;
52 uint16_t cmap_entries;
53 uint8_t cmap_bpp;
54
55 uint16_t startx;
56 uint16_t starty;
57 uint16_t width;
58 uint16_t height;
59 uint8_t img_bpp;
60 uint8_t img_descr;
61} __attribute__((packed)) tga_header_t;
62
63typedef enum {
64 CMAP_NOT_PRESENT = 0,
65 CMAP_PRESENT = 1,
66 CMAP_RESERVED_START = 2,
67 CMAP_PRIVATE_START = 128
68} cmap_type_t;
69
70typedef enum {
71 IMG_EMTPY = 0,
72 IMG_CMAP = 1,
73 IMG_BGRA = 2,
74 IMG_GRAY = 3,
75 IMG_CMAP_RLE = 9,
76 IMG_BGRA_RLE = 10,
77 IMG_GRAY_RLE = 11
78} img_type_t;
79
80typedef struct {
81 cmap_type_t cmap_type;
82 img_type_t img_type;
83
84 uint16_t cmap_first_entry;
85 uint16_t cmap_entries;
86 uint8_t cmap_bpp;
87
88 uint16_t startx;
89 uint16_t starty;
90 uint16_t width;
91 uint16_t height;
92 uint8_t img_bpp;
93 uint8_t img_alpha_bpp;
94 uint8_t img_alpha_dir;
95
96 void *id_data;
97 size_t id_length;
98
99 void *cmap_data;
100 size_t cmap_length;
101
102 void *img_data;
103 size_t img_length;
104} tga_t;
105
106/** Decode Truevision TGA header
107 *
108 * @param[in] data Memory representation of TGA.
109 * @param[in] size Size of the representation (in bytes).
110 * @param[out] tga Decoded TGA.
111 *
112 * @return True on succesful decoding.
113 * @return False on failure.
114 *
115 */
116static bool decode_tga_header(void *data, size_t size, tga_t *tga)
117{
118 /* Header sanity check */
119 if (size < sizeof(tga_header_t))
120 return false;
121
122 tga_header_t *head = (tga_header_t *) data;
123
124 /* Image ID field */
125 tga->id_data = data + sizeof(tga_header_t);
126 tga->id_length = head->id_length;
127
128 if (size < sizeof(tga_header_t) + tga->id_length)
129 return false;
130
131 /* Color map type */
132 tga->cmap_type = head->cmap_type;
133
134 /* Image type */
135 tga->img_type = head->img_type;
136
137 /* Color map specification */
138 tga->cmap_first_entry = uint16_t_le2host(head->cmap_first_entry);
139 tga->cmap_entries = uint16_t_le2host(head->cmap_entries);
140 tga->cmap_bpp = head->cmap_bpp;
141 tga->cmap_data = tga->id_data + tga->id_length;
142 tga->cmap_length = ALIGN_UP(tga->cmap_entries * tga->cmap_bpp, 8) >> 3;
143
144 if (size < sizeof(tga_header_t) + tga->id_length +
145 tga->cmap_length)
146 return false;
147
148 /* Image specification */
149 tga->startx = uint16_t_le2host(head->startx);
150 tga->starty = uint16_t_le2host(head->starty);
151 tga->width = uint16_t_le2host(head->width);
152 tga->height = uint16_t_le2host(head->height);
153 tga->img_bpp = head->img_bpp;
154 tga->img_alpha_bpp = head->img_descr & 0x0f;
155 tga->img_alpha_dir = (head->img_descr & 0xf0) >> 4;
156 tga->img_data = tga->cmap_data + tga->cmap_length;
157
158 uint64_t length = (uint64_t) tga->width * tga->height * tga->img_bpp;
159 if (length & 0x7)
160 length += 8;
161 length >>= 3;
162
163 if (length > SIZE_MAX - sizeof(tga_header_t) - tga->id_length -
164 tga->cmap_length)
165 return false;
166
167 tga->img_length = length;
168
169 if (size < sizeof(tga_header_t) + tga->id_length +
170 tga->cmap_length + tga->img_length)
171 return false;
172
173 return true;
174}
175
176/** Decode Truevision TGA format
177 *
178 * Decode Truevision TGA format and create a surface
179 * from it. The supported variants of TGA are currently
180 * limited to uncompressed 24 bit true-color images without
181 * alpha channel.
182 *
183 * @param gc Graphic context
184 * @param data Memory representation of gzipped TGA.
185 * @param size Size of the representation (in bytes).
186 * @param rbitmap Place to store pointer to new bitmap
187 * @param rrect Place to store bitmap rectangle
188 *
189 * @return EOK un success or an error code
190 */
191errno_t decode_tga(gfx_context_t *gc, void *data, size_t size,
192 gfx_bitmap_t **rbitmap, gfx_rect_t *rrect)
193{
194 gfx_bitmap_params_t params;
195 gfx_bitmap_alloc_t alloc;
196 gfx_bitmap_t *bitmap = NULL;
197 pixelmap_t pixelmap;
198 errno_t rc;
199
200 tga_t tga;
201 if (!decode_tga_header(data, size, &tga))
202 return EINVAL;
203
204 /*
205 * Check for unsupported features.
206 */
207
208 switch (tga.cmap_type) {
209 case CMAP_NOT_PRESENT:
210 break;
211 default:
212 /* Unsupported */
213 return ENOTSUP;
214 }
215
216 switch (tga.img_type) {
217 case IMG_BGRA:
218 if (tga.img_bpp != 24)
219 return ENOTSUP;
220 break;
221 case IMG_GRAY:
222 if (tga.img_bpp != 8)
223 return ENOTSUP;
224 break;
225 default:
226 /* Unsupported */
227 return ENOTSUP;
228 }
229
230 if (tga.img_alpha_bpp != 0)
231 return ENOTSUP;
232
233 sysarg_t twidth = tga.startx + tga.width;
234 sysarg_t theight = tga.starty + tga.height;
235
236 gfx_bitmap_params_init(&params);
237 params.rect.p1.x = twidth;
238 params.rect.p1.y = theight;
239
240 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
241 if (rc != EOK)
242 return rc;
243
244 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
245 if (rc != EOK) {
246 gfx_bitmap_destroy(bitmap);
247 return rc;
248 }
249
250 pixelmap.width = twidth;
251 pixelmap.height = theight;
252 pixelmap.data = alloc.pixels;
253
254 /*
255 * TGA is encoded in a bottom-up manner, the true-color
256 * variant is in BGR 8:8:8 encoding.
257 */
258
259 switch (tga.img_type) {
260 case IMG_BGRA:
261 for (sysarg_t y = tga.starty; y < theight; y++) {
262 for (sysarg_t x = tga.startx; x < twidth; x++) {
263 size_t offset =
264 ((y - tga.starty) * tga.width + (x - tga.startx)) * 3;
265
266 pixel_t pixel =
267 bgr_888_2pixel(((uint8_t *) tga.img_data) + offset);
268 pixelmap_put_pixel(&pixelmap, x, theight - y - 1, pixel);
269 }
270 }
271 break;
272 case IMG_GRAY:
273 for (sysarg_t y = tga.starty; y < theight; y++) {
274 for (sysarg_t x = tga.startx; x < twidth; x++) {
275 size_t offset =
276 (y - tga.starty) * tga.width + (x - tga.startx);
277
278 pixel_t pixel =
279 gray_8_2pixel(((uint8_t *) tga.img_data) + offset);
280 pixelmap_put_pixel(&pixelmap, x, theight - y - 1, pixel);
281 }
282 }
283 break;
284 default:
285 break;
286 }
287
288 *rbitmap = bitmap;
289 *rrect = params.rect;
290 return EOK;
291}
292
293/** @}
294 */
Note: See TracBrowser for help on using the repository browser.