You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
преди 19 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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 memory area into an internal libcucul canvas.
  31. *
  32. * Valid values for \c format are:
  33. *
  34. * \li \c "": attempt to autodetect the file format.
  35. *
  36. * \li \c "ansi": import ANSI files.
  37. *
  38. * \li \c "caca": import native libcaca files.
  39. *
  40. * \param data The memory area to be loaded into a canvas.
  41. * \param size The length of the memory area.
  42. * \param format A string describing the input format.
  43. * \return A libcucul canvas, or NULL in case of error.
  44. */
  45. cucul_canvas_t * cucul_import_canvas(void const *data, unsigned int size,
  46. char const *format)
  47. {
  48. char const *buf = (char const*) data;
  49. if(size==0 || data==NULL)
  50. return NULL;
  51. if(!strcasecmp("caca", format))
  52. return import_caca(data, size);
  53. if(!strcasecmp("text", format))
  54. return import_text(data, size);
  55. if(!strcasecmp("ansi", format))
  56. return import_ansi(data, size);
  57. /* Autodetection */
  58. if(!strcasecmp("", format))
  59. {
  60. /* if 4 first letters are CACA */
  61. if(size >= 4 &&
  62. buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
  63. return import_caca(data, size);
  64. /* If 2 first characters are ESC[ (not reliable at all) */
  65. if(size >= 2 && buf[0] == 0x1b && buf[1] == '[')
  66. return import_ansi(data, size);
  67. /* Otherwise, import it as text */
  68. return import_text(data, size);
  69. }
  70. return NULL;
  71. }
  72. /** \brief Get available import formats
  73. *
  74. * Return a list of available import formats. The list is a NULL-terminated
  75. * array of strings, interleaving a string containing the internal value for
  76. * the import format, to be used with cucul_import_canvas(), and a string
  77. * containing the natural language description for that import format.
  78. *
  79. * \return An array of strings.
  80. */
  81. char const * const * cucul_get_import_list(void)
  82. {
  83. static char const * const list[] =
  84. {
  85. "", "autodetect",
  86. "text", "plain text",
  87. "caca", "native libcaca format",
  88. "ansi", "ANSI coloured text",
  89. NULL, NULL
  90. };
  91. return list;
  92. }
  93. /*
  94. * XXX: the following functions are local.
  95. */
  96. static cucul_canvas_t *import_caca(void const *data, unsigned int size)
  97. {
  98. cucul_canvas_t *cv;
  99. uint8_t const *buf = (uint8_t const *)data;
  100. unsigned int width, height, n;
  101. if(size < 16)
  102. return NULL;
  103. if(buf[0] != 'C' || buf[1] != 'A' || buf[2] != 'C' || buf[3] != 'A')
  104. return NULL;
  105. if(buf[4] != 'C' || buf[5] != 'A' || buf[6] != 'N' || buf[7] != 'V')
  106. return NULL;
  107. width = ((uint32_t)buf[8] << 24) | ((uint32_t)buf[9] << 16)
  108. | ((uint32_t)buf[10] << 8) | (uint32_t)buf[11];
  109. height = ((uint32_t)buf[12] << 24) | ((uint32_t)buf[13] << 16)
  110. | ((uint32_t)buf[14] << 8) | (uint32_t)buf[15];
  111. if(!width || !height)
  112. return NULL;
  113. if(size != 16 + width * height * 8)
  114. return NULL;
  115. cv = cucul_create_canvas(width, height);
  116. if(!cv)
  117. return NULL;
  118. for(n = height * width; n--; )
  119. {
  120. cv->chars[n] = ((uint32_t)buf[16 + 0 + 8 * n] << 24)
  121. | ((uint32_t)buf[16 + 1 + 8 * n] << 16)
  122. | ((uint32_t)buf[16 + 2 + 8 * n] << 8)
  123. | (uint32_t)buf[16 + 3 + 8 * n];
  124. cv->attr[n] = ((uint32_t)buf[16 + 4 + 8 * n] << 24)
  125. | ((uint32_t)buf[16 + 5 + 8 * n] << 16)
  126. | ((uint32_t)buf[16 + 6 + 8 * n] << 8)
  127. | (uint32_t)buf[16 + 7 + 8 * n];
  128. }
  129. return cv;
  130. }
  131. static cucul_canvas_t *import_text(void const *data, unsigned int size)
  132. {
  133. cucul_canvas_t *cv;
  134. char const *text = (char const *)data;
  135. unsigned int width = 1, height = 1, x = 0, y = 0, i;
  136. cv = cucul_create_canvas(width, height);
  137. cucul_set_color(cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_TRANSPARENT);
  138. for(i = 0; i < size; i++)
  139. {
  140. unsigned char ch = *text++;
  141. if(ch == '\r')
  142. continue;
  143. if(ch == '\n')
  144. {
  145. x = 0;
  146. y++;
  147. continue;
  148. }
  149. if(x >= width || y >= height)
  150. {
  151. if(x >= width)
  152. width = x + 1;
  153. if(y >= height)
  154. height = y + 1;
  155. cucul_set_canvas_size(cv, width, height);
  156. }
  157. cucul_putchar(cv, x, y, ch);
  158. x++;
  159. }
  160. return cv;
  161. }
  162. #define IS_ALPHA(x) (x>='A' && x<='z')
  163. #define END_TUP 0x1337
  164. unsigned char _get_ansi_command(unsigned char const *buffer, int size);
  165. int _parse_tuple(unsigned int *ret, unsigned char const *buffer, int size);
  166. void _manage_modifiers(int i, int *fg, int *bg, int *save_fg, int *save_bg, int *bold);
  167. static cucul_canvas_t *import_ansi(void const *data, unsigned int size)
  168. {
  169. cucul_canvas_t *cv;
  170. unsigned char const *buffer = (unsigned char const*)data;
  171. unsigned int i, sent_size = 0;
  172. unsigned char c;
  173. unsigned int count = 0;
  174. unsigned int tuple[1024]; /* Should be enough. Will it be ? */
  175. int x = 0, y = 0, width = 80, height = 25;
  176. int save_x = 0, save_y = 0;
  177. unsigned int j, add = 0;
  178. int fg, bg, save_fg, save_bg, bold;
  179. fg = save_fg = CUCUL_COLOR_LIGHTGRAY;
  180. bg = save_bg = CUCUL_COLOR_BLACK;
  181. bold = 0;
  182. cv = cucul_create_canvas(width, height);
  183. for(i = 0; i < size; i++)
  184. {
  185. if((buffer[i] == 0x1b) && (buffer[i + 1] == '[')) /* ESC code */
  186. {
  187. i++; // ESC
  188. i++; // [
  189. sent_size = size - i;
  190. c = _get_ansi_command(&buffer[i], sent_size);
  191. add = _parse_tuple(tuple, &buffer[i], sent_size);
  192. count = 0;
  193. while(tuple[count] != END_TUP)
  194. count++; /* Gruik */
  195. switch(c)
  196. {
  197. case 'f':
  198. case 'H':
  199. if(tuple[0] != END_TUP)
  200. {
  201. y = tuple[0] - 1;
  202. x = tuple[1] == END_TUP ? 0 : tuple[1] - 1;
  203. }
  204. else
  205. {
  206. y = 0;
  207. x = 0;
  208. }
  209. break;
  210. case 'A':
  211. y -= tuple[0] == END_TUP ? 1 : tuple[0];
  212. if(y < 0)
  213. y = 0;
  214. break;
  215. case 'B':
  216. y += tuple[0] == END_TUP ? 1 : tuple[0];
  217. break;
  218. case 'C':
  219. x += tuple[0] == END_TUP ? 1 : tuple[0];
  220. break;
  221. case 'D':
  222. x -= tuple[0] == END_TUP ? 1 : tuple[0];
  223. if(x < 0)
  224. x = 0;
  225. break;
  226. case 's':
  227. save_x = x;
  228. save_y = y;
  229. break;
  230. case 'u':
  231. x = save_x;
  232. y = save_y;
  233. break;
  234. case 'J':
  235. if(tuple[0] == 2)
  236. {
  237. x = 0;
  238. y = 0;
  239. }
  240. break;
  241. case 'K':
  242. // CLEAR END OF LINE
  243. break;
  244. case 'm':
  245. for(j = 0; j < count; j++)
  246. _manage_modifiers(tuple[j], &fg, &bg, &save_fg, &save_bg, &bold);
  247. if(bold && fg < 8)
  248. fg += 8;
  249. if(bold && bg < 8)
  250. bg += 8;
  251. cucul_set_color(cv, fg, bg);
  252. break;
  253. default:
  254. /*printf("Unknow command %c (%c)\n", c, IS_ALPHA(c)?c:'.');*/
  255. break;
  256. }
  257. }
  258. else
  259. {
  260. if(buffer[i] == '\n')
  261. {
  262. x = 0;
  263. y++;
  264. }
  265. else if(buffer[i] == '\r')
  266. {
  267. // DOS sucks.
  268. }
  269. else
  270. {
  271. _cucul_putchar32(cv, x, y,_cucul_cp437_to_utf32(buffer[i]));
  272. x++;
  273. }
  274. }
  275. if(x >= width || y >= height)
  276. {
  277. if(x >= width)
  278. width = x + 1;
  279. if(y >= height)
  280. height = y + 1;
  281. cucul_set_canvas_size(cv, width, height);
  282. }
  283. i += add; // add is tuple char count, then +[ +command
  284. add = 0;
  285. }
  286. return cv;
  287. }
  288. /* XXX : ANSI loader helpers */
  289. unsigned char _get_ansi_command(unsigned char const *buffer, int size)
  290. {
  291. int i;
  292. for(i = 0; i < size; i++)
  293. if(IS_ALPHA(buffer[i]))
  294. return buffer[i];
  295. return 0;
  296. }
  297. int _parse_tuple(unsigned int *ret, unsigned char const *buffer, int size)
  298. {
  299. int i = 0;
  300. int j = 0;
  301. int t = 0;
  302. unsigned char nbr[1024];
  303. ret[0] = END_TUP;
  304. for(i = 0; i < size; i++)
  305. {
  306. if(IS_ALPHA(buffer[i]))
  307. {
  308. if(j != 0)
  309. {
  310. ret[t] = atoi((char*)nbr);
  311. t++;
  312. }
  313. ret[t] = END_TUP;
  314. j = 0;
  315. return i;
  316. }
  317. if(buffer[i] != ';')
  318. {
  319. nbr[j] = buffer[i];
  320. nbr[j + 1] = 0;
  321. j++;
  322. }
  323. else
  324. {
  325. ret[t] = atoi((char*)nbr);
  326. t++;
  327. ret[t] = END_TUP;
  328. j = 0;
  329. }
  330. }
  331. return size;
  332. }
  333. void _manage_modifiers(int i, int *fg, int *bg, int *save_fg, int *save_bg, int *bold)
  334. {
  335. static uint8_t const ansi2cucul[] =
  336. {
  337. CUCUL_COLOR_BLACK,
  338. CUCUL_COLOR_RED,
  339. CUCUL_COLOR_GREEN,
  340. CUCUL_COLOR_BROWN,
  341. CUCUL_COLOR_BLUE,
  342. CUCUL_COLOR_MAGENTA,
  343. CUCUL_COLOR_CYAN,
  344. CUCUL_COLOR_LIGHTGRAY
  345. };
  346. if(i >= 30 && i <= 37)
  347. *fg = ansi2cucul[i - 30];
  348. else if(i == 39)
  349. *fg = CUCUL_COLOR_DEFAULT;
  350. else if(i >= 40 && i <= 47)
  351. *bg = ansi2cucul[i - 40];
  352. else if(i == 49)
  353. *bg = CUCUL_COLOR_DEFAULT;
  354. else if(i >= 90 && i <= 97)
  355. *fg = ansi2cucul[i - 90] + 8;
  356. else if(i >= 100 && i <= 107)
  357. *bg = ansi2cucul[i - 100] + 8;
  358. else switch(i)
  359. {
  360. case 0:
  361. *fg = CUCUL_COLOR_DEFAULT;
  362. *bg = CUCUL_COLOR_DEFAULT;
  363. *bold = 0;
  364. break;
  365. case 1: /* BOLD */
  366. *bold = 1;
  367. break;
  368. case 4: // Underline
  369. break;
  370. case 5: // blink
  371. break;
  372. case 7: // reverse
  373. *fg = 15 - *fg;
  374. *bg = 15 - *bg;
  375. break;
  376. case 8: // invisible
  377. *save_fg = *fg;
  378. *save_bg = *bg;
  379. *fg = CUCUL_COLOR_TRANSPARENT;
  380. *bg = CUCUL_COLOR_TRANSPARENT;
  381. break;
  382. case 28: // not invisible
  383. *fg = *save_fg;
  384. *bg = *save_bg;
  385. break;
  386. default:
  387. /* printf("Unknow option to 'm' %d (%c)\n", c, IS_ALPHA(c)?c:'.'); */
  388. break;
  389. }
  390. }