source: libcaca/trunk/cucul/import.c @ 871

Last change on this file since 871 was 871, checked in by Jean-Yves Lamoureux, 15 years ago
  • Added preliminary ANSI importer, added import formats autodection
  • Property svn:keywords set to Id
File size: 14.8 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: import.c 871 2006-04-25 10:14:12Z jylam $
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14/*
15 *  This file contains various import functions.
16 */
17
18#include "config.h"
19#include "common.h"
20
21#if !defined(__KERNEL__)
22#   include <stdio.h>
23#   include <stdlib.h>
24#   include <string.h>
25#endif
26
27#include "cucul.h"
28#include "cucul_internals.h"
29
30static cucul_canvas_t *import_caca(void const *, unsigned int);
31static cucul_canvas_t *import_text(void const *, unsigned int);
32static cucul_canvas_t *import_ansi(void const *, unsigned int);
33
34/** \brief Import a buffer into a canvas
35 *
36 *  This function imports a memory area into an internal libcucul canvas.
37 *
38 *  Valid values for \c format are:
39 *
40 *  \li \c "": attempt to autodetect the file format.
41 *
42 *  \li \c "caca": import native libcaca files.
43 *
44 *  \param data The memory area to be loaded into a canvas.
45 *  \param size The length of the memory area.
46 *  \param format A string describing the input format.
47 *  \return A libcucul canvas, or NULL in case of error.
48 */
49cucul_canvas_t * cucul_import_canvas(void const *data, unsigned int size,
50                                     char const *format)
51{
52    char const *buf = (char const*) data;
53
54    if(size==0 || data==NULL)
55        return NULL;
56
57    if(!strcasecmp("caca", format))
58        return import_caca(data, size);
59    if(!strcasecmp("text", format))
60        return import_text(data, size);
61    if(!strcasecmp("ansi", format))
62        return import_ansi(data, size);
63
64    if(!strcasecmp("", format))
65    {
66        /* Autodetection */
67        if(size>=4) /* if 4 first letters are CACA */
68        {
69            if(buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
70               return import_caca(data, size);
71        }
72        if(size>=2) /* If 2 first characters are ESC[ (not reliable at all) */
73        {
74            if((buf[0] == 0x1b) && (buf[1] == '['))
75               return import_ansi(data, size);
76        }
77        /* Otherwise, import it as text */
78        return import_caca(data, size);
79    }
80    return NULL;
81}
82
83/** \brief Get available import formats
84 *
85 *  Return a list of available import formats. The list is a NULL-terminated
86 *  array of strings, interleaving a string containing the internal value for
87 *  the import format, to be used with cucul_import_canvas(), and a string
88 *  containing the natural language description for that import format.
89 *
90 *  \return An array of strings.
91 */
92char const * const * cucul_get_import_list(void)
93{
94    static char const * const list[] =
95    {
96        "", "autodetect",
97        "text", "plain text",
98        "caca", "native libcaca format",
99        "ansi", "ANSI coloured text",
100        NULL, NULL
101    };
102
103    return list;
104}
105
106/*
107 * XXX: the following functions are local.
108 */
109
110static cucul_canvas_t *import_caca(void const *data, unsigned int size)
111{
112    cucul_canvas_t *cv;
113    uint8_t const *buf = (uint8_t const *)data;
114    unsigned int width, height, n;
115
116    if(size < 16)
117        return NULL;
118
119    if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
120        return NULL;
121
122    if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V')
123        return NULL;
124
125    width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
126           | ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
127    height = ((uint32_t)buf[12] << 24) | ((uint32_t)buf[13] << 16)
128            | ((uint32_t)buf[14] << 8) | (uint32_t)buf[15];
129
130    if(!width || !height)
131        return NULL;
132
133    if(size != 16 + width * height * 8)
134        return NULL;
135
136    cv = cucul_create_canvas(width, height);
137
138    if(!cv)
139        return NULL;
140
141    for(n = height * width; n--; )
142    {
143        cv->chars[n] = ((uint32_t)buf[16 + 0 + 8 * n] << 24)
144                     | ((uint32_t)buf[16 + 1 + 8 * n] << 16)
145                     | ((uint32_t)buf[16 + 2 + 8 * n] << 8)
146                     | (uint32_t)buf[16 + 3 + 8 * n];
147        cv->attr[n] = ((uint32_t)buf[16 + 4 + 8 * n] << 24)
148                    | ((uint32_t)buf[16 + 5 + 8 * n] << 16)
149                    | ((uint32_t)buf[16 + 6 + 8 * n] << 8)
150                    | (uint32_t)buf[16 + 7 + 8 * n];
151    }
152
153    return cv;
154}
155
156static cucul_canvas_t *import_text(void const *data, unsigned int size)
157{
158    cucul_canvas_t *cv;
159    char const *text = (char const *)data;
160    unsigned int width = 1, height = 1, x = 0, y = 0, i;
161
162    cv = cucul_create_canvas(width, height);
163    cucul_set_color(cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_TRANSPARENT);
164
165    for(i = 0; i < size; i++)
166    {
167        unsigned char ch = *text++;
168
169        if(ch == '\r')
170            continue;
171
172        if(ch == '\n')
173        {
174            x = 0;
175            y++;
176            continue;
177        }
178
179        while(x >= width)
180        {
181            width++;
182            cucul_set_canvas_size(cv, width, height);
183        }
184
185        while(y >= height)
186        {
187            height++;
188            cucul_set_canvas_size(cv, width, height);
189        }
190
191        cucul_putchar(cv, x, y, ch);
192        x++;
193    }
194
195    return cv;
196}
197
198#define IS_ALPHA(x) (x>='A' && x<='z')
199void updateCanvasSize(cucul_canvas_t *cv, int x, int y, int *max_x, int *max_y);
200unsigned char get_ansi_command(unsigned char const *buffer, int size);
201int parse_tuple(unsigned int *ret, unsigned char const *buffer, int size);
202void manage_modifiers(char c, int *fg, int *bg, int *old_fg, int *old_bg);
203
204static cucul_canvas_t *import_ansi(void const *data, unsigned int size)
205{
206    cucul_canvas_t *cv;
207    unsigned char const *buffer = (unsigned char const*)data;
208    unsigned int i, sent_size=0;
209    unsigned char c;
210    unsigned int count=0;
211    unsigned int tuple[1024]; /* Should be enough. Will it be ? */
212    int x=0, y=0, max_x = 80, max_y = 25;
213    int save_x=0, save_y=0;
214    unsigned int j, add=0;
215    int fg, bg, old_fg, old_bg;
216
217    fg = old_fg = CUCUL_COLOR_LIGHTGRAY;
218    bg = old_bg = CUCUL_COLOR_BLACK;
219
220    cv = cucul_create_canvas(max_x, max_y);
221
222    for(i = 0 ;i < size; i++)
223        {
224            if((buffer[i] == 0x1b) && (buffer[i+1] == '['))  /* ESC code */
225                {
226                    i++; // ESC
227                    i++; // [
228                    sent_size = size-i;
229                    c = get_ansi_command(&buffer[i], sent_size);
230                    add = parse_tuple(tuple, &buffer[i], sent_size);
231                    count = 0;
232
233                    while(tuple[count] != 0x1337)  count++;  /* Gruik */
234
235
236                    switch(c)
237                        {
238                        case 'f':
239                        case 'H':
240                            if(tuple[0] != 0x1337)
241                                {
242                                    x=tuple[0];
243                                    if(tuple[1] != 0x1337)
244                                        y=tuple[1];
245                                }
246                            else
247                                {
248                                    x = 0;
249                                    y = 0;
250                                }
251                            updateCanvasSize(cv, x, y, &max_x, &max_y);
252                            break;
253                        case 'A':
254                            if(tuple[0] == 0x1337)
255                                y-=1;
256                            else
257                                y-=tuple[0];
258                            if(y<0) y=0;
259                            updateCanvasSize(cv, x, y, &max_x, &max_y);
260                            break;
261                        case 'B':
262                            if(tuple[0] == 0x1337)
263                                y++;
264                            else
265                                y+=tuple[0];
266                            updateCanvasSize(cv, x, y, &max_x, &max_y);
267                            break;
268                        case 'C':
269                            if(tuple[0] == 0x1337)
270                                x++;
271                            else
272                                x+=tuple[0];
273                            updateCanvasSize(cv, x, y, &max_x, &max_y);
274                            break;
275                        case 'D':
276                            if(tuple[0] == 0x1337)
277                                x--;
278                            else
279                                x-=tuple[0];
280                            if(x<0) x=0;
281                            updateCanvasSize(cv, x, y, &max_x, &max_y);
282                            break;
283                        case 's':
284                            save_x = x;
285                            save_y = y;
286                            break;
287                        case 'u':
288                            x = save_x;
289                            y = save_y;
290                            updateCanvasSize(cv, x, y, &max_x, &max_y);
291                            break;
292                        case 'J':
293                            if(tuple[0] == 2)
294                                {
295                                    x = 0;
296                                    y = 0;
297                                    updateCanvasSize(cv, x, y, &max_x, &max_y);
298                                }
299                            break;
300                        case 'K':
301                            // CLEAR END OF LINE
302                            break;
303                        case 'm':
304                            for(j=0; j < count; j++)
305                                manage_modifiers(tuple[j], &fg, &bg, &old_fg, &old_bg);
306                            cucul_set_color(cv, fg, bg);
307                            break;
308                        default:
309                            /*printf("Unknow command %c (%c)\n", c, IS_ALPHA(c)?c:'.');*/
310                            break;
311                        }
312
313
314                } else {
315                    if(buffer[i] == '\n')
316                        {
317                            x = 0;
318                            y++;
319                            updateCanvasSize(cv, x, y, &max_x, &max_y);
320                        }
321                    else if(buffer[i] == '\r')
322                        {
323                            // DOS sucks.
324                        }
325                    else
326                        {
327                            if((buffer[i]>=0x20) || (buffer[i]<=0x7E))
328                                {
329                                    _cucul_putchar32(cv, x, y,_cucul_cp437_to_utf32(buffer[i]));
330
331                                    //  cucul_putchar(cv, x, y, buffer[i]);
332                                }
333                            else
334                                cucul_putchar(cv, x, y, '?');
335                            x++;
336                            updateCanvasSize(cv, x, y, &max_x, &max_y);
337                        }
338                }
339
340
341
342            i+=add; // add is tuple char count, then +[ +command
343            add = 0;
344
345        }
346    return cv;
347}
348
349/* XXX : ANSI loader helpers */
350
351unsigned char get_ansi_command(unsigned char const *buffer, int size)
352{
353    int i = 0;
354
355    for(i=0; i < size; i++)
356        if(IS_ALPHA(buffer[i]))
357            return buffer[i];
358
359    return 0;
360}
361
362int parse_tuple(unsigned int *ret, unsigned char const *buffer, int size)
363{
364    int i = 0;
365    int j = 0;
366    int t = 0;
367    unsigned char nbr[1024];
368
369
370    ret[0] = 0x1337;
371
372    for(i=0; i < size; i++)
373        {
374            if(IS_ALPHA(buffer[i]))
375                {
376                    if(j!=0) {
377                        ret[t] = atoi((char*)nbr);
378                        t++;
379                    }
380                    ret[t] = 0x1337;
381                    j=0;
382                    return i;
383                }
384            if(buffer[i] != ';')
385                {
386                    nbr[j] = buffer[i];
387                    nbr[j+1] = 0;
388                    j++;
389                } else
390                    {
391                        ret[t] = atoi((char*)nbr);
392                        t++;
393                        ret[t] = 0x1337;
394                        j=0;
395                    }
396        }
397    return size;
398}
399
400
401
402void manage_modifiers(char c, int *fg, int *bg, int *old_fg, int *old_bg)
403{
404    switch(c) {
405    case 0:
406        *fg = CUCUL_COLOR_LIGHTGRAY;
407        *bg = CUCUL_COLOR_BLACK;
408        break;
409    case 1: // BOLD
410
411        break;
412    case 4: // Underline
413
414        break;
415    case 5: // blink
416
417        break;
418    case 7: // reverse
419        *fg = 15-*fg;
420        *bg = 15-*bg;
421        break;
422    case 8: // invisible
423        *old_fg = *fg;
424        *old_bg = *bg;
425        *fg = CUCUL_COLOR_TRANSPARENT;
426        *bg = CUCUL_COLOR_TRANSPARENT;
427        break;
428    case 28: // not invisible
429        *fg = *old_fg;
430        *bg = *old_bg;
431        break;
432    case 30:
433        *fg = CUCUL_COLOR_BLACK;
434        break;
435    case 31:
436        *fg = CUCUL_COLOR_RED;
437        break;
438    case 32:
439        *fg = CUCUL_COLOR_GREEN;
440        break;
441    case 33:
442        *fg = CUCUL_COLOR_BROWN;
443        break;
444    case 34:
445        *fg = CUCUL_COLOR_BLUE;
446        break;
447    case 35:
448        *fg = CUCUL_COLOR_MAGENTA;
449        break;
450    case 36:
451        *fg = CUCUL_COLOR_CYAN;
452        break;
453    case 37:
454        *fg = CUCUL_COLOR_WHITE;
455        break;
456    case 39:
457        *fg = CUCUL_COLOR_LIGHTGRAY;
458        break;
459    case 40:
460        *bg = CUCUL_COLOR_BLACK;
461        break;
462    case 41:
463        *bg = CUCUL_COLOR_RED;
464        break;
465    case 42:
466        *bg = CUCUL_COLOR_GREEN;
467        break;
468    case 43:
469        *bg = CUCUL_COLOR_BROWN;
470        break;
471    case 44:
472        *bg = CUCUL_COLOR_BLUE;
473        break;
474    case 45:
475        *bg = CUCUL_COLOR_MAGENTA;
476        break;
477    case 46:
478        *bg = CUCUL_COLOR_CYAN;
479        break;
480    case 47:
481        *bg = CUCUL_COLOR_WHITE;
482        break;
483    case 49:
484        *bg = CUCUL_COLOR_BLACK;
485        break;
486
487    case 90:
488        *fg = CUCUL_COLOR_DARKGRAY;
489        break;
490    case 91:
491        *fg = CUCUL_COLOR_LIGHTRED;
492        break;
493    case 92:
494        *fg = CUCUL_COLOR_LIGHTGREEN;
495        break;
496    case 93:
497        *fg = CUCUL_COLOR_YELLOW;
498        break;
499    case 94:
500        *fg = CUCUL_COLOR_LIGHTBLUE;
501        break;
502    case 95:
503        *fg = CUCUL_COLOR_LIGHTMAGENTA;
504        break;
505    case 96:
506        *fg = CUCUL_COLOR_LIGHTCYAN;
507        break;
508    case 97:
509        *fg = CUCUL_COLOR_WHITE;
510        break;
511    case 100:
512        *bg = CUCUL_COLOR_DARKGRAY;
513        break;
514    case 101:
515        *bg = CUCUL_COLOR_LIGHTRED;
516        break;
517    case 102:
518        *bg = CUCUL_COLOR_LIGHTGREEN;
519        break;
520    case 103:
521        *bg = CUCUL_COLOR_YELLOW;
522        break;
523    case 104:
524        *bg = CUCUL_COLOR_LIGHTBLUE;
525        break;
526    case 105:
527        *bg = CUCUL_COLOR_LIGHTMAGENTA;
528        break;
529    case 106:
530        *bg = CUCUL_COLOR_LIGHTCYAN;
531        break;
532    case 107:
533        *bg = CUCUL_COLOR_WHITE;
534        break;
535    default:
536        /*   printf("Unknow option to 'm' %d (%c)\n", c, IS_ALPHA(c)?c:'.'); */
537        break;
538
539    }
540}
541
542
543void updateCanvasSize(cucul_canvas_t *cv, int x, int y, int *max_x, int *max_y)
544{
545    if(x>*max_x) *max_x = x;
546    if(y>*max_y) *max_y = y;
547
548    cucul_set_canvas_size(cv, *max_x, *max_y);
549}
Note: See TracBrowser for help on using the repository browser.