Magellan Linux

Annotation of /trunk/busybox/patches/busybox-1.20.2-fbsplash-tykef-1.0.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1837 - (hide annotations) (download)
Fri Jul 13 09:44:25 2012 UTC (11 years, 11 months ago) by niro
File size: 49226 byte(s)
-rediffed against busybox-1.20.2
1 niro 1837 diff -Naur busybox-1.20.2/miscutils/Config.src busybox-1.20.2-magellan/miscutils/Config.src
2     --- busybox-1.20.2/miscutils/Config.src 2012-06-26 15:35:45.000000000 +0200
3     +++ busybox-1.20.2-magellan/miscutils/Config.src 2012-07-13 12:32:32.086982678 +0200
4     @@ -276,7 +276,8 @@
5     select PLATFORM_LINUX
6     help
7     Shows splash image and progress bar on framebuffer device.
8     - Can be used during boot phase of an embedded device. ~2kb.
9     + Can be used during boot phase of an embedded device.
10     + Code size is 2..7kb depends on enabled features.
11     Usage:
12     - use kernel option 'vga=xxx' or otherwise enable fb device.
13     - put somewhere fbsplash.cfg file and an image in .ppm format.
14     @@ -292,6 +293,44 @@
15     "NN" (ASCII decimal number) - percentage to show on progress bar
16     "exit" - well you guessed it
17    
18     +config FEATURE_FBSPLASH_8BPP
19     + bool "support 8bit depth with color mapping"
20     + depends on FBSPLASH
21     + help
22     + support for low color framebuffer that's need color mapping ~350 b
23     +
24     +config FEATURE_FBSPLASH_SPRITES
25     + bool "Render icons and animations"
26     + default n
27     + depends on FBSPLASH
28     + help
29     + This option adds the ability to display icons on the
30     + image displayed by the fbsplash applet. ~1.5kb.
31     + - command for fifo:
32     + "load:x:y:filename" - load images from file
33     + each sprite is one square area when image is wider than higher
34     + before load new sprite set, old area is cleared.
35     + "sprite:n" - show one sprite - sprite 0 is background.
36     + "anime:n:m:t" - anime from sprite n up/down to sprite m
37     + time between sprites is in t * 100 msec.
38     +
39     +config FEATURE_FBSPLASH_TEXT
40     + bool "text rendering"
41     + default n
42     + depends on FBSPLASH
43     + help
44     + This option adds the ability to print text messages on the
45     + image displayed by the fbsplash applet. ~2kb.
46     + - command for fifo:
47     + "write:string to print" - print the string after the word "write:"
48     +
49     +config FEATURE_FBSPLASH_FONTLOAD
50     + bool "font loading"
51     + depends on FEATURE_FBSPLASH_TEXT
52     + help
53     + The font is loaded from a standard console font file.
54     + Supported are psf v1.x and psf v2.0 files including mapping ~1kb.
55     +
56     config FLASHCP
57     bool "flashcp"
58     default n # doesn't build on Ubuntu 8.04
59     diff -Naur busybox-1.20.2/miscutils/fbsplash.c busybox-1.20.2-magellan/miscutils/fbsplash.c
60     --- busybox-1.20.2/miscutils/fbsplash.c 2012-06-26 15:35:45.000000000 +0200
61     +++ busybox-1.20.2-magellan/miscutils/fbsplash.c 2012-07-13 13:16:08.328982661 +0200
62     @@ -1,6 +1,7 @@
63     /* vi: set sw=4 ts=4: */
64     /*
65     * Copyright (C) 2008 Michele Sanges <michele.sanges@gmail.com>
66     + * Copyright (C) 2009 Jiri Gabriel <george.gabriel@seznam.cz>
67     *
68     * Licensed under GPLv2 or later, see file LICENSE in this source tree.
69     *
70     @@ -10,19 +11,51 @@
71     * - run applet: $ setsid fbsplash [params] &
72     * -c: hide cursor
73     * -d /dev/fbN: framebuffer device (if not /dev/fb0)
74     - * -s path_to_image_file (can be "-" for stdin)
75     + * -s path_to_image_file - ppm or ppm.gz or ppm.bz2
76     * -i path_to_cfg_file
77     * -f path_to_fifo (can be "-" for stdin)
78     + * -m font map file - standard psf file (v1 and v2) can be with unumap
79     * - if you want to run it only in presence of a kernel parameter
80     * (for example fbsplash=on), use:
81     * grep -q "fbsplash=on" </proc/cmdline && setsid fbsplash [params]
82     * - commands for fifo:
83     * "NN" (ASCII decimal number) - percentage to show on progress bar.
84     - * "exit" (or just close fifo) - well you guessed it.
85     + * if number is smaller than zero progress bar is filled from left.
86     + * "write:string to print" - print the string after the word "write:"
87     + * "exit" - well you guessed it.
88     + */
89     +
90     +/*
91     + * enhancements:
92     + * - framebuffer can be in depth 8,15,16,24,32 PSEUDOCOLR,TRUECOLOR
93     + * not only 16
94     + * - image file cannot be stdin
95     + * - bugfix: if virtual size is bigger than visual resolution
96     + * - progress bar can be dscending for shutdown (-1..-100)
97     + * - progress bar is from background picture + color in cfg - only colorize.
98     + * - bouncing bar - command "bounce" and at start.
99     + * - smaller image is shown centered on screen cfg positions recalc on demand.
100     + * - without text rendering and sprites grow size is only 800b.
101     + * text rendering:
102     + * - font is standard psf console font
103     + * - if font not specified or not compiled in fontload function
104     + * font is used from kernel using KDFONTOP / GIO_FONTX / GIO_FONT
105     + * - colorize text render by \033[30m .. \033[37m,\033[1;30 .. \033[1;37m
106     + * sprites:
107     + * - animated sprites load by fifo command "load:x:y:filename".
108     + * File is ppm format may be gzipped/bzipped or raw.
109     + * Frame/Icon is always square. Width of each Frame is image height.
110     + * Frame number 0 is always created for save background.
111     + * Transparent color is in ppm file is stored as #FF00FF - purple.
112     + * Show frame by pipe command "sprite:n" where n is frame number.
113     + * Run animated sequence by "anime:n:m:t" where
114     + * n is first frame m is last frame, t is time between displaying
115     + * frames in 0.1sec. n can be bigger than m for reverse order in anime.
116     */
117    
118     //usage:#define fbsplash_trivial_usage
119     //usage: "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]"
120     +//usage: IF_FEATURE_FBSPLASH_FONTLOAD("[-m FONTMAPFILE]")
121     //usage:#define fbsplash_full_usage "\n\n"
122     //usage: " -s Image"
123     //usage: "\n -c Hide cursor"
124     @@ -30,31 +63,157 @@
125     //usage: "\n -i Config file (var=value):"
126     //usage: "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT"
127     //usage: "\n BAR_R,BAR_G,BAR_B"
128     +//usage: "\n TEXT_LEFT,TEXT_TOP,TEXT_R,TEXT_G,TEXT_B,TEXT_SIZE"
129     //usage: "\n -f Control pipe (else exit after drawing image)"
130     //usage: "\n commands: 'NN' (% for progress bar) or 'exit'"
131     +//usage: IF_FEATURE_FBSPLASH_FONTLOAD(
132     +//usage: "\n -m Font map file"
133     +//usage: "\n commands: 'NN' (% for progress bar), 'write:string to print' or 'exit'"
134     +//usage: )
135    
136     #include "libbb.h"
137     +#if BB_BIG_ENDIAN
138     +#warning "fbsplash work only on little endian architecures. Sorry"
139     +int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
140     +int fbsplash_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) {
141     + bb_error_msg_and_die("fbsplash not work on big endian architectures.");
142     + return 1;
143     +}
144     +
145     +#else
146     #include <linux/fb.h>
147    
148     +#if ENABLE_FEATURE_FBSPLASH_TEXT
149     +#include <linux/kd.h>
150     +
151     +/* if you have fonts with sequences can turn this to 1 i not find any font with this feature
152     + ~510 bytes of code */
153     +#define ENABLE_FEATURE_FBSPLASH_PSFSEQS 0
154     +
155     +/* if you not use text colors and need optimize size - disable text colors
156     + ~250 bytes of code */
157     +#define ENABLE_FEATURE_FBSPLASH_TEXT_COLORS 1
158     +
159     +#if !defined(GIO_UNIMAP)
160     +struct unipair {
161     + unsigned short unicode;
162     + unsigned short fontpos;
163     +} __atribute__ ((packed));
164     +
165     +struct unimapdesc {
166     + unsigned short entry_ct;
167     + struct unipair *entries;
168     +} __atribute__ ((packed));
169     +#endif
170     +
171     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
172     +
173     +enum { // uint16
174     + PSF1_MAGIC = 0x0436,
175     + PSF1_SEPARATOR = 0xFFFF,
176     + PSF1_STARTSEQ = 0xFFFE
177     +};
178     +
179     +enum { // uint32
180     + PSF2_MAGIC = 0x864ab572,
181     + PSF2_HAS_UNICODE_TABLE = 0x01, /* bits used in flags */
182     + PSF2_MAXVERSION = 0 /* max version recognized so far */
183     +};
184     +
185     +enum { // uint8
186     + PSF1_MODE512 = 0x01,
187     + PSF1_MODEHASTAB = 0x02,
188     + PSF1_MODEHASSEQ = 0x04,
189     + PSF1_MAXMODE = 0x05,
190     + PSF2_STARTSEQ = 0xFE,
191     + PSF2_SEPARATOR = 0xFF
192     +};
193     +
194     +struct psf1_header {
195     + uint16_t magic; /* Magic number */
196     + uint8_t mode; /* PSF font mode */
197     + uint8_t charsize; /* Character size */
198     +} __attribute__ ((packed));
199     +
200     +struct psf2_header {
201     + uint32_t magic;
202     + uint32_t version;
203     + uint32_t headersize; /* offset of bitmaps in file */
204     + uint32_t flags;
205     + uint32_t length; /* number of glyphs */
206     + uint32_t charsize; /* number of bytes for each character */
207     + uint32_t height, width; /* max dimensions of glyphs */
208     + /* charsize = height * ((width + 7) / 8) */
209     +} __attribute__ ((packed));
210     +
211     +#endif // FONTLOAD
212     +struct fbfont {
213     + uint8_t *mem1;
214     + uint8_t *glyphs;
215     + struct unimapdesc ud;
216     + int height;
217     + int width;
218     + int glyphcount;
219     + int charsize;
220     + int rowbytes;
221     +};
222     +
223     +#endif
224     +
225     +
226     /* If you want logging messages on /tmp/fbsplash.log... */
227     #define DEBUG 0
228    
229     +
230     +typedef uint32_t RGB;
231     +
232     +struct sprite {
233     + int w,h,bw; // width height in pixels, width in bytes
234     + uint8_t pixbuf[0];
235     +};
236     +
237     +struct ppmfile {
238     + int fd;
239     + int sizx,sizy;
240     + int bufhead,buftail;
241     + uint8_t buf[0]; // buf for entire pixels row
242     +};
243     +
244     struct globals {
245     #if DEBUG
246     bool bdebug_messages; // enable/disable logging
247     FILE *logfile_fd; // log file
248     #endif
249     - unsigned char *addr; // pointer to framebuffer memory
250     - unsigned ns[7]; // n-parameters
251     + unsigned char *addr; // pointer to visible framebuffer memory
252     + unsigned char *mapaddr; // pointer to framebuffer memory
253     +#if ENABLE_FEATURE_FBSPLASH_TEXT
254     + #define FBCFGVALS 13
255     +#else
256     + #define FBCFGVALS 7
257     +#endif
258     + unsigned ns[FBCFGVALS]; // n-parameters
259     const char *image_filename;
260     struct fb_var_screeninfo scr_var;
261     struct fb_fix_screeninfo scr_fix;
262     - unsigned bytes_per_pixel;
263     + int bytes_per_pixel,x0,y0; // offset for centering
264     + struct sprite *spb1,*spb2;
265     +#if ENABLE_FEATURE_FBSPLASH_TEXT
266     + struct fbfont *font;
267     + struct sprite *spt;
268     + uint8_t *unknown_glyph;
269     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
270     + uint8_t combglyph[4*32]; /* max width=32 max height=32 */
271     +#endif
272     +#endif
273     };
274     +
275     #define G (*ptr_to_globals)
276     #define INIT_G() do { \
277     SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
278     } while (0)
279     +#if ENABLE_FEATURE_FBSPLASH_TEXT
280     + #define GF (*(ptr_to_globals->font))
281     +#endif
282    
283     #define nbar_width ns[0] // progress bar width
284     #define nbar_height ns[1] // progress bar height
285     @@ -63,6 +222,75 @@
286     #define nbar_colr ns[4] // progress bar color red component
287     #define nbar_colg ns[5] // progress bar color green component
288     #define nbar_colb ns[6] // progress bar color blue component
289     +#define text_posx ns[7] // text horizontal position
290     +#define text_posy ns[8] // text vertical position
291     +#define text_colr ns[9] // text color red component
292     +#define text_colg ns[10] // text color green component
293     +#define text_colb ns[11] // text color blue component
294     +#define text_size ns[12] // text size (1 to 4)
295     +
296     +/**
297     + * A function to compute pixel value
298     + */
299     +static RGB FAST_FUNC makecol(uint16_t r, uint16_t g, uint16_t b) {
300     + if (r > 255) r = 255;
301     + if (g > 255) g = 255;
302     + if (b > 255) b = 255;
303     +#if ENABLE_FEATURE_FBSPLASH_8BPP
304     + if (G.bytes_per_pixel == 1) {
305     + // mymap is 6*8*5 = 240 values on offset 16
306     + // (r/42.6666) + (g/32) + (b/51.2)
307     + return 16 + (((r << 8) + r) / 13107) * 40 +
308     + (((g << 8) + g) / 9362) * 5 +
309     + (((b << 8) + b) / 16383);
310     + }
311     +#endif
312     + return ((r >> (8 - G.scr_var.red.length )) << G.scr_var.red.offset) |
313     + ((g >> (8 - G.scr_var.green.length)) << G.scr_var.green.offset) |
314     + ((b >> (8 - G.scr_var.blue.length )) << G.scr_var.blue.offset);
315     +}
316     +
317     +/*
318     + * A function to put the pixel row
319     + */
320     +static void fb_putpixrow(int x, int y, int w, uint8_t *rgb) {
321     + uint8_t *a;
322     + int realw;
323     + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres) return;
324     + a = G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x;
325     + realw = ((x + w) < G.scr_var.xres ? w : G.scr_var.xres - x) * G.bytes_per_pixel;
326     + memcpy(a,rgb,realw);
327     + return;
328     +}
329     +
330     +/*
331     + * A function to put the sprite to position or fill sprite from videoram
332     + */
333     +static void fb_sprite(int x, int y, int x0, int width, struct sprite *s, int direction) {
334     + uint8_t *a,*p;
335     + int realw,iy;
336     +
337     + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres ||
338     + x0 >= s->w || x0 < 0 || width > (s->w - x0)) {
339     + return;
340     + }
341     + realw = ((x + width) < G.scr_var.xres ? width : (G.scr_var.xres - x)) * G.bytes_per_pixel;
342     + a = G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x;
343     + p = &(s->pixbuf[x0 * G.bytes_per_pixel]);
344     + for (iy = 0; iy < s->h; iy++) {
345     + if ((iy + y) > G.scr_var.yres) break;
346     + if (direction == 1) {
347     + memcpy(p,a,realw);
348     + } else {
349     + memcpy(a,p,realw);
350     + }
351     + a += G.scr_fix.line_length;
352     + p += s->bw;
353     + }
354     + return;
355     +}
356     +#define fb_putsprite(x,y,s) fb_sprite(x,y,0,s->w,s,0)
357     +#define fb_getsprite(x,y,s) fb_sprite(x,y,0,s->w,s,1)
358    
359     #if DEBUG
360     #define DEBUG_MESSAGE(strMessage, args...) \
361     @@ -124,32 +352,60 @@
362     xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var);
363     xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix);
364    
365     - switch (G.scr_var.bits_per_pixel) {
366     - case 8:
367     - fb_setpal(fbfd);
368     - break;
369     -
370     - case 16:
371     - case 24:
372     - case 32:
373     - break;
374     -
375     - default:
376     - bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel);
377     - break;
378     +#if ENABLE_FEATURE_FBSPLASH_8BPP
379     + if ((G.scr_var.bits_per_pixel < 8) ||
380     + (G.scr_fix.type != FB_TYPE_PACKED_PIXELS)) {
381     + bb_error_msg_and_die("only 8,15,16,24 and 32 bpp is supported");
382     }
383     -
384     - G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3;
385     +#else
386     + if ((G.scr_var.bits_per_pixel < 15) ||
387     + (G.scr_fix.type != FB_TYPE_PACKED_PIXELS)) {
388     + bb_error_msg_and_die("only 15,16,24 and 32 bpp is supported");
389     + }
390     +#endif
391     + switch (G.scr_fix.visual) {
392     +#if ENABLE_FEATURE_FBSPLASH_8BPP
393     + case FB_VISUAL_PSEUDOCOLOR: do {
394     + uint8_t *cmem;
395     + struct fb_cmap *cmap;
396     + int r,g,b,i;
397     + cmem = xzalloc(sizeof(struct fb_cmap) + sizeof(uint16_t) * 3 * 256);
398     + cmap = (struct fb_cmap *)cmem;
399     + cmap->len = 256;
400     + cmap->red = (uint16_t *)&(cmem[sizeof(struct fb_cmap)]);
401     + cmap->green = &(cmap->red[256]);
402     + cmap->blue = &(cmap->green[256]);
403     + xioctl(fbfd, FBIOGETCMAP, cmem); // read original palette
404     + // fill cmap with my 6x8x5 pallette
405     + for (r = 0,i = 16; r < 6; r++) {
406     + for (g = 0; g < 8; g++) {
407     + for (b = 0; b < 5; b++, i++) {
408     + cmap->red[i] = r * 13107;
409     + cmap->green[i] = g * 9362;
410     + cmap->blue[i] = b * 16383;
411     + }
412     + }
413     + }
414     + xioctl(fbfd, FBIOPUTCMAP, cmem);
415     + free(cmem);
416     + } while(0);
417     +#endif
418     + case FB_VISUAL_TRUECOLOR:
419     + break;
420     + default:
421     + bb_error_msg_and_die("only TrueColor modes is supported");
422     + }
423     +
424     + G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) / 8;
425    
426     // map the device in memory
427     - G.addr = mmap(NULL,
428     - G.scr_var.yres * G.scr_fix.line_length,
429     + G.mapaddr = mmap(NULL,
430     + G.scr_var.yres_virtual * G.scr_fix.line_length ,
431     PROT_WRITE, MAP_SHARED, fbfd, 0);
432     - if (G.addr == MAP_FAILED)
433     + if (G.mapaddr == MAP_FAILED)
434     bb_perror_msg_and_die("mmap");
435     -
436     // point to the start of the visible screen
437     - G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * G.bytes_per_pixel;
438     + G.addr = G.mapaddr + G.scr_var.yoffset * G.scr_fix.line_length;
439     close(fbfd);
440     }
441    
442     @@ -199,210 +455,788 @@
443    
444    
445     /**
446     - * Draw hollow rectangle on framebuffer
447     + * Draw a progress bar on framebuffer
448     + * \param frompct percentage on which bar starting
449     + * \param topct percentage where bar end
450     */
451     -static void fb_drawrectangle(void)
452     +static void fb_drawnbar(int frompct, int topct)
453     {
454     - int cnt;
455     - unsigned thispix;
456     - unsigned char *ptr1, *ptr2;
457     - unsigned char nred = G.nbar_colr/2;
458     - unsigned char ngreen = G.nbar_colg/2;
459     - unsigned char nblue = G.nbar_colb/2;
460     -
461     - thispix = fb_pixel_value(nred, ngreen, nblue);
462     -
463     - // horizontal lines
464     - ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
465     - ptr2 = G.addr + (G.nbar_posy + G.nbar_height - 1) * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
466     - cnt = G.nbar_width - 1;
467     - do {
468     - fb_write_pixel(ptr1, thispix);
469     - fb_write_pixel(ptr2, thispix);
470     - ptr1 += G.bytes_per_pixel;
471     - ptr2 += G.bytes_per_pixel;
472     - } while (--cnt >= 0);
473     -
474     - // vertical lines
475     - ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
476     - ptr2 = G.addr + G.nbar_posy * G.scr_fix.line_length + (G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel;
477     - cnt = G.nbar_height - 1;
478     - do {
479     - fb_write_pixel(ptr1, thispix);
480     - fb_write_pixel(ptr2, thispix);
481     - ptr1 += G.scr_fix.line_length;
482     - ptr2 += G.scr_fix.line_length;
483     - } while (--cnt >= 0);
484     + int w0,w1,w2;
485     +
486     + if (G.spb1 == NULL || G.spb2 == NULL)
487     + return;
488     + if (frompct < 0 || frompct > 100 ||
489     + topct < 0 || topct > 100 ||
490     + frompct > topct) {
491     + return;
492     + }
493     +
494     + w0 = G.spb1->w * frompct / 100;
495     + w0 = (w0 > G.spb1->w ? G.spb1->w : w0);
496     + w2 = G.spb1->w * (100 - topct) / 100;
497     + w2 = ((w0 + w2) > G.spb1->w ? G.spb1->w - w0 : w2);
498     + w1 = G.spb1->w - w0 - w2;
499     + if (w0 > 0)
500     + fb_sprite(G.nbar_posx, G.nbar_posy, 0, w0, G.spb1, 0); // left "empty" area
501     + if (w1 > 0)
502     + fb_sprite(G.nbar_posx + w0, G.nbar_posy, w0, w1, G.spb2, 0); // filled area
503     + if (w2 > 0)
504     + fb_sprite(G.nbar_posx + w0 + w1, G.nbar_posy, w0 + w1, w2, G.spb1, 0); // right "empty" area
505     }
506    
507     +static struct sprite *fb_newsprite(int pw, int ph, int scrx, int scry) {
508     + struct sprite *s;
509     + s=xmalloc(sizeof(struct sprite) +
510     + ph * pw * G.bytes_per_pixel);
511     + s->w = pw;
512     + s->h = ph;
513     + s->bw = pw * G.bytes_per_pixel;
514     + if (scrx >= 0) fb_getsprite(scrx, scry, s); // read
515     + return s;
516     +}
517    
518     /**
519     - * Draw filled rectangle on framebuffer
520     - * \param nx1pos,ny1pos upper left position
521     - * \param nx2pos,ny2pos down right position
522     - * \param nred,ngreen,nblue rgb color
523     + * Open PPM file - must be binary, color maxval 255
524     */
525     -static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
526     - unsigned char nred, unsigned char ngreen, unsigned char nblue)
527     -{
528     - int cnt1, cnt2, nypos;
529     - unsigned thispix;
530     - unsigned char *ptr;
531     -
532     - thispix = fb_pixel_value(nred, ngreen, nblue);
533     -
534     - cnt1 = ny2pos - ny1pos;
535     - nypos = ny1pos;
536     - do {
537     - ptr = G.addr + nypos * G.scr_fix.line_length + nx1pos * G.bytes_per_pixel;
538     - cnt2 = nx2pos - nx1pos;
539     - do {
540     - fb_write_pixel(ptr, thispix);
541     - ptr += G.bytes_per_pixel;
542     - } while (--cnt2 >= 0);
543     +static struct ppmfile *ppm_open(const char *filename) {
544     + int i,k,l,val;
545     + struct ppmfile *p;
546     + uint8_t *s;
547     + char *e;
548     +
549     + i = open_zipped(filename);
550     + if (i == -1) return NULL;
551     + p = (struct ppmfile *) xmalloc(sizeof(struct ppmfile) + 600);
552     + // initial buf 600 bytes header cannot be larger
553     + p->fd = i;
554     + /* Parse ppm header:
555     + * - Magic: two characters "P6".
556     + * - Whitespace (blanks, TABs, CRs, LFs).
557     + * - A width, formatted as ASCII characters in decimal.
558     + * - Whitespace.
559     + * - A height, ASCII decimal.
560     + * - Whitespace.
561     + * - The maximum color value, ASCII decimal, in 0..65535
562     + * - Newline or other single whitespace character.
563     + * (we support newline only)
564     + * - A raster of Width * Height pixels in triplets of rgb
565     + * in pure binary by 1 or 2 bytes. (we support only 1 byte)
566     + */
567     + l=read(p->fd,&(p->buf[0]),600);
568     + if ((l < 0) || (p->buf[0] != 'P') || (p->buf[1] != '6')) {
569     + goto ppmopen_end;
570     + }
571     + for (s = &(p->buf[2]), i = 0, k = 0; s < &(p->buf[l]) && (k < 3); ) {
572     + switch (i) {
573     + case 0:
574     + if (*s <= ' ') {
575     + s++; // skip whitespaces
576     + } else {
577     + i++; // next state
578     + }
579     + break;
580     + case 1: // num or rmks
581     + if (*s == '#') {
582     + i = 2;
583     + } else {
584     + val=bb_strtoi((char *)s,&e,10);
585     + if (s == (uint8_t *)e) goto ppmopen_end; // no number - error
586     + s=(uint8_t *)e;
587     + i=0; // skip whitespaces
588     + switch (++k) {
589     + case 1: p->sizx = val; break;
590     + case 2: p->sizy = val; break;
591     + case 3:
592     + if (val > 255)
593     + goto ppmopen_end; // only 1 byte per color
594     + s++;
595     + p->bufhead = s - &(p->buf[0]);
596     + p->buftail = l;
597     + break;
598     + }
599     + }
600     + break;
601     + case 2: // skip to eol
602     + if (*s == 10) i=0;
603     + s++;
604     + break;
605     + }
606     + }
607     + if (p->sizx < 1 || p->sizy < 1) goto ppmopen_end;
608     + if (p->sizx > 200) {
609     + // buf is only 600 bytes = 200 pix prealocated - need more.
610     + p = xrealloc(p,sizeof(struct ppmfile) + 3 * p->sizx);
611     + }
612     + return p;
613     +
614     +ppmopen_end:
615     + close(p->fd);
616     + free(p);
617     + return NULL;
618     +}
619    
620     - nypos++;
621     - } while (--cnt1 >= 0);
622     +/**
623     + * Read pixelline from ppm to internal buffer and return pointer
624     + */
625     +static uint8_t *ppm_readline(struct ppmfile *p) {
626     + int i;
627     + if (p==NULL) return NULL;
628     + if (p->bufhead < p->buftail) {
629     + // pack buffer
630     + for (i = 0; p->bufhead < p->buftail; i++) {
631     + p->buf[i]=p->buf[p->bufhead++];
632     + }
633     + p->buftail = i;
634     + } else {
635     + p->buftail = 0;
636     + }
637     + while (p->buftail < (p->sizx * 3)) {
638     + i=read(p->fd, &(p->buf[p->buftail]), (p->sizx * 3) - p->buftail);
639     + if (i < 0) return NULL;
640     + p->buftail += i;
641     + }
642     + p->bufhead = p->sizx * 3;
643     + return &(p->buf[0]);
644     }
645    
646     +/**
647     + * Close ppmfile
648     + */
649     +static void ppm_close(struct ppmfile *p) {
650     + if (p == NULL) return;
651     + close(p->fd);
652     + free(p);
653     +}
654    
655     /**
656     - * Draw a progress bar on framebuffer
657     - * \param percent percentage of loading
658     + * Draws a PPM image.
659     */
660     -static void fb_drawprogressbar(unsigned percent)
661     +static void fb_drawimage(void)
662     {
663     - int left_x, top_y, pos_x;
664     - unsigned width, height;
665     + struct ppmfile *ppm;
666     + unsigned char *pixel;
667     + unsigned char *rgbline,*rgbpix,*sprpix;
668     + RGB thispix;
669     + unsigned i, j, width, height;
670     +
671     + ppm = ppm_open(G.image_filename);
672     + if (ppm == NULL)
673     + bb_error_msg_and_die("PPM file %s cannot be opened",G.image_filename);
674     + width = ppm->sizx;
675     + height = ppm->sizy;
676     + if (width > G.scr_var.xres || height > G.scr_var.yres)
677     + bb_error_msg_and_die("PPM %dx%d does not match screen %dx%d",
678     + width, height, G.scr_var.xres, G.scr_var.yres);
679     + if (width > G.scr_var.xres)
680     + width = G.scr_var.xres;
681     + if (height > G.scr_var.yres)
682     + height = G.scr_var.yres;
683     +
684     + G.x0 = (width == G.scr_var.xres ? 0 : (G.scr_var.xres - width) / 2);
685     + G.y0 = (height == G.scr_var.yres ? 0 : (G.scr_var.yres - height) / 2);
686     + rgbline = xmalloc((width * G.bytes_per_pixel) + sizeof(RGB));
687    
688     - // outer box
689     - left_x = G.nbar_posx;
690     - top_y = G.nbar_posy;
691     - width = G.nbar_width - 1;
692     - height = G.nbar_height - 1;
693     - if ((int)(height | width) < 0)
694     - return;
695     - // NB: "width" of 1 actually makes rect with width of 2!
696     - fb_drawrectangle();
697     + for (j = 0; j < height; j++) {
698     + pixel = ppm_readline(ppm);
699     + rgbpix = rgbline;
700     + if (pixel == NULL)
701     + bb_error_msg_and_die("bad PPM file '%s' line %d", G.image_filename,j);
702     + if (G.spb2 != NULL && j >= G.nbar_posy && j < (G.nbar_posy + G.spb2->h)) {
703     + sprpix = &(G.spb2->pixbuf[(j - G.nbar_posy) * G.spb2->bw]);
704     + } else {
705     + sprpix = NULL;
706     + }
707    
708     - // inner "empty" rectangle
709     - left_x++;
710     - top_y++;
711     - width -= 2;
712     - height -= 2;
713     - if ((int)(height | width) < 0)
714     - return;
715     + for (i = 0; i < width; i++) {
716     + thispix = makecol(pixel[0],pixel[1],pixel[2]);
717     + *((RGB*)rgbpix) = thispix;
718     + if ((sprpix != NULL) && (i >= G.nbar_posx)) {
719     + if (G.nbar_colr >= 256) { // Multiple not add
720     + thispix = makecol((G.nbar_colr & 255) * pixel[0], (G.nbar_colg & 255) * pixel[1], (G.nbar_colb & 255) * pixel[2]);
721     + } else {
722     + thispix = makecol(G.nbar_colr + pixel[0], G.nbar_colg + pixel[1], G.nbar_colb + pixel[2]);
723     + }
724     + memcpy(sprpix,&thispix,G.bytes_per_pixel);
725     + if (i >= (G.nbar_posx + G.spb2->w - 1)) {
726     + sprpix = NULL;
727     + } else {
728     + sprpix += G.bytes_per_pixel;
729     + }
730     + }
731     + pixel += 3;
732     + rgbpix += G.bytes_per_pixel;
733     + }
734     + fb_putpixrow(G.x0,j + G.y0,width,rgbline);
735     + }
736     + free(rgbline);
737     + ppm_close(ppm);
738     + // recalc cfg if centered image
739     + G.nbar_posx += G.x0;
740     + G.nbar_posy += G.y0;
741     +#if ENABLE_FEATURE_FBSPLASH_TEXT
742     + G.text_posx += G.x0;
743     + G.text_posy += G.y0;
744     +#endif
745     +}
746    
747     - pos_x = left_x;
748     - if (percent > 0) {
749     - int y;
750     - unsigned i;
751     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
752     +/**
753     + * Read rectangle sprites from ppm file
754     + * \return pointer to array of sprites
755     + * \return number of sprites loaded
756     + */
757     +static struct sprite *fb_loadsprites(char *filename, int sx, int sy) {
758     + struct ppmfile *ppm;
759     + uint8_t *pixel, *rgbpix;
760     + struct sprite *s=NULL;
761     + int y,i;
762     + RGB thispix;
763     +
764     + if ((ppm = ppm_open(filename)) == NULL) goto readsprites_out;
765     + s = fb_newsprite(ppm->sizx + ppm->sizy, ppm->sizy, -1, -1);
766     + fb_sprite(sx + G.x0, sy + G.y0, 0, s->h, s, 1); // load square 0 - background
767     + rgbpix = &(s->pixbuf[0]);
768     + for (y = 0; y < ppm->sizy; y++) {
769     + // skip square 0
770     + rgbpix += s->h * G.bytes_per_pixel;
771     + // read from file
772     + pixel = ppm_readline(ppm);
773     + for (i = 0; (pixel != NULL) && (i < ppm->sizx); i++) {
774     + if (pixel[0]==0xFF && pixel[1]==0 && pixel[2]==0xFF) {
775     + // transparent color => get pixel from square 0
776     + memcpy(&thispix,
777     + &(s->pixbuf[y * s->bw + (i % s->h) * G.bytes_per_pixel]),
778     + G.bytes_per_pixel);
779     + } else {
780     + thispix = makecol(pixel[0],pixel[1],pixel[2]);
781     + }
782     + memcpy(rgbpix,&thispix,G.bytes_per_pixel);
783     + pixel += 3;
784     + rgbpix += G.bytes_per_pixel;
785     + }
786     + }
787     + ppm_close(ppm);
788     + return s;
789     +readsprites_out:
790     + if (s != NULL) free(s);
791     + return NULL;
792     +}
793     +
794     +#define fb_putanim(x,y,n,s) fb_sprite(x + G.x0,y + G.y0,s->h * n,s->h,s,0)
795     +#endif
796    
797     - // actual progress bar
798     - pos_x += (unsigned)(width * percent) / 100;
799     +#if ENABLE_FEATURE_FBSPLASH_TEXT
800    
801     - y = top_y;
802     - i = height;
803     - if (height == 0)
804     - height++; // divide by 0 is bad
805     - while (i >= 0) {
806     - // draw one-line thick "rectangle"
807     - // top line will have gray lvl 200, bottom one 100
808     - unsigned gray_level = 100 + i*100 / height;
809     - fb_drawfullrectangle(
810     - left_x, y, pos_x, y,
811     - gray_level, gray_level, gray_level);
812     - y++;
813     - i--;
814     +/*
815     + * A function to put the pixel
816     + */
817     +static void fb_putpixel(int x, int y, RGB rgb) {
818     + uint8_t *a;
819     + if (x < 0 || y < 0 || x > G.scr_var.xres || y > G.scr_var.yres) return;
820     + a=G.addr + G.scr_fix.line_length * y + G.bytes_per_pixel * x;
821     + memcpy(a,&rgb,G.bytes_per_pixel);
822     +
823     + return;
824     +}
825     +
826     +/**
827     + * UTF-8 - get one charcter and advance to next
828     + * ??? this function may be in libbb ???
829     + * \return UCS4 value
830     + */
831     +static uint32_t ucs4value(uint8_t **s) {
832     + uint8_t *c;
833     + uint32_t ucs,w;
834     + int count;
835     +
836     + if (s==NULL || *s==NULL || **s==0) return 0;
837     + c = *s;
838     + ucs = *c++;
839     + if (ucs >= 0xC0) { /* 0x80..0xBF is error in utf8 but i use as-is */
840     + for (w = ucs & 0x7F, count = 0;(w & 0x40) == 0x40; count++) {
841     + w <<= 1;
842     + }
843     + ucs=ucs & (0x7E >> count);
844     + for(; count > 0; count--) {
845     + if ((*c & 0xC0) != 0x80) { /* error in utf8 */
846     + ucs=0;
847     + break;
848     + }
849     + ucs = (ucs << 6) + (*c++ & 0x3F);
850     + }
851     + }
852     + *s=c;
853     + return ucs;
854     +}
855     +
856     +/**
857     + * Find in GF.ud.entries desired UTF-8 char and advance to next char
858     + * can combine glyphs in own memory
859     + * \param s pointer to utf8 char pointer
860     + * \return pinter to glyph
861     + */
862     +static uint8_t *getglyph(uint8_t **s) {
863     + uint32_t ucs;
864     + uint8_t *c,*g;
865     + int utflen,i;
866     +
867     + if (s == NULL || *s == NULL || **s == 0)
868     + return G.unknown_glyph; /* end of string - no advance */
869     + c = *s;
870     + ucs = ucs4value(&c);
871     + utflen = c - *s;
872     + g = G.unknown_glyph;
873     + if (GF.ud.entries == NULL) {
874     + if (ucs < GF.glyphcount) {
875     + g = GF.glyphs + GF.charsize * ucs;
876     + }
877     + } else if (ucs <= 0xFFFF) { // only ucs2
878     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
879     + int j,compose;
880     + memset(G.combglyph,0,sizeof(G.combglyph));
881     + for (i = 0, compose=0; i < GF.ud.entry_ct; i++) {
882     + if (GF.ud.entries[i].unicode == ucs) {
883     + g=GF.glyphs +
884     + GF.ud.entries[i].fontpos * GF.charsize;
885     + for (j = 0; j < GF.charsize; j++) {
886     + G.combglyph[j] |= g[j];
887     + }
888     + compose++;
889     + }
890     }
891     + if (compose > 1) { // found more than one
892     + g = &(G.combglyph[0]);
893     + }
894     +#else
895     + // no sequences - first found win
896     + for (i = 0; i < GF.ud.entry_ct ; i++) {
897     + if (GF.ud.entries[i].unicode == ucs) {
898     + g = GF.glyphs + GF.ud.entries[i].fontpos * GF.charsize;
899     + break;
900     + }
901     + }
902     +#endif
903     }
904     + *s=c;
905     + return g;
906     +}
907    
908     - fb_drawfullrectangle(
909     - pos_x, top_y,
910     - left_x + width, top_y + height,
911     - G.nbar_colr, G.nbar_colg, G.nbar_colb);
912     +/**
913     + * Draws a single character on framebuffer.
914     + * \param nXPos horizontal position from which draw the character.
915     + * \param nYPos vertical position from which draw the character.
916     + * \param nCharSize character scale factor [1..4].
917     + * \param pointer to *nChar character to draw - auto advance by utf8.
918     + * \param RGB color
919     + */
920     +static void fb_drawchar(int nXPos, int nYPos, int nCharSize,
921     + uint8_t **nChar, RGB thispix)
922     +{
923     + int x,y,px;
924     + uint8_t *glyph;
925     +
926     + if (G.font==NULL || GF.height==0 || GF.glyphs==NULL) return;
927     + if (G.unknown_glyph == NULL) {
928     + uint8_t *unknown;
929     + const uint8_t unconst[]="?";
930     + unknown=(uint8_t *)unconst;
931     + G.unknown_glyph = getglyph(&unknown);
932     + }
933     +
934     + glyph=getglyph(nChar);
935     + if (glyph==NULL) return;
936     + glyph-=GF.rowbytes;
937     + for (y = 0; y < (GF.height * nCharSize); y++) {
938     + if ((y % nCharSize) == 0) glyph+=GF.rowbytes;
939     + for (x = 0,px = -1; x < (GF.width * nCharSize); x++) {
940     + if ((x % nCharSize) == 0) px++;
941     + if ((glyph[px / 8] & (0x80 >> (px % 8))) != 0) {
942     + fb_putpixel(nXPos + x, nYPos + y,thispix);
943     + }
944     + }
945     + }
946     }
947    
948    
949     /**
950     - * Draw image from PPM file
951     + * Draws a string on framebuffer.
952     + * \param *strString pointer to the string.
953     */
954     -static void fb_drawimage(void)
955     +static void fb_drawstring(char *strString)
956     {
957     - FILE *theme_file;
958     - char *read_ptr;
959     - unsigned char *pixline;
960     - unsigned i, j, width, height, line_size;
961     + RGB thispix;
962     + int nCharSize;
963     + int x;
964     + uint8_t *c;
965     +
966     + // size check
967     + nCharSize = G.text_size;
968     + if (nCharSize < 1)
969     + nCharSize = 1;
970     + else if (nCharSize > 4)
971     + nCharSize = 4;
972     +
973     + if (G.font==NULL || GF.height==0 || GF.glyphs==NULL) return;
974     +
975     + // redraws the portion of image interested to the old write operation
976     + fb_putsprite(G.text_posx, G.text_posy, G.spt);
977     +
978     + // new write operation
979     + thispix=makecol(G.text_colr,G.text_colg,G.text_colb);
980     + for (x = G.text_posx, c = (uint8_t *)strString; *c != 0;) {
981     +#if ENABLE_FEATURE_FBSPLASH_TEXT_COLORS
982     + if (*c==0x1b && c[1]=='[') {
983     + long newcol=0,first;
984     + char *e;
985     + e=(char *)&(c[1]);
986     + do {
987     + first=newcol;
988     + ++e;
989     + newcol = strtol(e,&e,10);
990     + } while (*e == ';');
991     + if (*e == 'm' && ((newcol == 0) || (newcol >= 30 && newcol <= 37))) {
992     + if (newcol >= 30 && newcol <= 37) {
993     + if (newcol == 0 && first == 1) {
994     + thispix=makecol(0x33,0x33,0x33);
995     + } else {
996     + newcol -= 30;
997     + first = (first == 1 ? 0xFF : 0xCC);
998     + thispix=makecol((newcol & 1) ? first : 0,
999     + (newcol & 2) ? first : 0,
1000     + (newcol & 4) ? first : 0);
1001     + }
1002     + } else {
1003     + thispix=makecol(G.text_colr,G.text_colg,G.text_colb);
1004     + }
1005     + c=(uint8_t *)(++e);
1006     + continue;
1007     + }
1008     + }
1009     +#endif
1010     + fb_drawchar(x, G.text_posy, nCharSize, &c, thispix);
1011     + x += GF.width * nCharSize;
1012     + if (x >= G.scr_var.xres) break; // too long string
1013     + }
1014     +}
1015    
1016     - if (LONE_DASH(G.image_filename)) {
1017     - theme_file = stdin;
1018     - } else {
1019     - int fd = open_zipped(G.image_filename);
1020     - if (fd < 0)
1021     - bb_simple_perror_msg_and_die(G.image_filename);
1022     - theme_file = xfdopen_for_read(fd);
1023     +/**
1024     + * Free readed font structure with all allocated memory
1025     + */
1026     +static void fb_freefont(void) {
1027     + if (G.font != NULL) {
1028     + if (GF.mem1 != NULL) free(GF.mem1);
1029     + if (GF.ud.entries != NULL) free(GF.ud.entries);
1030     + free(G.font);
1031     + G.font=NULL;
1032     }
1033     +}
1034    
1035     - /* Parse ppm header:
1036     - * - Magic: two characters "P6".
1037     - * - Whitespace (blanks, TABs, CRs, LFs).
1038     - * - A width, formatted as ASCII characters in decimal.
1039     - * - Whitespace.
1040     - * - A height, ASCII decimal.
1041     - * - Whitespace.
1042     - * - The maximum color value, ASCII decimal, in 0..65535
1043     - * - Newline or other single whitespace character.
1044     - * (we support newline only)
1045     - * - A raster of Width * Height pixels in triplets of rgb
1046     - * in pure binary by 1 or 2 bytes. (we support only 1 byte)
1047     - */
1048     -#define concat_buf bb_common_bufsiz1
1049     - read_ptr = concat_buf;
1050     - while (1) {
1051     - int w, h, max_color_val;
1052     - int rem = concat_buf + sizeof(concat_buf) - read_ptr;
1053     - if (rem < 2
1054     - || fgets(read_ptr, rem, theme_file) == NULL
1055     - ) {
1056     - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
1057     - }
1058     - read_ptr = strchrnul(read_ptr, '#');
1059     - *read_ptr = '\0'; /* ignore #comments */
1060     - if (sscanf(concat_buf, "P6 %u %u %u", &w, &h, &max_color_val) == 3
1061     - && max_color_val <= 255
1062     - ) {
1063     - width = w; /* w is on stack, width may be in register */
1064     - height = h;
1065     - break;
1066     +/**
1067     + * Read font and mapping from console using ioctl GIO_FONT and GIO_UNIMAP
1068     + */
1069     +static void fb_readvgafont(void) {
1070     + int fd,i;
1071     +#if (defined(KDFONTOP) && defined(KD_FONT_OP_GET)) || defined(GIO_FONTX)
1072     +#if defined(KDFONTOP) && defined(KD_FONT_OP_GET)
1073     + struct console_font_op fo;
1074     + fd = open(CURRENT_TTY,O_NONBLOCK);
1075     + if (fd == -1) return;
1076     +
1077     + fo.data = NULL;
1078     + fo.charcount = 0;
1079     + fo.height = 32; fo.width = 32; // max usable font size
1080     + fo.flags = 0;
1081     + fo.op = KD_FONT_OP_GET;
1082     + if (ioctl(fd, KDFONTOP, &fo) == 0) {
1083     + i = (fo.width + 7) / 8;
1084     + fo.data = xmalloc(fo.charcount * 32 * i);
1085     + if (ioctl(fd, KDFONTOP, &fo) == -1) {
1086     + free(fo.data);
1087     + goto fb_vgafontout;
1088     + }
1089     + }
1090     + if (G.font != NULL) fb_freefont();
1091     + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont));
1092     + GF.height = fo.height;
1093     + GF.glyphcount = fo.charcount;
1094     + GF.width = fo.width;
1095     + GF.rowbytes = (fo.width + 7) / 8;
1096     + GF.charsize = GF.height * GF.rowbytes;
1097     + GF.mem1 = (uint8_t *) xmalloc(GF.height * GF.glyphcount * GF.rowbytes);
1098     + GF.glyphs = GF.mem1;
1099     + for (i = 0; i < GF.glyphcount; i++) {
1100     + memcpy(&(GF.glyphs[i * GF.height * GF.rowbytes]),
1101     + &(fo.data[i * 32 * GF.rowbytes]),
1102     + GF.height * GF.rowbytes);
1103     + }
1104     + if (fo.data) free(fo.data);
1105     +#else // KDFONTOP / GIO_FONTX
1106     + struct consolefontdesc cfd;
1107     + int j;
1108     + fd = open(CURRENT_TTY,O_NONBLOCK);
1109     + if (fd == -1) return;
1110     +
1111     + cfd.chardata = NULL;
1112     + cfd.charcount = 0;
1113     + cfd.charheight = 0;
1114     + if (ioctl(fd, GIO_FONTX, &cfd) == 0) {
1115     + cfd.chardata = xmalloc(cfd.charcount * 32);
1116     + if (ioctl(fd, GIO_FONTX, &cfd) == -1) {
1117     + free(cfd.chardata);
1118     + goto fb_vgafontout;
1119     + }
1120     + } else {
1121     + cfd.charcount=256;
1122     + cfd.chardata = xmalloc(256 * 32);
1123     + if (ioctl(fd, GIO_FONT, cfd.chardata) != 0) {
1124     + free(cfd.chardata);
1125     + goto fb_vgafontout;
1126     + }
1127     + // compute real height
1128     + cfd.charheight=0;
1129     + for (j = 31; (j > 0) && (cfd.charheight == 0); j--) {
1130     + for (i = 0; (i < 256) && (cfd.charheight == 0); i++) {
1131     + if (cfd.chardata[i*32+j] != 0)
1132     + cfd.charheight=j;
1133     + }
1134     + }
1135     + }
1136     + if (cfd.charheight != 0) {
1137     + if (G.font != NULL) fb_freefont();
1138     + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont));
1139     + GF.charsize = cfd.charheight;
1140     + GF.height = GF.charsize;
1141     + GF.glyphcount = cfd.charcount;
1142     + GF.width = 8;
1143     + GF.rowbytes = 1;
1144     + GF.mem1 = (uint8_t *) xmalloc(GF.height * GF.glyphcount);
1145     + GF.glyphs = GF.mem1;
1146     + // pack font
1147     + for (i = 0; i < GF.glyphcount; i++) {
1148     + memcpy(&(GF.glyphs[i * GF.height]),
1149     + &(cfd.chardata[i * 32]),
1150     + GF.height);
1151     }
1152     }
1153     + free(cfd.chardata);
1154     +#endif // FONTOP / FONTX
1155     +#if defined(GIO_UNIMAP)
1156     + GF.ud.entry_ct = 0;
1157     + ioctl(fd, GIO_UNIMAP, &(GF.ud));
1158     + if (errno != ENOMEM) {
1159     + goto fb_vgafontout;
1160     + }
1161     + if (GF.ud.entry_ct > 0) {
1162     + GF.ud.entries = xmalloc(GF.ud.entry_ct * sizeof(struct unipair));
1163     + if (ioctl(fd, GIO_UNIMAP, &(GF.ud)) == -1) {
1164     + // error no unimap
1165     + free(GF.ud.entries);
1166     + GF.ud.entry_ct = 0;
1167     + }
1168     + }
1169     +#endif // GIO_UNIMAP
1170     +fb_vgafontout:
1171     + close(fd);
1172     +#endif // GIO_FONTX or KDFONTOP available
1173     + return;
1174     +}
1175    
1176     - line_size = width*3;
1177     - pixline = xmalloc(line_size);
1178     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
1179    
1180     - if (width > G.scr_var.xres)
1181     - width = G.scr_var.xres;
1182     - if (height > G.scr_var.yres)
1183     - height = G.scr_var.yres;
1184     - for (j = 0; j < height; j++) {
1185     - unsigned char *pixel;
1186     - unsigned char *src;
1187     +static uint16_t nextuni(int ver, uint8_t *map, int *pos) {
1188     + uint16_t rv;
1189     + int i;
1190     + i=*pos;
1191     + if (ver==1) {
1192     + rv = map[i + 1];
1193     + rv = (rv << 8) + map[i];
1194     + i += 2;
1195     + } else { // ver 2
1196     + if (map[i] == 0xFF) rv = 0xFFFF;
1197     + else if (map[i] == 0xFE) rv = 0xFFFE;
1198     + else if (map[i] < 0xC0) rv = map[i];
1199     + else if (map[i] < 0xE0) {
1200     + rv = map[i] & 0x1F;
1201     + if ((map[i + 1] & 0xC0) == 0x80)
1202     + rv = (rv << 6) + (map[++i] & 0x3F);
1203     + } else if (map[i] < 0xF0) {
1204     + rv = map[i] & 0x0F;
1205     + if ((map[i + 1] & 0xC0) == 0x80)
1206     + rv = (rv << 6) + (map[++i] & 0x3F);
1207     + if ((map[i + 1] & 0xC0) == 0x80)
1208     + rv = (rv << 6) + (map[++i] & 0x3F);
1209     + } else rv = map[i];
1210     + i++;
1211     + }
1212     + *pos=i;
1213     + return rv;
1214     +}
1215    
1216     - if (fread(pixline, 1, line_size, theme_file) != line_size)
1217     - bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
1218     - pixel = pixline;
1219     - src = G.addr + j * G.scr_fix.line_length;
1220     - for (i = 0; i < width; i++) {
1221     - unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]);
1222     - fb_write_pixel(src, thispix);
1223     - src += G.bytes_per_pixel;
1224     - pixel += 3;
1225     +/**
1226     + * Convert unimap from psf v1 and psf v2 to unimapdesc
1227     + */
1228     +static void convertmap(int ver, uint8_t *map, int mapsize, struct unimapdesc *ud) {
1229     + int i,j,k,glyph,glycodes;
1230     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1231     + int l, seqlen=0, *seq=NULL;
1232     +#endif
1233     + uint16_t e;
1234     + ud->entry_ct=0;
1235     + for (i = 0, glycodes=0; i < mapsize; ) {
1236     + e = nextuni(ver, map, &i);
1237     + if (e == PSF1_STARTSEQ) {
1238     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1239     + seqlen++;
1240     +#endif
1241     + e = nextuni(ver, map, &i);
1242     + while ((e != PSF1_SEPARATOR) && (i < mapsize)) {
1243     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1244     + ud->entry_ct += glycodes;
1245     +#endif
1246     + e = nextuni(ver, map, &i);
1247     + }
1248     + glycodes=0;
1249     + } else if (e == PSF1_SEPARATOR) {
1250     + ud->entry_ct += glycodes;
1251     + glycodes=0;
1252     + } else {
1253     + glycodes++;
1254     + }
1255     + }
1256     + ud->entries = (struct unipair *)
1257     + xmalloc(sizeof(struct unimapdesc) * ud->entry_ct);
1258     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1259     + if (seqlen > 0) {
1260     + seq = xzalloc(sizeof(int) * (seqlen + 1));
1261     + }
1262     +#endif
1263     + for (i = 0, glyph = 0, j = 0, k = 0; i < mapsize; ) {
1264     + e = nextuni(ver, map, &i);
1265     + if (e == PSF1_STARTSEQ) {
1266     + e = nextuni(ver, map, &i);
1267     + k++; // this is seqence - position saved
1268     + // remove sequence - this is not glyph
1269     + while (ud->entries[j-1].fontpos == glyph && j > 0) {
1270     + j--;
1271     + }
1272     + // skip chars in seq
1273     + while ((e != PSF1_SEPARATOR) && (i < mapsize)) {
1274     + e = nextuni(ver, map, &i);
1275     + }
1276     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1277     + if (k < seqlen) seq[k] = i;
1278     +#endif
1279     + } else if (e == PSF1_SEPARATOR) {
1280     + glyph++;
1281     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1282     + // next may be sequence
1283     + if (k < seqlen) seq[k] = i;
1284     +#endif
1285     + } else if (j < ud->entry_ct) {
1286     + ud->entries[j].unicode=e;
1287     + ud->entries[j++].fontpos=glyph;
1288     + }
1289     + }
1290     +#if ENABLE_FEATURE_FBSPLASH_PSFSEQS
1291     + i = 0;
1292     + while (i < seqlen) {
1293     + k = seq[i];
1294     + do {
1295     + e = nextuni(ver, map, &k);
1296     + } while (e != PSF1_STARTSEQ && e != PSF1_SEPARATOR && k < mapsize);
1297     + if (e == PSF1_STARTSEQ) {
1298     + e = nextuni(ver, map, &k);
1299     + while ((e != PSF1_SEPARATOR) && (k < mapsize)) {
1300     + // find glyph in table
1301     + glyph = 0;
1302     + while ((glyph < j) && (ud->entries[glyph].unicode != e)) {
1303     + glyph++;
1304     + }
1305     + // write glyph to table for all chars
1306     + if (glyph < j) { // found
1307     + l = seq[i]; // code pointer
1308     + e = nextuni(ver, map, &l);
1309     + while(e != PSF1_STARTSEQ && l < mapsize) {
1310     + ud->entries[j].unicode=e;
1311     + ud->entries[j++].fontpos=ud->entries[glyph].fontpos;
1312     + e = nextuni(ver, map, &l);
1313     + }
1314     + }
1315     + e = nextuni(ver, map, &k);
1316     + }
1317     }
1318     + i++;
1319     }
1320     - free(pixline);
1321     - fclose(theme_file);
1322     + if (seqlen > 0) {
1323     + // remove unfound glyphs if any
1324     + ud->entry_ct = j;
1325     + free(seq);
1326     + }
1327     +#endif
1328     }
1329    
1330     +/**
1331     + * Read PSF v1 and PSF v2 fonts to own font structure
1332     + */
1333     +static void fb_readpsf(const char *filename) {
1334     + unsigned int len;
1335     + int maplen;
1336     + uint8_t *buf;
1337     + struct psf1_header *psf1;
1338     + struct psf2_header *psf2;
1339     +
1340     + if (G.font != NULL) fb_freefont();
1341     + len = 48*1024; // can't be larger
1342     + buf = xmalloc_open_zipped_read_close(filename, &len);
1343     + if (buf == NULL) {
1344     + bb_simple_perror_msg_and_die(filename);
1345     + }
1346     + if (len < 1024) {
1347     + goto badfmt;
1348     + }
1349     + G.font = (struct fbfont *) xzalloc(sizeof(struct fbfont));
1350     + GF.mem1 = buf;
1351     + psf1 = (struct psf1_header *)buf;
1352     + psf2 = (struct psf2_header *)buf;
1353     + if ((psf1->magic == PSF1_MAGIC) && (psf1->mode <= PSF1_MAXMODE)) {
1354     + GF.glyphs = &(buf[sizeof(struct psf1_header)]);
1355     + GF.charsize = psf1->charsize;
1356     + GF.height = GF.charsize;
1357     + GF.glyphcount = ((psf1->mode & PSF1_MODE512) ? 512 : 256);
1358     + GF.width = 8;
1359     + maplen = len - sizeof(struct psf1_header) -
1360     + (GF.charsize * GF.glyphcount);
1361     + if ((maplen > 0) && ((psf1->mode & PSF1_MODEHASTAB) != 0)) {
1362     + convertmap(1,&(buf[len - maplen]),maplen,&(GF.ud));
1363     + } else {
1364     + if (maplen < 0) goto badfmt;
1365     + }
1366     + } else if ((psf2->magic == PSF2_MAGIC) &&
1367     + (psf2->version <= PSF2_MAXVERSION)) {
1368     + GF.glyphs=&(buf[psf2->headersize]);
1369     + GF.height = psf2->height;
1370     + GF.width = psf2->width;
1371     + GF.glyphcount = psf2->length;
1372     + GF.charsize = psf2->charsize;
1373     + maplen = len - psf2->headersize -
1374     + (GF.charsize * GF.glyphcount);
1375     + if ((maplen > 0) && ((psf2->flags & PSF2_HAS_UNICODE_TABLE) != 0)) {
1376     + convertmap(2,&(buf[len - maplen]),maplen,&(GF.ud));
1377     + } else {
1378     + if (maplen < 0) goto badfmt;
1379     + }
1380     + } else {
1381     + goto badfmt;
1382     + }
1383     + GF.rowbytes = GF.charsize / GF.height;
1384     +
1385     + return;
1386     +badfmt:
1387     + if (G.font) fb_freefont();
1388     + bb_error_msg_and_die("Cannot read file %s - unrecognized format\n",filename);
1389     +}
1390     +#endif // FONTLOAD
1391     +#endif // TEXT
1392    
1393     /**
1394     * Parse configuration file
1395     @@ -414,6 +1248,9 @@
1396     "BAR_WIDTH\0" "BAR_HEIGHT\0"
1397     "BAR_LEFT\0" "BAR_TOP\0"
1398     "BAR_R\0" "BAR_G\0" "BAR_B\0"
1399     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1400     + "TEXT_LEFT\0" "TEXT_TOP\0" "TEXT_R\0" "TEXT_G\0" "TEXT_B\0" "TEXT_SIZE\0"
1401     +#endif
1402     #if DEBUG
1403     "DEBUG\0"
1404     #endif
1405     @@ -421,15 +1258,15 @@
1406     char *token[2];
1407     parser_t *parser = config_open2(cfg_filename, xfopen_stdin);
1408     while (config_read(parser, token, 2, 2, "#=",
1409     - (PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
1410     + (PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
1411     unsigned val = xatoi_positive(token[1]);
1412     int i = index_in_strings(param_names, token[0]);
1413     if (i < 0)
1414     bb_error_msg_and_die("syntax error: %s", token[0]);
1415     - if (i >= 0 && i < 7)
1416     + if (i >= 0 && i < FBCFGVALS)
1417     G.ns[i] = val;
1418     #if DEBUG
1419     - if (i == 7) {
1420     + if (i == FBCFGVALS) {
1421     G.bdebug_messages = val;
1422     if (G.bdebug_messages)
1423     G.logfile_fd = xfopen_for_write("/tmp/fbsplash.log");
1424     @@ -443,11 +1280,24 @@
1425     int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1426     int fbsplash_main(int argc UNUSED_PARAM, char **argv)
1427     {
1428     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
1429     + const char *fontmap_filename = NULL;
1430     +#endif
1431     const char *fb_device, *cfg_filename, *fifo_filename;
1432     - FILE *fp = fp; // for compiler
1433     - char *num_buf;
1434     - unsigned num;
1435     + char num_buf[512];
1436     + int num;
1437     bool bCursorOff;
1438     + struct timeval tim;
1439     + fd_set rdfds;
1440     + FILE *fp=fp;
1441     + int bounce_x=0;
1442     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1443     + int anim_x,anim_y, /* position of sprite or animation */
1444     + anim_n,anim_m, /* min sprite, max sprite for animation */
1445     + anim_p=0, /* actual sprite */
1446     + anim_t=0,anim_now=0; /* time between steps */
1447     + struct sprite *spa=NULL;
1448     +#endif
1449    
1450     INIT_G();
1451    
1452     @@ -455,9 +1305,19 @@
1453     fb_device = "/dev/fb0";
1454     cfg_filename = NULL;
1455     fifo_filename = NULL;
1456     +
1457     +#if ENABLE_FEATURE_FBSPLASH_FONTLOAD
1458     + bCursorOff = 1 & getopt32(argv, "cs:d:i:f:m:",
1459     + &G.image_filename, &fb_device, &cfg_filename, &fifo_filename, &fontmap_filename);
1460     +
1461     + if (fontmap_filename) fb_readpsf(fontmap_filename);
1462     +#else
1463     bCursorOff = 1 & getopt32(argv, "cs:d:i:f:",
1464     &G.image_filename, &fb_device, &cfg_filename, &fifo_filename);
1465     -
1466     +#endif
1467     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1468     + if (G.font==NULL) fb_readvgafont();
1469     +#endif
1470     // parse configuration file
1471     if (cfg_filename)
1472     init(cfg_filename);
1473     @@ -473,8 +1333,20 @@
1474     full_write(STDOUT_FILENO, "\033[?25l", 6);
1475     }
1476    
1477     + if (fifo_filename != NULL) {
1478     + G.spb2 = fb_newsprite(G.nbar_width, G.nbar_height, -1, -1);
1479     + }
1480     +
1481     fb_drawimage();
1482    
1483     + G.spb1 = fb_newsprite(G.nbar_width, G.nbar_height, G.nbar_posx, G.nbar_posy);
1484     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1485     + if (G.font != NULL)
1486     + G.spt = fb_newsprite(G.scr_var.xres - G.text_posx,
1487     + GF.height * G.text_size,
1488     + G.text_posx, G.text_posy);
1489     +#endif
1490     +
1491     if (!fifo_filename)
1492     return EXIT_SUCCESS;
1493    
1494     @@ -491,31 +1363,138 @@
1495     // when last writer closes input end.
1496     // The simplest way is to open fifo for writing too
1497     // and become an additional writer :)
1498     - open(fifo_filename, O_WRONLY); // errors are ignored
1499     + open(fifo_filename, O_WRONLY | O_NDELAY); // errors are ignored
1500     }
1501    
1502     - fb_drawprogressbar(0);
1503     // Block on read, waiting for some input.
1504     // Use of <stdio.h> style I/O allows to correctly
1505     // handle a case when we have many buffered lines
1506     // already in the pipe
1507     - while ((num_buf = xmalloc_fgetline(fp)) != NULL) {
1508     - if (strncmp(num_buf, "exit", 4) == 0) {
1509     - DEBUG_MESSAGE("exit");
1510     - break;
1511     - }
1512     - num = atoi(num_buf);
1513     - if (isdigit(num_buf[0]) && (num <= 100)) {
1514     + // select and fgets work just in time only in nobuf mode
1515     + setvbuf(fp, NULL, _IONBF, 0);
1516     + tim.tv_sec = 0;
1517     + tim.tv_usec = 100000;
1518     + while (1) {
1519     + FD_ZERO(&rdfds);
1520     + FD_SET(fileno(fp),&rdfds);
1521     + if ((num=select(fileno(fp) + 1,&rdfds,NULL,NULL,&tim))==-1)
1522     + break; // select error
1523     + if (num != 0 && fgets(num_buf,sizeof(num_buf) - 1,fp) != NULL) {
1524     + num_buf[sizeof(num_buf) - 1]=0;
1525     + num=strlen(num_buf) - 1;
1526     + if (num >= 0 && num_buf[num]==10) num_buf[num]=0;
1527     + if (strncmp(num_buf, "exit", 4) == 0) {
1528     + DEBUG_MESSAGE("exit");
1529     + break;
1530     + } else if (strncmp(num_buf, "bounce", 6) == 0) {
1531     + bounce_x = 0;
1532     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1533     + } else if (strncmp(num_buf, "write:", 6) == 0) {
1534     + if (G.font!=NULL) fb_drawstring(num_buf + 6);
1535     + DEBUG_MESSAGE(num_buf);
1536     +#endif
1537     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1538     + } else if (strncmp(num_buf, "load:", 5) == 0) {
1539     + if (spa) {
1540     + fb_putanim(anim_x,anim_y,0,spa); // hide old
1541     + free(spa);
1542     + spa=NULL;
1543     + }
1544     + if (sscanf(&(num_buf[5]),"%d:%d:",
1545     + &anim_x,&anim_y) == 2) {
1546     + // skip x:y
1547     + for (num=5;num_buf[num] != ':';) num++;
1548     + for (num++;num_buf[num] != ':';) num++;
1549     + spa=fb_loadsprites(&(num_buf[num + 1]),anim_x,anim_y);
1550     + anim_t = anim_now = 0; // stop animation
1551     + }
1552     + } else if (strncmp(num_buf, "sprite:", 7) == 0) {
1553     + if (spa != NULL) {
1554     + // "sprite:n"
1555     + anim_t = anim_now = 0; // stop animation
1556     + anim_p = atoi(&(num_buf[7]));
1557     + if (anim_p >= 0) {
1558     + fb_putanim(anim_x,anim_y,anim_p,spa);
1559     + }
1560     + }
1561     + } else if (strncmp(num_buf, "anime:", 6) == 0) {
1562     + if (spa != NULL) {
1563     + // "anime:n:m:t"
1564     + if ((sscanf(&(num_buf[6]),"%d:%d:%d",
1565     + &anim_n,&anim_m,&anim_t) == 3) &&
1566     + (anim_n >= 0) && (anim_m >= 0)) {
1567     + anim_p = anim_n; // first frame
1568     + fb_putanim(anim_x,anim_y,anim_p,spa);
1569     + anim_now = anim_t; // next sprite after time t
1570     + } else {
1571     + anim_now = anim_t = 0; // stop animation
1572     + }
1573     + }
1574     +#endif
1575     + } else {
1576     + num = atoi(num_buf);
1577     + if ((isdigit(num_buf[0]) || (num_buf[0]=='-')) &&
1578     + (num >= -100 && num <= 100)) {
1579     #if DEBUG
1580     - DEBUG_MESSAGE(itoa(num));
1581     + char strVal[10];
1582     + sprintf(strVal, "%d", num);
1583     + DEBUG_MESSAGE(strVal);
1584     +#endif
1585     + if (num < 0) {
1586     + fb_drawnbar(-1 * num,100);
1587     + } else {
1588     + fb_drawnbar(0,num);
1589     + }
1590     + bounce_x = -1; // stop bounce
1591     + }
1592     + }
1593     + } else {
1594     + if (fp == stdin && feof(fp)) break; // stdin closed END
1595     + }
1596     + if (tim.tv_usec == 0) { // timeout - anime
1597     + tim.tv_usec = 100000;
1598     + if (bounce_x >= 0) {
1599     + bounce_x += 5;
1600     + if (bounce_x > 160) bounce_x = 0;
1601     + if (bounce_x > 80)
1602     + fb_drawnbar(160 - bounce_x,180 - bounce_x);
1603     + else
1604     + fb_drawnbar(bounce_x, bounce_x + 20);
1605     + }
1606     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1607     + if (spa != NULL && anim_t != 0) {
1608     + --anim_now;
1609     + if (anim_now <= 0) {
1610     + anim_now = anim_t; // wait
1611     + if (anim_n < anim_m) {
1612     + anim_p++;
1613     + if (anim_p > anim_m) anim_p = anim_n;
1614     + } else {
1615     + anim_p--;
1616     + if (anim_p < anim_m) anim_p = anim_n;
1617     + }
1618     + fb_putanim(anim_x,anim_y,anim_p,spa);
1619     + }
1620     + }
1621     #endif
1622     - fb_drawprogressbar(num);
1623     }
1624     - free(num_buf);
1625     }
1626     -
1627     + if (G.spb1 != NULL) free(G.spb1);
1628     + G.spb1 = NULL;
1629     + if (G.spb2 != NULL) free(G.spb2);
1630     + G.spb2 = NULL;
1631     +#if ENABLE_FEATURE_FBSPLASH_TEXT
1632     + if (G.font != NULL) fb_freefont();
1633     + if (G.spt != NULL) free(G.spt);
1634     + G.spt = NULL;
1635     +#endif
1636     +#if ENABLE_FEATURE_FBSPLASH_SPRITES
1637     + if (spa != NULL) free(spa);
1638     +#endif
1639     if (bCursorOff) // restore cursor
1640     full_write(STDOUT_FILENO, "\033[?25h", 6);
1641    
1642     return EXIT_SUCCESS;
1643     }
1644     +#endif
1645     +
1646     diff -Naur busybox-1.20.2/miscutils/fbsplash.cfg busybox-1.20.2-magellan/miscutils/fbsplash.cfg
1647     --- busybox-1.20.2/miscutils/fbsplash.cfg 2012-06-26 15:35:45.000000000 +0200
1648     +++ busybox-1.20.2-magellan/miscutils/fbsplash.cfg 2012-07-13 13:16:33.600982661 +0200
1649     @@ -7,3 +7,13 @@
1650     BAR_R=80
1651     BAR_G=80
1652     BAR_B=130
1653     +# the below settings are active only if you enable the option FBSPLASH_TEXT_RENDERING
1654     +# text position
1655     +#TEXT_LEFT=100
1656     +#TEXT_TOP=350
1657     +## text color
1658     +#TEXT_R=80
1659     +#TEXT_G=80
1660     +#TEXT_B=130
1661     +## text size (1 to 4)
1662     +#TEXT_SIZE=2