iPXE
pnm.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26/** @file
27 *
28 * Portable anymap format (PNM)
29 *
30 */
31
32#include <stdlib.h>
33#include <string.h>
34#include <errno.h>
35#include <ctype.h>
36#include <ipxe/image.h>
37#include <ipxe/pixbuf.h>
38#include <ipxe/pnm.h>
39
40/**
41 * Extract PNM ASCII value
42 *
43 * @v image PNM image
44 * @v pnm PNM context
45 * @ret value Value, or negative error
46 */
47static int pnm_ascii ( struct image *image, struct pnm_context *pnm ) {
48 char buf[ pnm->ascii_len + 1 /* NUL */ ];
49 char *endp;
50 char ch;
51 size_t len;
52 int value;
53 int in_comment = 0;
54
55 /* Skip any leading whitespace and comments */
56 for ( ; pnm->offset < image->len ; pnm->offset++ ) {
57 ch = *( ( ( const uint8_t * ) image->data ) + pnm->offset );
58 if ( in_comment ) {
59 if ( ch == '\n' )
60 in_comment = 0;
61 } else {
62 if ( ch == '#' ) {
63 in_comment = 1;
64 } else if ( ! isspace ( ch ) ) {
65 break;
66 }
67 }
68 }
69
70 /* Fail if no value is present */
71 len = ( image->len - pnm->offset );
72 if ( len == 0 ) {
73 DBGC ( image, "PNM %s ran out of ASCII data\n", image->name );
74 return -EINVAL;
75 }
76
77 /* Copy ASCII value to buffer and ensure string is NUL-terminated */
78 if ( len > ( sizeof ( buf ) - 1 /* NUL */ ) )
79 len = ( sizeof ( buf ) - 1 /* NUL */ );
80 memcpy ( buf, ( image->data + pnm->offset ), len );
81 buf[len] = '\0';
82
83 /* Parse value and update offset */
84 value = strtoul ( buf, &endp, 0 );
85 pnm->offset += ( endp - buf );
86
87 /* Check and skip terminating whitespace character, if present */
88 if ( ( pnm->offset != image->len ) && ( *endp != '\0' ) ) {
89 if ( ! isspace ( *endp ) ) {
90 DBGC ( image, "PNM %s invalid ASCII integer\n",
91 image->name );
92 return -EINVAL;
93 }
94 pnm->offset++;
95 }
96
97 return value;
98}
99
100/**
101 * Extract PNM binary value
102 *
103 * @v image PNM image
104 * @v pnm PNM context
105 * @ret value Value, or negative error
106 */
107static int pnm_binary ( struct image *image, struct pnm_context *pnm ) {
108 const uint8_t *value;
109
110 /* Sanity check */
111 if ( pnm->offset == image->len ) {
112 DBGC ( image, "PNM %s ran out of binary data\n",
113 image->name );
114 return -EINVAL;
115 }
116
117 /* Extract value */
118 value = ( image->data + pnm->offset++ );
119 return *value;
120}
121
122/**
123 * Scale PNM scalar value
124 *
125 * @v image PNM image
126 * @v pnm PNM context
127 * @v value Raw value
128 * @ret value Scaled value (in range 0-255)
129 */
130static int pnm_scale ( struct image *image, struct pnm_context *pnm,
131 unsigned int value ) {
132
133 if ( value > pnm->max ) {
134 DBGC ( image, "PNM %s has out-of-range value %d (max %d)\n",
135 image->name, value, pnm->max );
136 return -EINVAL;
137 }
138 return ( ( 255 * value ) / pnm->max );
139}
140
141/**
142 * Convert PNM bitmap composite value to RGB
143 *
144 * @v composite Composite value
145 * @v index Pixel index within this composite value
146 * @ret rgb 24-bit RGB value
147 */
148static uint32_t pnm_bitmap ( uint32_t composite, unsigned int index ) {
149
150 /* Composite value is an 8-bit bitmask */
151 return ( ( ( composite << index ) & 0x80 ) ? 0x000000 : 0xffffff );
152}
153
154/**
155 * Convert PNM greymap composite value to RGB
156 *
157 * @v composite Composite value
158 * @v index Pixel index within this composite value
159 * @ret rgb 24-bit RGB value
160 */
161static uint32_t pnm_greymap ( uint32_t composite, unsigned int index __unused ){
162
163 /* Composite value is an 8-bit greyscale value */
164 return ( ( composite << 16 ) | ( composite << 8 ) | composite );
165}
166
167/**
168 * Convert PNM pixmap composite value to RGB
169 *
170 * @v composite Composite value
171 * @v index Pixel index within this composite value
172 * @ret rgb 24-bit RGB value
173 */
174static uint32_t pnm_pixmap ( uint32_t composite, unsigned int index __unused ) {
175
176 /* Composite value is already an RGB value */
177 return composite;
178}
179
180/**
181 * Extract PNM pixel data
182 *
183 * @v image PNM image
184 * @v pnm PNM context
185 * @v pixbuf Pixel buffer
186 * @ret rc Return status code
187 */
188static int pnm_data ( struct image *image, struct pnm_context *pnm,
189 struct pixel_buffer *pixbuf ) {
190 struct pnm_type *type = pnm->type;
191 unsigned int pixels = pixbuf->pixels;
192 unsigned int index = 0;
193 unsigned int xpos = 0;
194 int scalar;
195 uint32_t composite;
196 unsigned int i;
197
198 /* Fill pixel buffer */
199 while ( index < pixels ) {
200
201 /* Extract a scaled composite scalar value from the file */
202 composite = 0;
203 for ( i = 0 ; i < type->depth ; i++ ) {
204 scalar = type->scalar ( image, pnm );
205 if ( scalar < 0 )
206 return scalar;
207 scalar = pnm_scale ( image, pnm, scalar );
208 if ( scalar < 0 )
209 return scalar;
210 composite = ( ( composite << 8 ) | scalar );
211 }
212
213 /* Extract 24-bit RGB values from composite value */
214 for ( i = 0 ; i < type->packing ; i++ ) {
215 if ( index >= pixels ) {
216 DBGC ( image, "PNM %s has too many pixels\n",
217 image->name );
218 return -EINVAL;
219 }
220 pixbuf->data[index++] = type->rgb ( composite, i );
221 if ( ++xpos == pixbuf->width ) {
222 xpos = 0;
223 break;
224 }
225 }
226 }
227
228 return 0;
229}
230
231/** PNM image types */
232static struct pnm_type pnm_types[] = {
233 {
234 .type = '1',
235 .depth = 1,
236 .packing = 1,
237 .flags = PNM_BITMAP,
238 .scalar = pnm_ascii,
239 .rgb = pnm_bitmap,
240 },
241 {
242 .type = '2',
243 .depth = 1,
244 .packing = 1,
245 .scalar = pnm_ascii,
246 .rgb = pnm_greymap,
247 },
248 {
249 .type = '3',
250 .depth = 3,
251 .packing = 1,
252 .scalar = pnm_ascii,
253 .rgb = pnm_pixmap,
254 },
255 {
256 .type = '4',
257 .depth = 1,
258 .packing = 8,
259 .flags = PNM_BITMAP,
260 .scalar = pnm_binary,
261 .rgb = pnm_bitmap,
262 },
263 {
264 .type = '5',
265 .depth = 1,
266 .packing = 1,
267 .scalar = pnm_binary,
268 .rgb = pnm_greymap,
269 },
270 {
271 .type = '6',
272 .depth = 3,
273 .packing = 1,
274 .scalar = pnm_binary,
275 .rgb = pnm_pixmap,
276 },
277};
278
279/**
280 * Determine PNM image type
281 *
282 * @v image PNM image
283 * @ret type PNM image type, or NULL if not found
284 */
285static struct pnm_type * pnm_type ( struct image *image ) {
286 const struct pnm_signature *signature;
287 struct pnm_type *type;
288 unsigned int i;
289
290 /* Extract signature */
291 assert ( image->len >= sizeof ( *signature ) );
293
294 /* Check for supported types */
295 for ( i = 0 ; i < ( sizeof ( pnm_types ) /
296 sizeof ( pnm_types[0] ) ) ; i++ ) {
297 type = &pnm_types[i];
298 if ( type->type == signature->type )
299 return type;
300 }
301 return NULL;
302}
303
304/**
305 * Convert PNM image to pixel buffer
306 *
307 * @v image PNM image
308 * @v pixbuf Pixel buffer to fill in
309 * @ret rc Return status code
310 */
311static int pnm_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) {
312 struct pnm_context pnm;
313 int width;
314 int height;
315 int max;
316 int rc;
317
318 /* Initialise PNM context */
319 pnm.type = pnm_type ( image );
320 if ( ! pnm.type ) {
321 rc = -ENOTSUP;
322 goto err_type;
323 }
324 pnm.offset = sizeof ( struct pnm_signature );
326
327 /* Extract width */
328 if ( ( width = pnm_ascii ( image, &pnm ) ) < 0 ) {
329 rc = width;
330 goto err_width;
331 }
332
333 /* Extract height */
334 if ( ( height = pnm_ascii ( image, &pnm ) ) < 0 ) {
335 rc = height;
336 goto err_height;
337 }
338
339 /* Extract maximum scalar value, if not predefined */
340 if ( pnm.type->flags & PNM_BITMAP ) {
341 pnm.max = ( ( 1 << pnm.type->packing ) - 1 );
342 pnm.ascii_len = 1;
343 } else {
344 if ( ( max = pnm_ascii ( image, &pnm ) ) < 0 ) {
345 rc = max;
346 goto err_max;
347 }
348 pnm.max = max;
349 }
350 if ( pnm.max == 0 ) {
351 DBGC ( image, "PNM %s has invalid maximum value 0\n",
352 image->name );
353 rc = -EINVAL;
354 goto err_max;
355 }
356 DBGC ( image, "PNM %s is type %c width %d height %d max %d\n",
357 image->name, pnm.type->type, width, height, pnm.max );
358
359 /* Allocate pixel buffer */
360 *pixbuf = alloc_pixbuf ( width, height );
361 if ( ! *pixbuf ) {
362 rc = -ENOMEM;
363 goto err_alloc_pixbuf;
364 }
365
366 /* Extract pixel data */
367 if ( ( rc = pnm_data ( image, &pnm, *pixbuf ) ) != 0 )
368 goto err_data;
369
370 return 0;
371
372 err_data:
373 pixbuf_put ( *pixbuf );
374 err_alloc_pixbuf:
375 err_max:
376 err_height:
377 err_width:
378 err_type:
379 return rc;
380}
381
382/**
383 * Probe PNM image
384 *
385 * @v image PNM image
386 * @ret rc Return status code
387 */
388static int pnm_probe ( struct image *image ) {
389 const struct pnm_signature *signature;
390
391 /* Sanity check */
392 if ( image->len < sizeof ( *signature ) ) {
393 DBGC ( image, "PNM %s is too short\n", image->name );
394 return -ENOEXEC;
395 }
396
397 /* Check signature */
399 if ( ! ( ( signature->magic == PNM_MAGIC ) &&
400 ( isdigit ( signature->type ) ) &&
401 ( isspace ( signature->space ) ) ) ) {
402 DBGC ( image, "PNM %s has invalid signature\n", image->name );
403 return -ENOEXEC;
404 }
405 DBGC ( image, "PNM %s is type %c\n", image->name, signature->type );
406
407 return 0;
408}
409
410/** PNM image type */
411struct image_type pnm_image_type __image_type ( PROBE_NORMAL ) = {
412 .name = "PNM",
413 .probe = pnm_probe,
414 .pixbuf = pnm_pixbuf,
415};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
u8 signature
CPU signature.
Definition CIB_PRM.h:7
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
long index
Definition bigint.h:65
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define max(x, y)
Definition ath.h:41
int isspace(int character)
Check to see if character is a space.
Definition ctype.c:42
Character types.
static int isdigit(int character)
Check if character is a decimal digit.
Definition ctype.h:30
ring len
Length.
Definition dwmac.h:226
uint32_t type
Operating system type.
Definition ena.h:1
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOEXEC
Exec format error.
Definition errno.h:520
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
Executable images.
#define PROBE_NORMAL
Normal image probe priority.
Definition image.h:156
#define __image_type(probe_order)
An executable image type.
Definition image.h:170
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
struct pixel_buffer * alloc_pixbuf(unsigned int width, unsigned int height)
Allocate pixel buffer.
Definition pixbuf.c:60
Pixel buffer.
static int pnm_ascii(struct image *image, struct pnm_context *pnm)
Extract PNM ASCII value.
Definition pnm.c:47
static struct pnm_type * pnm_type(struct image *image)
Determine PNM image type.
Definition pnm.c:285
static int pnm_scale(struct image *image, struct pnm_context *pnm, unsigned int value)
Scale PNM scalar value.
Definition pnm.c:130
static int pnm_probe(struct image *image)
Probe PNM image.
Definition pnm.c:388
static struct pnm_type pnm_types[]
PNM image types.
Definition pnm.c:232
static int pnm_pixbuf(struct image *image, struct pixel_buffer **pixbuf)
Convert PNM image to pixel buffer.
Definition pnm.c:311
static uint32_t pnm_pixmap(uint32_t composite, unsigned int index __unused)
Convert PNM pixmap composite value to RGB.
Definition pnm.c:174
static uint32_t pnm_greymap(uint32_t composite, unsigned int index __unused)
Convert PNM greymap composite value to RGB.
Definition pnm.c:161
static int pnm_data(struct image *image, struct pnm_context *pnm, struct pixel_buffer *pixbuf)
Extract PNM pixel data.
Definition pnm.c:188
static int pnm_binary(struct image *image, struct pnm_context *pnm)
Extract PNM binary value.
Definition pnm.c:107
static uint32_t pnm_bitmap(uint32_t composite, unsigned int index)
Convert PNM bitmap composite value to RGB.
Definition pnm.c:148
Portable anymap format (PNM)
#define PNM_ASCII_LEN
Default maximum length of ASCII values.
Definition pnm.h:41
@ PNM_BITMAP
Bitmap format.
Definition pnm.h:80
#define PNM_MAGIC
PNM magic byte.
Definition pnm.h:26
uint8_t ch
Definition registers.h:1
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition string.c:485
An executable image type.
Definition image.h:95
An executable image.
Definition image.h:24
const void * data
Read-only data.
Definition image.h:51
char * name
Name.
Definition image.h:38
size_t len
Length of raw file image.
Definition image.h:56
A pixel buffer.
Definition pixbuf.h:17
unsigned int pixels
Total number of pixels.
Definition pixbuf.h:27
unsigned int width
Width.
Definition pixbuf.h:21
uint32_t * data
32-bit (8:8:8:8) xRGB pixel data, in host-endian order
Definition pixbuf.h:25
PNM context.
Definition pnm.h:29
unsigned int max
Maximum pixel value.
Definition pnm.h:37
size_t ascii_len
Maximum length of ASCII values.
Definition pnm.h:35
struct pnm_type * type
PNM type.
Definition pnm.h:31
size_t offset
Current byte offset.
Definition pnm.h:33
PNM signature.
Definition pnm.h:16
PNM type.
Definition pnm.h:44
int(* scalar)(struct image *image, struct pnm_context *pnm)
Extract scalar value.
Definition pnm.h:59
uint8_t flags
Flags.
Definition pnm.h:52