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 
24 FILE_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  */
47 static 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  */
107 static 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  */
130 static 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  */
148 static 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  */
161 static 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  */
174 static 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  */
188 static 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 */
232 static 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  */
285 static 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 ) );
292  signature = image->data;
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  */
311 static 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 );
325  pnm.ascii_len = PNM_ASCII_LEN;
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  */
388 static 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 */
398  signature = image->data;
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 */
411 struct image_type pnm_image_type __image_type ( PROBE_NORMAL ) = {
412  .name = "PNM",
413  .probe = pnm_probe,
414  .pixbuf = pnm_pixbuf,
415 };
#define EINVAL
Invalid argument.
Definition: errno.h:428
static int pnm_probe(struct image *image)
Probe PNM image.
Definition: pnm.c:388
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
struct pixel_buffer * alloc_pixbuf(unsigned int width, unsigned int height)
Allocate pixel buffer.
Definition: pixbuf.c:59
int(* scalar)(struct image *image, struct pnm_context *pnm)
Extract scalar value.
Definition: pnm.h:59
#define max(x, y)
Definition: ath.h:40
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:484
uint8_t flags
Flags.
Definition: pnm.h:52
Error codes.
const void * data
Read-only data.
Definition: image.h:50
static int pnm_binary(struct image *image, struct pnm_context *pnm)
Extract PNM binary value.
Definition: pnm.c:107
#define ENOEXEC
Exec format error.
Definition: errno.h:519
#define PNM_ASCII_LEN
Default maximum length of ASCII values.
Definition: pnm.h:41
uint32_t type
Operating system type.
Definition: ena.h:12
#define DBGC(...)
Definition: compiler.h:505
struct image_type pnm_image_type __image_type(PROBE_NORMAL)
PNM image type.
An executable image type.
Definition: image.h:94
long index
Definition: bigint.h:62
static struct pnm_type * pnm_type(struct image *image)
Determine PNM image type.
Definition: pnm.c:285
#define PROBE_NORMAL
Normal image probe priority.
Definition: image.h:155
An executable image.
Definition: image.h:23
Pixel buffer.
unsigned int pixels
Total number of pixels.
Definition: pixbuf.h:26
Character types.
static struct pnm_type pnm_types[]
PNM image types.
Definition: pnm.c:232
unsigned int max
Maximum pixel value.
Definition: pnm.h:37
char * name
Name of this image type.
Definition: image.h:96
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
uint8_t ch
Definition: registers.h:83
static int isdigit(int character)
Check if character is a decimal digit.
Definition: ctype.h:29
#define ENOMEM
Not enough space.
Definition: errno.h:534
void * memcpy(void *dest, const void *src, size_t len) __nonnull
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
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Executable images.
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
ring len
Length.
Definition: dwmac.h:231
uint32_t * data
32-bit (8:8:8:8) xRGB pixel data, in host-endian order
Definition: pixbuf.h:24
static int pnm_ascii(struct image *image, struct pnm_context *pnm)
Extract PNM ASCII value.
Definition: pnm.c:47
size_t ascii_len
Maximum length of ASCII values.
Definition: pnm.h:35
static uint32_t pnm_bitmap(uint32_t composite, unsigned int index)
Convert PNM bitmap composite value to RGB.
Definition: pnm.c:148
size_t len
Length of raw file image.
Definition: image.h:55
uint8_t packing
Number of pixels per composite value.
Definition: pnm.h:50
A pixel buffer.
Definition: pixbuf.h:16
int isspace(int character)
Check to see if character is a space.
Definition: ctype.c:41
unsigned char uint8_t
Definition: stdint.h:10
PNM type.
Definition: pnm.h:44
unsigned int uint32_t
Definition: stdint.h:12
struct pnm_type * type
PNM type.
Definition: pnm.h:31
PNM signature.
Definition: pnm.h:16
static int pnm_scale(struct image *image, struct pnm_context *pnm, unsigned int value)
Scale PNM scalar value.
Definition: pnm.c:130
Portable anymap format (PNM)
char type
PNM type.
Definition: pnm.h:46
int(* pixbuf)(struct image *image, struct pixel_buffer **pixbuf)
Create pixel buffer from image.
Definition: image.h:120
Bitmap format.
Definition: pnm.h:80
#define PNM_MAGIC
PNM magic byte.
Definition: pnm.h:26
static uint32_t pnm_greymap(uint32_t composite, unsigned int index __unused)
Convert PNM greymap composite value to RGB.
Definition: pnm.c:161
u8 signature
CPU signature.
Definition: CIB_PRM.h:35
char * name
Name.
Definition: image.h:37
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
size_t offset
Current byte offset.
Definition: pnm.h:33
PNM context.
Definition: pnm.h:29
unsigned int width
Width.
Definition: pixbuf.h:20
static int pnm_data(struct image *image, struct pnm_context *pnm, struct pixel_buffer *pixbuf)
Extract PNM pixel data.
Definition: pnm.c:188