Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

import.c 13 KiB

18 år sedan
18 år sedan
18 år sedan
18 år sedan
18 år sedan
18 år sedan
18 år sedan
18 år sedan
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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$
  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. * This file contains various import functions.
  15. */
  16. #include "config.h"
  17. #include "common.h"
  18. #if !defined(__KERNEL__)
  19. # include <stdio.h>
  20. # include <stdlib.h>
  21. # include <string.h>
  22. #endif
  23. #include "cucul.h"
  24. #include "cucul_internals.h"
  25. static cucul_canvas_t *import_caca(void const *, unsigned int);
  26. static cucul_canvas_t *import_text(void const *, unsigned int);
  27. static cucul_canvas_t *import_ansi(void const *, unsigned int);
  28. /** \brief Import a buffer into a canvas
  29. *
  30. * This function imports a libcucul buffer (cucul_load_memory()/cucul_load_file())
  31. * into an internal libcucul canvas.
  32. *
  33. * Valid values for \c format are:
  34. *
  35. * \li \c "": attempt to autodetect the file format.
  36. *
  37. * \li \c "ansi": import ANSI files.
  38. *
  39. * \li \c "caca": import native libcaca files.
  40. *
  41. * \param buffer A \e libcucul buffer containing the data to be loaded
  42. * into a canvas.
  43. * \param format A string describing the input format.
  44. * \return A libcucul canvas, or NULL in case of error.
  45. */
  46. cucul_canvas_t * cucul_import_canvas(cucul_buffer_t *buffer, char const *format)
  47. {
  48. char const *buf = (char const*)buffer->data;
  49. if(buffer->size == 0 || buffer->data == NULL)
  50. return NULL;
  51. if(!strcasecmp("caca", format))
  52. return import_caca(buffer->data, buffer->size);
  53. if(!strcasecmp("text", format))
  54. return import_text(buffer->data, buffer->size);
  55. if(!strcasecmp("ansi", format))
  56. return import_ansi(buffer->data, buffer->size);
  57. /* Autodetection */
  58. if(!strcasecmp("", format))
  59. {
  60. unsigned int i=0;
  61. /* if 4 first letters are CACA */
  62. if(buffer->size >= 4 &&
  63. buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
  64. return import_caca(buffer->data, buffer->size);
  65. /* If we find ESC[ argv, we guess it's an ANSI file */
  66. while(i < buffer->size - 1)
  67. {
  68. if((buf[i] == 0x1b) && (buf[i+1] == '['))
  69. return import_ansi(buffer->data, buffer->size);
  70. i++;
  71. }
  72. /* Otherwise, import it as text */
  73. return import_text(buffer->data, buffer->size);
  74. }
  75. return NULL;
  76. }
  77. /** \brief Get available import formats
  78. *
  79. * Return a list of available import formats. The list is a NULL-terminated
  80. * array of strings, interleaving a string containing the internal value for
  81. * the import format, to be used with cucul_import_canvas(), and a string
  82. * containing the natural language description for that import format.
  83. *
  84. * \return An array of strings.
  85. */
  86. char const * const * cucul_get_import_list(void)
  87. {
  88. static char const * const list[] =
  89. {
  90. "", "autodetect",
  91. "text", "plain text",
  92. "caca", "native libcaca format",
  93. "ansi", "ANSI coloured text",
  94. NULL, NULL
  95. };
  96. return list;
  97. }
  98. /*
  99. * XXX: the following functions are local.
  100. */
  101. static cucul_canvas_t *import_caca(void const *data, unsigned int size)
  102. {
  103. cucul_canvas_t *cv;
  104. uint8_t const *buf = (uint8_t const *)data;
  105. unsigned int width, height, n;
  106. if(size < 16)
  107. return NULL;
  108. if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
  109. return NULL;
  110. if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V')
  111. return NULL;
  112. width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
  113. | ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
  114. height = ((uint32_t)buf[12] << 24) | ((uint32_t)buf[13] << 16)
  115. | ((uint32_t)buf[14] << 8) | (uint32_t)buf[15];
  116. if(!width || !height)
  117. return NULL;
  118. if(size != 16 + width * height * 8)
  119. return NULL;
  120. cv = cucul_create_canvas(width, height);
  121. if(!cv)
  122. return NULL;
  123. for(n = height * width; n--; )
  124. {
  125. cv->chars[n] = ((uint32_t)buf[16 + 0 + 8 * n] << 24)
  126. | ((uint32_t)buf[16 + 1 + 8 * n] << 16)
  127. | ((uint32_t)buf[16 + 2 + 8 * n] << 8)
  128. | (uint32_t)buf[16 + 3 + 8 * n];
  129. cv->attr[n] = ((uint32_t)buf[16 + 4 + 8 * n] << 24)
  130. | ((uint32_t)buf[16 + 5 + 8 * n] << 16)
  131. | ((uint32_t)buf[16 + 6 + 8 * n] << 8)
  132. | (uint32_t)buf[16 + 7 + 8 * n];
  133. }
  134. return cv;
  135. }
  136. static cucul_canvas_t *import_text(void const *data, unsigned int size)
  137. {
  138. cucul_canvas_t *cv;
  139. char const *text = (char const *)data;
  140. unsigned int width = 1, height = 1, x = 0, y = 0, i;
  141. cv = cucul_create_canvas(width, height);
  142. cucul_set_color(cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_TRANSPARENT);
  143. for(i = 0; i < size; i++)
  144. {
  145. unsigned char ch = *text++;
  146. if(ch == '\r')
  147. continue;
  148. if(ch == '\n')
  149. {
  150. x = 0;
  151. y++;
  152. continue;
  153. }
  154. if(x >= width || y >= height)
  155. {
  156. if(x >= width)
  157. width = x + 1;
  158. if(y >= height)
  159. height = y + 1;
  160. cucul_set_canvas_size(cv, width, height);
  161. }
  162. cucul_putchar(cv, x, y, ch);
  163. x++;
  164. }
  165. return cv;
  166. }
  167. static void manage_modifiers(int, uint8_t *, uint8_t *, uint8_t *,
  168. uint8_t *, uint8_t *, uint8_t *);
  169. static cucul_canvas_t *import_ansi(void const *data, unsigned int size)
  170. {
  171. cucul_canvas_t *cv;
  172. unsigned char const *buffer = (unsigned char const*)data;
  173. unsigned int i, j;
  174. int x = 0, y = 0;
  175. unsigned int width = 80, height = 25;
  176. int save_x = 0, save_y = 0;
  177. unsigned int skip;
  178. uint8_t fg, bg, save_fg, save_bg, bold, reverse;
  179. fg = save_fg = CUCUL_COLOR_LIGHTGRAY;
  180. bg = save_bg = CUCUL_COLOR_BLACK;
  181. bold = reverse = 0;
  182. cv = cucul_create_canvas(width, height);
  183. cucul_set_color(cv, fg, bg);
  184. for(i = 0; i < size; i += skip)
  185. {
  186. skip = 1;
  187. if(buffer[i] == '\x1a' && size - i >= 8
  188. && !memcmp(buffer + i + 1, "SAUCE00", 7))
  189. break; /* End before SAUCE data */
  190. if(buffer[i] == '\r')
  191. continue; /* DOS sucks */
  192. if(buffer[i] == '\n')
  193. {
  194. x = 0;
  195. y++;
  196. continue;
  197. }
  198. /* Interpret escape commands, as per Standard ECMA-48 "Control
  199. * Functions for Coded Character Sets", 5.4. Control sequences. */
  200. if(buffer[i] == '\x1b' && buffer[i + 1] == '[')
  201. {
  202. unsigned int argc = 0, argv[101];
  203. unsigned int param, inter, final;
  204. /* Compute offsets to parameter bytes, intermediate bytes and
  205. * to the final byte. Only the final byte is mandatory, there
  206. * can be zero of the others.
  207. *
  208. * +-----+------------------+---------------------+-----------------+
  209. * | CSI | parameter bytes | intermediate bytes | final byte |
  210. * | | 0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e |
  211. * | ^[[ | 0123456789:;<=>? | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |
  212. * +-----+------------------+---------------------+-----------------+
  213. */
  214. param = 2;
  215. for(inter = param; i + inter < size; inter++)
  216. if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
  217. break;
  218. for(final = inter; i + final < size; final++)
  219. if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
  220. break;
  221. if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
  222. break; /* Invalid Final Byte */
  223. skip += final;
  224. /* Sanity checks */
  225. if(param < inter && buffer[i + param] >= 0x3c)
  226. {
  227. //fprintf(stderr, "private sequence \"^[[%.*s\"\n",
  228. // final - param + 1, buffer + i + param);
  229. continue; /* Private sequence, skip it entirely */
  230. }
  231. if(final - param > 100)
  232. continue; /* Suspiciously long sequence, skip it */
  233. /* ECMA-48 5.4.2: Parameter string format */
  234. if(param < inter)
  235. {
  236. argv[0] = 0;
  237. for(j = param; j < inter; j++)
  238. {
  239. if(buffer[i + j] == ';')
  240. argv[++argc] = 0;
  241. else if(buffer[i + j] >= '0' && buffer[i + j] <= '9')
  242. argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
  243. }
  244. argc++;
  245. }
  246. /* Interpret final byte. The code representations are given in
  247. * ECMA-48 5.4: Control sequences, and the code definitions are
  248. * given in ECMA-48 8.3: Definition of control functions. */
  249. switch(buffer[i + final])
  250. {
  251. case 'f': /* CUP - Cursor Position */
  252. case 'H': /* HVP - Character And Line Position */
  253. x = (argc > 1) ? argv[1] - 1 : 0;
  254. y = (argc > 0) ? argv[0] - 1 : 0;
  255. break;
  256. case 'A': /* CUU - Cursor Up */
  257. y -= argc ? argv[0] : 1;
  258. if(y < 0)
  259. y = 0;
  260. break;
  261. case 'B': /* CUD - Cursor Down */
  262. y += argc ? argv[0] : 1;
  263. break;
  264. case 'C': /* CUF - Cursor Right */
  265. x += argc ? argv[0] : 1;
  266. break;
  267. case 'D': /* CUB - Cursor Left */
  268. x -= argc ? argv[0] : 1;
  269. if(x < 0)
  270. x = 0;
  271. break;
  272. case 's': /* Private (save cursor position) */
  273. save_x = x;
  274. save_y = y;
  275. break;
  276. case 'u': /* Private (reload cursor positin) */
  277. x = save_x;
  278. y = save_y;
  279. break;
  280. case 'J': /* ED - Erase In Page */
  281. if(argv[0] == 2)
  282. x = y = 0;
  283. break;
  284. case 'K': /* EL - Erase In Line */
  285. for(j = x; j < width; j++)
  286. _cucul_putchar32(cv, j, y, (uint32_t)' ');
  287. x = width;
  288. break;
  289. case 'm': /* SGR - Select Graphic Rendition */
  290. for(j = 0; j < argc; j++)
  291. manage_modifiers(argv[j], &fg, &bg,
  292. &save_fg, &save_bg, &bold, &reverse);
  293. if(bold && fg < 8)
  294. fg += 8;
  295. if(reverse)
  296. cucul_set_color(cv, bg, fg);
  297. else
  298. cucul_set_color(cv, fg, bg);
  299. break;
  300. default:
  301. break;
  302. }
  303. continue;
  304. }
  305. /* We're going to paste a character. First make sure the canvas
  306. * is big enough. */
  307. if((unsigned int)x >= width)
  308. {
  309. x = 0;
  310. y++;
  311. }
  312. if((unsigned int)y >= height)
  313. {
  314. height = y + 1;
  315. cucul_set_canvas_size(cv, width, height);
  316. }
  317. /* Now paste our character */
  318. _cucul_putchar32(cv, x, y,_cucul_cp437_to_utf32(buffer[i]));
  319. x++;
  320. }
  321. return cv;
  322. }
  323. /* XXX : ANSI loader helper */
  324. static void manage_modifiers(int i, uint8_t *fg, uint8_t *bg, uint8_t *save_fg,
  325. uint8_t *save_bg, uint8_t *bold, uint8_t *reverse)
  326. {
  327. static uint8_t const ansi2cucul[] =
  328. {
  329. CUCUL_COLOR_BLACK,
  330. CUCUL_COLOR_RED,
  331. CUCUL_COLOR_GREEN,
  332. CUCUL_COLOR_BROWN,
  333. CUCUL_COLOR_BLUE,
  334. CUCUL_COLOR_MAGENTA,
  335. CUCUL_COLOR_CYAN,
  336. CUCUL_COLOR_LIGHTGRAY
  337. };
  338. if(i >= 30 && i <= 37)
  339. *fg = ansi2cucul[i - 30];
  340. else if(i >= 40 && i <= 47)
  341. *bg = ansi2cucul[i - 40];
  342. else if(i >= 90 && i <= 97)
  343. *fg = ansi2cucul[i - 90] + 8;
  344. else if(i >= 100 && i <= 107)
  345. *bg = ansi2cucul[i - 100] + 8;
  346. else switch(i)
  347. {
  348. case 0:
  349. *fg = CUCUL_COLOR_DEFAULT;
  350. *bg = CUCUL_COLOR_DEFAULT;
  351. *bold = 0;
  352. *reverse = 0;
  353. break;
  354. case 1: /* BOLD */
  355. *bold = 1;
  356. break;
  357. case 4: // Underline
  358. break;
  359. case 5: // blink
  360. break;
  361. case 7: // reverse
  362. *reverse = 1;
  363. break;
  364. case 8: // invisible
  365. *save_fg = *fg;
  366. *save_bg = *bg;
  367. *fg = CUCUL_COLOR_TRANSPARENT;
  368. *bg = CUCUL_COLOR_TRANSPARENT;
  369. break;
  370. case 28: // not invisible
  371. *fg = *save_fg;
  372. *bg = *save_bg;
  373. break;
  374. case 39:
  375. *fg = CUCUL_COLOR_DEFAULT;
  376. break;
  377. case 49:
  378. *bg = CUCUL_COLOR_DEFAULT;
  379. break;
  380. default:
  381. break;
  382. }
  383. }