Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
19 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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. unsigned int i=0;
  61. /* if 4 first letters are CACA */
  62. if(size >= 4 &&
  63. buf[0] == 'C' && buf[1] == 'A' && buf[2] == 'C' && buf[3] != 'A')
  64. return import_caca(data, size);
  65. /* If we find ESC[ argv, we guess it's an ANSI file */
  66. while(i<size-1)
  67. {
  68. if((buf[i] == 0x1b) && (buf[i+1] == '['))
  69. return import_ansi(data, size);
  70. i++;
  71. }
  72. /* Otherwise, import it as text */
  73. return import_text(data, 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. #define IS_ALPHA(x) (x>='A' && x<='z')
  168. #define END_ARG 0x1337
  169. static int parse_tuple(unsigned int *, unsigned char const *, int);
  170. static void manage_modifiers(int, uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *);
  171. static cucul_canvas_t *import_ansi(void const *data, unsigned int size)
  172. {
  173. cucul_canvas_t *cv;
  174. unsigned char const *buffer = (unsigned char const*)data;
  175. unsigned int i;
  176. int x = 0, y = 0;
  177. unsigned int width = 80, height = 25;
  178. int save_x = 0, save_y = 0;
  179. unsigned int j, skip;
  180. uint8_t fg, bg, save_fg, save_bg, bold, reverse;
  181. fg = save_fg = CUCUL_COLOR_LIGHTGRAY;
  182. bg = save_bg = CUCUL_COLOR_BLACK;
  183. bold = reverse = 0;
  184. cv = cucul_create_canvas(width, height);
  185. cucul_set_color(cv, fg, bg);
  186. for(i = 0; i < size; i += skip)
  187. {
  188. skip = 1;
  189. if(buffer[i] == '\x1a' && size - i >= 8
  190. && !memcmp(buffer + i + 1, "SAUCE00", 7))
  191. break; /* End before SAUCE data */
  192. if(buffer[i] == '\r')
  193. continue; /* DOS sucks */
  194. if(buffer[i] == '\n')
  195. {
  196. x = 0;
  197. y++;
  198. continue;
  199. }
  200. if(buffer[i] == '\x1b' && buffer[i + 1] == '[') /* ESC code */
  201. {
  202. unsigned int argv[1024]; /* Should be enough. Will it be? */
  203. unsigned int argc = 0;
  204. unsigned char c = '\0';
  205. i++; // ESC
  206. i++; // [
  207. for(j = i; j < size; j++)
  208. if(IS_ALPHA(buffer[j]))
  209. {
  210. c = buffer[j];
  211. break;
  212. }
  213. skip += parse_tuple(argv, buffer + i, size - i);
  214. while(argv[argc] != END_ARG)
  215. argc++; /* Gruik */
  216. switch(c)
  217. {
  218. case 'f':
  219. case 'H':
  220. switch(argc)
  221. {
  222. case 0: x = y = 0; break;
  223. case 1: y = argv[0] - 1; x = 0; break;
  224. case 2: y = argv[0] - 1; x = argv[1] - 1; break;
  225. }
  226. break;
  227. case 'A':
  228. y -= argc ? argv[0] : 1;
  229. if(y < 0)
  230. y = 0;
  231. break;
  232. case 'B':
  233. y += argc ? argv[0] : 1;
  234. break;
  235. case 'C':
  236. x += argc ? argv[0] : 1;
  237. break;
  238. case 'D':
  239. x -= argc ? argv[0] : 1;
  240. if(x < 0)
  241. x = 0;
  242. break;
  243. case 's':
  244. save_x = x;
  245. save_y = y;
  246. break;
  247. case 'u':
  248. x = save_x;
  249. y = save_y;
  250. break;
  251. case 'J':
  252. if(argv[0] == 2)
  253. x = y = 0;
  254. break;
  255. case 'K':
  256. // CLEAR END OF LINE
  257. for(j = x; j < width; j++)
  258. _cucul_putchar32(cv, j, y, (uint32_t)' ');
  259. x = width;
  260. break;
  261. case 'm':
  262. for(j = 0; j < argc; j++)
  263. manage_modifiers(argv[j], &fg, &bg,
  264. &save_fg, &save_bg, &bold, &reverse);
  265. if(bold && fg < 8)
  266. fg += 8;
  267. if(bold && bg < 8)
  268. bg += 8;
  269. if(reverse)
  270. cucul_set_color(cv, bg, fg);
  271. else
  272. cucul_set_color(cv, fg, bg);
  273. break;
  274. default:
  275. break;
  276. }
  277. continue;
  278. }
  279. /* We're going to paste a character. First make sure the canvas
  280. * is big enough. */
  281. if(x >= width)
  282. {
  283. x = 0;
  284. y++;
  285. }
  286. if(y >= height)
  287. {
  288. height = y + 1;
  289. cucul_set_canvas_size(cv, width, height);
  290. }
  291. /* Now paste our character */
  292. _cucul_putchar32(cv, x, y,_cucul_cp437_to_utf32(buffer[i]));
  293. x++;
  294. }
  295. return cv;
  296. }
  297. /* XXX : ANSI loader helpers */
  298. static int parse_tuple(unsigned int *ret, unsigned char const *buffer, int size)
  299. {
  300. int i = 0;
  301. int j = 0;
  302. int t = 0;
  303. unsigned char nbr[1024];
  304. ret[0] = END_ARG;
  305. for(i = 0; i < size; i++)
  306. {
  307. if(IS_ALPHA(buffer[i]))
  308. {
  309. if(j != 0)
  310. {
  311. ret[t] = atoi((char*)nbr);
  312. t++;
  313. }
  314. ret[t] = END_ARG;
  315. j = 0;
  316. return i;
  317. }
  318. if(buffer[i] != ';')
  319. {
  320. nbr[j] = buffer[i];
  321. nbr[j + 1] = 0;
  322. j++;
  323. }
  324. else
  325. {
  326. ret[t] = atoi((char*)nbr);
  327. t++;
  328. ret[t] = END_ARG;
  329. j = 0;
  330. }
  331. }
  332. return size;
  333. }
  334. static void manage_modifiers(int i, uint8_t *fg, uint8_t *bg, uint8_t *save_fg,
  335. uint8_t *save_bg, uint8_t *bold, uint8_t *reverse)
  336. {
  337. static uint8_t const ansi2cucul[] =
  338. {
  339. CUCUL_COLOR_BLACK,
  340. CUCUL_COLOR_RED,
  341. CUCUL_COLOR_GREEN,
  342. CUCUL_COLOR_BROWN,
  343. CUCUL_COLOR_BLUE,
  344. CUCUL_COLOR_MAGENTA,
  345. CUCUL_COLOR_CYAN,
  346. CUCUL_COLOR_LIGHTGRAY
  347. };
  348. if(i >= 30 && i <= 37)
  349. *fg = ansi2cucul[i - 30];
  350. else if(i >= 40 && i <= 47)
  351. *bg = ansi2cucul[i - 40];
  352. else if(i >= 90 && i <= 97)
  353. *fg = ansi2cucul[i - 90] + 8;
  354. else if(i >= 100 && i <= 107)
  355. *bg = ansi2cucul[i - 100] + 8;
  356. else switch(i)
  357. {
  358. case 0:
  359. *fg = CUCUL_COLOR_DEFAULT;
  360. *bg = CUCUL_COLOR_DEFAULT;
  361. *bold = 0;
  362. *reverse = 0;
  363. break;
  364. case 1: /* BOLD */
  365. *bold = 1;
  366. break;
  367. case 4: // Underline
  368. break;
  369. case 5: // blink
  370. break;
  371. case 7: // reverse
  372. *reverse = 1;
  373. break;
  374. case 8: // invisible
  375. *save_fg = *fg;
  376. *save_bg = *bg;
  377. *fg = CUCUL_COLOR_TRANSPARENT;
  378. *bg = CUCUL_COLOR_TRANSPARENT;
  379. break;
  380. case 28: // not invisible
  381. *fg = *save_fg;
  382. *bg = *save_bg;
  383. break;
  384. case 39:
  385. *fg = CUCUL_COLOR_DEFAULT;
  386. break;
  387. case 49:
  388. *bg = CUCUL_COLOR_DEFAULT;
  389. break;
  390. default:
  391. break;
  392. }
  393. }