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 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  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. void _update_canvas_size(cucul_canvas_t *cv, int x, int y, int *max_x, int *max_y);
  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(char c, int *fg, int *bg, int *old_fg, int *old_bg);
  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, max_x = 80, max_y = 25;
  176. int save_x = 0, save_y = 0;
  177. unsigned int j, add = 0;
  178. int fg, bg, old_fg, old_bg;
  179. fg = old_fg = CUCUL_COLOR_LIGHTGRAY;
  180. bg = old_bg = CUCUL_COLOR_BLACK;
  181. cv = cucul_create_canvas(max_x, max_y);
  182. for(i = 0; i < size; i++)
  183. {
  184. if((buffer[i] == 0x1b) && (buffer[i + 1] == '[')) /* ESC code */
  185. {
  186. i++; // ESC
  187. i++; // [
  188. sent_size = size - i;
  189. c = _get_ansi_command(&buffer[i], sent_size);
  190. add = _parse_tuple(tuple, &buffer[i], sent_size);
  191. count = 0;
  192. while(tuple[count] != 0x1337)
  193. count++; /* Gruik */
  194. switch(c)
  195. {
  196. case 'f':
  197. case 'H':
  198. if(tuple[0] != 0x1337)
  199. {
  200. x = tuple[0];
  201. if(tuple[1] != 0x1337)
  202. y = tuple[1];
  203. }
  204. else
  205. {
  206. x = 0;
  207. y = 0;
  208. }
  209. _update_canvas_size(cv, x, y, &max_x, &max_y);
  210. break;
  211. case 'A':
  212. if(tuple[0] == 0x1337)
  213. y -= 1;
  214. else
  215. y -= tuple[0];
  216. if(y < 0) y = 0;
  217. _update_canvas_size(cv, x, y, &max_x, &max_y);
  218. break;
  219. case 'B':
  220. if(tuple[0] == 0x1337)
  221. y++;
  222. else
  223. y += tuple[0];
  224. _update_canvas_size(cv, x, y, &max_x, &max_y);
  225. break;
  226. case 'C':
  227. if(tuple[0] == 0x1337)
  228. x++;
  229. else
  230. x += tuple[0];
  231. _update_canvas_size(cv, x, y, &max_x, &max_y);
  232. break;
  233. case 'D':
  234. if(tuple[0] == 0x1337)
  235. x--;
  236. else
  237. x -= tuple[0];
  238. if(x < 0) x = 0;
  239. _update_canvas_size(cv, x, y, &max_x, &max_y);
  240. break;
  241. case 's':
  242. save_x = x;
  243. save_y = y;
  244. break;
  245. case 'u':
  246. x = save_x;
  247. y = save_y;
  248. _update_canvas_size(cv, x, y, &max_x, &max_y);
  249. break;
  250. case 'J':
  251. if(tuple[0] == 2)
  252. {
  253. x = 0;
  254. y = 0;
  255. _update_canvas_size(cv, x, y, &max_x, &max_y);
  256. }
  257. break;
  258. case 'K':
  259. // CLEAR END OF LINE
  260. break;
  261. case 'm':
  262. for(j = 0; j < count; j++)
  263. _manage_modifiers(tuple[j], &fg, &bg, &old_fg, &old_bg);
  264. cucul_set_color(cv, fg, bg);
  265. break;
  266. default:
  267. /*printf("Unknow command %c (%c)\n", c, IS_ALPHA(c)?c:'.');*/
  268. break;
  269. }
  270. }
  271. else
  272. {
  273. if(buffer[i] == '\n')
  274. {
  275. x = 0;
  276. y++;
  277. _update_canvas_size(cv, x, y, &max_x, &max_y);
  278. }
  279. else if(buffer[i] == '\r')
  280. {
  281. // DOS sucks.
  282. }
  283. else
  284. {
  285. if((buffer[i] >= 0x20) || (buffer[i] <= 0x7E))
  286. {
  287. _cucul_putchar32(cv, x, y,_cucul_cp437_to_utf32(buffer[i]));
  288. // cucul_putchar(cv, x, y, buffer[i]);
  289. }
  290. else
  291. cucul_putchar(cv, x, y, '?');
  292. x++;
  293. _update_canvas_size(cv, x, y, &max_x, &max_y);
  294. }
  295. }
  296. i += add; // add is tuple char count, then +[ +command
  297. add = 0;
  298. }
  299. return cv;
  300. }
  301. /* XXX : ANSI loader helpers */
  302. unsigned char _get_ansi_command(unsigned char const *buffer, int size)
  303. {
  304. int i;
  305. for(i = 0; i < size; i++)
  306. if(IS_ALPHA(buffer[i]))
  307. return buffer[i];
  308. return 0;
  309. }
  310. int _parse_tuple(unsigned int *ret, unsigned char const *buffer, int size)
  311. {
  312. int i = 0;
  313. int j = 0;
  314. int t = 0;
  315. unsigned char nbr[1024];
  316. ret[0] = 0x1337;
  317. for(i = 0; i < size; i++)
  318. {
  319. if(IS_ALPHA(buffer[i]))
  320. {
  321. if(j != 0)
  322. {
  323. ret[t] = atoi((char*)nbr);
  324. t++;
  325. }
  326. ret[t] = 0x1337;
  327. j = 0;
  328. return i;
  329. }
  330. if(buffer[i] != ';')
  331. {
  332. nbr[j] = buffer[i];
  333. nbr[j + 1] = 0;
  334. j++;
  335. }
  336. else
  337. {
  338. ret[t] = atoi((char*)nbr);
  339. t++;
  340. ret[t] = 0x1337;
  341. j = 0;
  342. }
  343. }
  344. return size;
  345. }
  346. void _manage_modifiers(char c, int *fg, int *bg, int *old_fg, int *old_bg)
  347. {
  348. switch(c)
  349. {
  350. case 0:
  351. *fg = CUCUL_COLOR_DEFAULT;
  352. *bg = CUCUL_COLOR_DEFAULT;
  353. break;
  354. case 1: // BOLD
  355. break;
  356. case 4: // Underline
  357. break;
  358. case 5: // blink
  359. break;
  360. case 7: // reverse
  361. *fg = 15 - *fg;
  362. *bg = 15 - *bg;
  363. break;
  364. case 8: // invisible
  365. *old_fg = *fg;
  366. *old_bg = *bg;
  367. *fg = CUCUL_COLOR_TRANSPARENT;
  368. *bg = CUCUL_COLOR_TRANSPARENT;
  369. break;
  370. case 28: // not invisible
  371. *fg = *old_fg;
  372. *bg = *old_bg;
  373. break;
  374. case 30: *fg = CUCUL_COLOR_BLACK; break;
  375. case 31: *fg = CUCUL_COLOR_RED; break;
  376. case 32: *fg = CUCUL_COLOR_GREEN; break;
  377. case 33: *fg = CUCUL_COLOR_BROWN; break;
  378. case 34: *fg = CUCUL_COLOR_BLUE; break;
  379. case 35: *fg = CUCUL_COLOR_MAGENTA; break;
  380. case 36: *fg = CUCUL_COLOR_CYAN; break;
  381. case 37: *fg = CUCUL_COLOR_WHITE; break;
  382. case 39: *fg = CUCUL_COLOR_LIGHTGRAY; break;
  383. case 40: *bg = CUCUL_COLOR_BLACK; break;
  384. case 41: *bg = CUCUL_COLOR_RED; break;
  385. case 42: *bg = CUCUL_COLOR_GREEN; break;
  386. case 43: *bg = CUCUL_COLOR_BROWN; break;
  387. case 44: *bg = CUCUL_COLOR_BLUE; break;
  388. case 45: *bg = CUCUL_COLOR_MAGENTA; break;
  389. case 46: *bg = CUCUL_COLOR_CYAN; break;
  390. case 47: *bg = CUCUL_COLOR_WHITE; break;
  391. case 49: *bg = CUCUL_COLOR_BLACK; break;
  392. case 90: *fg = CUCUL_COLOR_DARKGRAY; break;
  393. case 91: *fg = CUCUL_COLOR_LIGHTRED; break;
  394. case 92: *fg = CUCUL_COLOR_LIGHTGREEN; break;
  395. case 93: *fg = CUCUL_COLOR_YELLOW; break;
  396. case 94: *fg = CUCUL_COLOR_LIGHTBLUE; break;
  397. case 95: *fg = CUCUL_COLOR_LIGHTMAGENTA; break;
  398. case 96: *fg = CUCUL_COLOR_LIGHTCYAN; break;
  399. case 97: *fg = CUCUL_COLOR_WHITE; break;
  400. case 100: *bg = CUCUL_COLOR_DARKGRAY; break;
  401. case 101: *bg = CUCUL_COLOR_LIGHTRED; break;
  402. case 102: *bg = CUCUL_COLOR_LIGHTGREEN; break;
  403. case 103: *bg = CUCUL_COLOR_YELLOW; break;
  404. case 104: *bg = CUCUL_COLOR_LIGHTBLUE; break;
  405. case 105: *bg = CUCUL_COLOR_LIGHTMAGENTA; break;
  406. case 106: *bg = CUCUL_COLOR_LIGHTCYAN; break;
  407. case 107: *bg = CUCUL_COLOR_WHITE; break;
  408. default:
  409. /* printf("Unknow option to 'm' %d (%c)\n", c, IS_ALPHA(c)?c:'.'); */
  410. break;
  411. }
  412. }
  413. void _update_canvas_size(cucul_canvas_t *cv, int x, int y, int *max_x, int *max_y)
  414. {
  415. if(x > *max_x)
  416. *max_x = x;
  417. if(y > *max_y)
  418. *max_y = y;
  419. cucul_set_canvas_size(cv, *max_x, *max_y);
  420. }