* 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
| @@ -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 */ | |||
| @@ -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: | |||
| @@ -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; | |||