Browse Source

* Updated the caca export format so that it supports multiple frames.

* Updated the caca importer to reflect that; only one frame is read at the
    moment.
  * Added an "utf8cr" export format for UTF-8 + CRLF exports.
  * Updated cacaserver to reflect file format changes.
tags/v0.99.beta14
Sam Hocevar sam 18 years ago
parent
commit
98ee92b2d0
3 changed files with 179 additions and 62 deletions
  1. +106
    -28
      cucul/export.c
  2. +59
    -21
      cucul/import.c
  3. +14
    -13
      src/cacaserver.c

+ 106
- 28
cucul/export.c View File

@@ -31,9 +31,25 @@
#include "cucul.h"
#include "cucul_internals.h"

static inline int sprintu32(char *s, uint32_t x)
{
s[0] = (uint8_t)(x >> 24);
s[1] = (uint8_t)(x >> 16) & 0xff;
s[2] = (uint8_t)(x >> 8) & 0xff;
s[3] = (uint8_t)(x ) & 0xff;
return 4;
}

static inline int sprintu16(char *s, uint16_t x)
{
s[0] = (uint8_t)(x >> 8) & 0xff;
s[1] = (uint8_t)(x ) & 0xff;
return 2;
}

static int export_caca(cucul_canvas_t *, cucul_buffer_t *);
static int export_ansi(cucul_canvas_t *, cucul_buffer_t *);
static int export_utf8(cucul_canvas_t *, cucul_buffer_t *);
static int export_utf8(cucul_canvas_t *, cucul_buffer_t *, int);
static int export_html(cucul_canvas_t *, cucul_buffer_t *);
static int export_html3(cucul_canvas_t *, cucul_buffer_t *);
static int export_irc(cucul_canvas_t *, cucul_buffer_t *);
@@ -90,7 +106,9 @@ cucul_buffer_t * cucul_export_canvas(cucul_canvas_t *cv, char const *format)
else if(!strcasecmp("ansi", format))
ret = export_ansi(cv, ex);
else if(!strcasecmp("utf8", format))
ret = export_utf8(cv, ex);
ret = export_utf8(cv, ex, 0);
else if(!strcasecmp("utf8cr", format))
ret = export_utf8(cv, ex, 1);
else if(!strcasecmp("html", format))
ret = export_html(cv, ex);
else if(!strcasecmp("html3", format))
@@ -134,6 +152,7 @@ char const * const * cucul_get_export_list(void)
"caca", "native libcaca format",
"ansi", "ANSI",
"utf8", "UTF-8 with ANSI escape codes",
"utf8cr", "UTF-8 with ANSI escape codes and MS-DOS \\r",
"html", "HTML",
"html3", "backwards-compatible HTML",
"irc", "IRC with mIRC colours",
@@ -156,45 +175,104 @@ static int export_caca(cucul_canvas_t *cv, cucul_buffer_t *ex)
uint32_t *attrs = cv->attrs;
uint32_t *chars = cv->chars;
char *cur;
uint32_t w, h;
unsigned int n;

/* 16 bytes for the canvas, 8 bytes for each character cell. */
ex->size = 16 + 8 * cv->width * cv->height;
/* 44 bytes for the header:
* - 4 bytes for "\xCA\xCA" + "CV"
* - 16 bytes for the canvas header
* - 24 bytes for the frame info
* 8 bytes for each character cell */
ex->size = 44 + 8 * cv->width * cv->height;
ex->data = malloc(ex->size);

cur = ex->data;

w = cv->width;
h = cv->height;

cur += sprintf(cur, "CACACANV%c%c%c%c%c%c%c%c",
(unsigned char)(w >> 24), (unsigned char)((w >> 16) & 0xff),
(unsigned char)((w >> 8) & 0xff), (unsigned char)(w & 0xff),
(unsigned char)(h >> 24), (unsigned char)((h >> 16) & 0xff),
(unsigned char)((h >> 8) & 0xff), (unsigned char)(h & 0xff));

/* magic */
cur += sprintf(cur, "%s", "\xCA\xCA" "CV");

/* canvas_header */
cur += sprintu32(cur, 16 + 24);
cur += sprintu32(cur, cv->width * cv->height * 8);
cur += sprintu16(cur, 0x0001);
cur += sprintu32(cur, 1);
cur += sprintu16(cur, 0x0000);

/* frame_info */
cur += sprintu32(cur, cv->width);
cur += sprintu32(cur, cv->height);
cur += sprintu32(cur, 0);
cur += sprintu32(cur, cv->curattr);
cur += sprintu32(cur, 0);
cur += sprintu32(cur, 0);

/* canvas_data */
for(n = cv->height * cv->width; n--; )
{
uint32_t ch = *chars++;
uint32_t a = *attrs++;

*cur++ = ch >> 24;
*cur++ = (ch >> 16) & 0xff;
*cur++ = (ch >> 8) & 0xff;
*cur++ = ch & 0xff;

*cur++ = a >> 24;
*cur++ = (a >> 16) & 0xff;
*cur++ = (a >> 8) & 0xff;
*cur++ = a & 0xff;
cur += sprintu32(cur, *chars++);
cur += sprintu32(cur, *attrs++);
}

return 0;
}

/*
* The libcaca canvas format, version 1
* ------------------------------------
*
* All types are big endian.
*
* struct
* {
* magic:
* uint8_t caca_header[2]; // "\xCA\xCA"
* uint8_t caca_file_type[2]; // "CV"
*
* canvas_header:
* uint32_t control_size; // Control size (canvas_data - canvas_header)
* uint32_t data_size; // Data size (EOF - canvas_data)
*
* uint16_t version; // Canvas format version
* // bit 0: set to 1 if canvas is compatible
* // with version 1 of the format
* // bits 1-15: unused yet, must be 0
*
* uint32_t frames; // Frame count
*
* uint16_t flags; // Feature flags
* // bits 0-15: unused yet, must be 0
*
* frame_info:
* struct
* {
* uint32_t width; // Frame width
* uint32_t height; // Frame height
* uint32_t duration; // Frame duration in milliseconds, 0 to
* // not specify a duration
* uint32_t attr; // Graphics context attribute
* int32_t handle_x; // Handle X coordinate
* int32_t handle_y; // Handle Y coordinate
* }
* frame_list[frames];
*
* control_extension_1:
* control_extension_2:
* ...
* control_extension_N:
* ... // reserved for future use
*
* canvas_data:
* uint8_t data[data_size]; // canvas data
*
* data_extension_1:
* data_extension_2:
* ...
* data_extension_N:
* ... // reserved for future use
* };
*/

/* Generate UTF-8 representation of current canvas. */
static int export_utf8(cucul_canvas_t *cv, cucul_buffer_t *ex)
static int export_utf8(cucul_canvas_t *cv, cucul_buffer_t *ex, int cr)
{
static uint8_t const palette[] =
{
@@ -262,7 +340,7 @@ static int export_utf8(cucul_canvas_t *cv, cucul_buffer_t *ex)
if(prevfg != 0x10 || prevbg != 0x10)
cur += sprintf(cur, "\033[0m");

cur += sprintf(cur, "\n");
cur += sprintf(cur, cr ? "\r\n" : "\n");
}

/* Crop to really used size */


+ 59
- 21
cucul/import.c View File

@@ -22,6 +22,11 @@
# if defined(HAVE_ERRNO_H)
# include <errno.h>
# endif
# if defined(HAVE_ARPA_INET_H)
# include <arpa/inet.h>
# elif defined(HAVE_NETINET_IN_H)
# include <netinet/in.h>
# endif
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
@@ -30,6 +35,20 @@
#include "cucul.h"
#include "cucul_internals.h"

static inline uint32_t sscanu32(void const *s)
{
uint32_t x;
memcpy(&x, s, 4);
return ntohl(x);
}

static inline uint16_t sscanu16(void const *s)
{
uint16_t x;
memcpy(&x, s, 2);
return ntohs(x);
}

/* ANSI Graphic Rendition Combination Mode */
struct ansi_grcm
{
@@ -85,8 +104,8 @@ cucul_canvas_t * cucul_import_canvas(cucul_buffer_t *buffer, char const *format)
unsigned int i;

/* If 4 first letters are CACA */
if(buffer->size >= 4 &&
buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
if(buffer->size >= 4 && (uint8_t)buf[0] == 0xca &&
(uint8_t)buf[1] == 0xca && buf[2] == 'C' && buf[3] == 'V')
return import_caca(buffer->data, buffer->size);

/* If we find ESC[ argv, we guess it's an ANSI file */
@@ -137,26 +156,49 @@ static cucul_canvas_t *import_caca(void const *data, unsigned int size)
{
cucul_canvas_t *cv;
uint8_t const *buf = (uint8_t const *)data;
unsigned int width, height, n;
unsigned int control_size, data_size, full_size, frames, f, n;
uint16_t version, flags;

if(size < 16)
if(size < 20)
goto invalid_caca;

if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
if(buf[0] != 0xca || buf[1] != 0xca || buf[2] != 'C' || buf[3] != 'V')
goto invalid_caca;

if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V')
control_size = sscanu32(buf + 4);
data_size = sscanu32(buf + 8);
version = sscanu16(buf + 12);
frames = sscanu32(buf + 14);
flags = sscanu16(buf + 18);

if(size != 4 + control_size + data_size)
goto invalid_caca;

width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
| ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
height = ((uint32_t)buf[12] << 24) | ((uint32_t)buf[13] << 16)
| ((uint32_t)buf[14] << 8) | (uint32_t)buf[15];
if(control_size < 16 + frames * 24)
goto invalid_caca;

if(size != 16 + width * height * 8)
for(full_size = 0, f = 0; f < frames; f++)
{
unsigned int width, height, duration;
uint32_t attr;
int x, y;

width = sscanu32(buf + 4 + 16 + f * 24);
height = sscanu32(buf + 4 + 16 + f * 24 + 4);
duration = sscanu32(buf + 4 + 16 + f * 24 + 8);
attr = sscanu32(buf + 4 + 16 + f * 24 + 12);
x = (int32_t)sscanu32(buf + 4 + 16 + f * 24 + 16);
y = (int32_t)sscanu32(buf + 4 + 16 + f * 24 + 20);

full_size += width * height * 8;
}

if(full_size != data_size)
goto invalid_caca;

cv = cucul_create_canvas(width, height);
/* FIXME: read all frames, not only the first one */
cv = cucul_create_canvas(sscanu32(buf + 4 + 16),
sscanu32(buf + 4 + 16 + 4));

if(!cv)
{
@@ -166,18 +208,14 @@ static cucul_canvas_t *import_caca(void const *data, unsigned int size)
return NULL;
}

for(n = height * width; n--; )
for(n = sscanu32(buf + 4 + 16) * sscanu32(buf + 4 + 16 + 4); n--; )
{
cv->chars[n] = ((uint32_t)buf[16 + 0 + 8 * n] << 24)
| ((uint32_t)buf[16 + 1 + 8 * n] << 16)
| ((uint32_t)buf[16 + 2 + 8 * n] << 8)
| (uint32_t)buf[16 + 3 + 8 * n];
cv->attrs[n] = ((uint32_t)buf[16 + 4 + 8 * n] << 24)
| ((uint32_t)buf[16 + 5 + 8 * n] << 16)
| ((uint32_t)buf[16 + 6 + 8 * n] << 8)
| (uint32_t)buf[16 + 7 + 8 * n];
cv->chars[n] = sscanu32(buf + 4 + control_size + 8 * n);
cv->attrs[n] = sscanu32(buf + 4 + control_size + 8 * n + 4);
}

cv->curattr = sscanu32(buf + 4 + 16 + 12);

return cv;

invalid_caca:


+ 14
- 13
src/cacaserver.c View File

@@ -142,7 +142,7 @@ int main(void)
#endif
server = malloc(sizeof(struct server));

server->input = malloc(16);
server->input = malloc(12);
server->read = 0;

server->client_count = 0;
@@ -206,7 +206,7 @@ int main(void)
{
cucul_buffer_t *b;
uint8_t *buf = server->input;
uint32_t width, height;
uint32_t control_size, data_size;
unsigned int size;

/* Manage new connections as this function will be called sometimes
@@ -214,22 +214,23 @@ int main(void)
manage_connections(server);

/* Read data from stdin */
read(0, buf, 16);
read(0, buf, 12);

while(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
while(buf[0] != 0xca || buf[1] != 0xca
|| buf[2] != 'C' || buf[3] != 'V')
{
memmove(buf, buf + 1, 15);
read(0, buf + 15, 1);
memmove(buf, buf + 1, 11);
read(0, buf + 11, 1);
}

width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
control_size = ((uint32_t)buf[4] << 24) | ((uint32_t)buf[5] << 16)
| ((uint32_t)buf[6] << 8) | (uint32_t)buf[7];
data_size = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
| ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
height = ((uint32_t)buf[12] << 24) | ((uint32_t)buf[13] << 16)
| ((uint32_t)buf[14] << 8) | (uint32_t)buf[15];

size = 16 + width * height * 8;
size = 4 + control_size + data_size;
buf = server->input = realloc(server->input, size);
read(0, buf + 16, size - 16);
read(0, buf + 12, size - 12);

/* Free the previous canvas, if any */
if(server->canvas)
@@ -250,8 +251,8 @@ int main(void)
}

/* Get ANSI representation of the image and skip the end-of buffer
* linefeed ("\r\n", 2 bytes) */
server->buffer = cucul_export_canvas(server->canvas, "utf8");
* linefeed ("\r\n", 2 byte) */
server->buffer = cucul_export_canvas(server->canvas, "utf8cr");
server->bufdata = cucul_get_buffer_data(server->buffer);
server->buflen = cucul_get_buffer_size(server->buffer);
server->buflen -= 2;


Loading…
Cancel
Save