Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

vor 19 Jahren
vor 19 Jahren
vor 19 Jahren
vor 19 Jahren
vor 19 Jahren
vor 19 Jahren
vor 19 Jahren
vor 19 Jahren
vor 19 Jahren
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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. 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 argv[1024]; /* Should be enough. Will it be? */
  203. unsigned int argc = 0;
  204. unsigned int param, inter, final;
  205. /* Offset to parameter bytes */
  206. param = 2;
  207. /* Offset to intermediate bytes: skip parameter bytes */
  208. for(inter = param; i + inter < size; inter++)
  209. if(buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
  210. break;
  211. /* Offset to final byte: skip intermediate bytes */
  212. for(final = inter; i + final < size; final++)
  213. if(buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
  214. break;
  215. if(buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
  216. break; /* Invalid Final Byte */
  217. skip += final;
  218. if(param < inter && buffer[i + param] >= 0x3c)
  219. {
  220. //fprintf(stderr, "private sequence \"^[[%.*s\"\n",
  221. // final - param + 1, buffer + i + param);
  222. continue; /* Private sequence, skip it entirely */
  223. }
  224. /* Parse parameter bytes, if any */
  225. if(param < inter)
  226. {
  227. argv[0] = 0;
  228. for(j = param; j < inter; j++)
  229. {
  230. if(buffer[i + j] == ';')
  231. argv[++argc] = 0;
  232. else if(buffer[i + j] >= '0' && buffer[i + j] <= '9')
  233. argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
  234. }
  235. argc++;
  236. }
  237. /* Interpret final byte */
  238. switch(buffer[i + final])
  239. {
  240. case 'f':
  241. case 'H':
  242. x = (argc > 1) ? argv[1] - 1 : 0;
  243. y = (argc > 0) ? argv[0] - 1 : 0;
  244. break;
  245. case 'A':
  246. y -= argc ? argv[0] : 1;
  247. if(y < 0)
  248. y = 0;
  249. break;
  250. case 'B':
  251. y += argc ? argv[0] : 1;
  252. break;
  253. case 'C':
  254. x += argc ? argv[0] : 1;
  255. break;
  256. case 'D':
  257. x -= argc ? argv[0] : 1;
  258. if(x < 0)
  259. x = 0;
  260. break;
  261. case 's':
  262. save_x = x;
  263. save_y = y;
  264. break;
  265. case 'u':
  266. x = save_x;
  267. y = save_y;
  268. break;
  269. case 'J':
  270. if(argv[0] == 2)
  271. x = y = 0;
  272. break;
  273. case 'K':
  274. // CLEAR END OF LINE
  275. for(j = x; j < width; j++)
  276. _cucul_putchar32(cv, j, y, (uint32_t)' ');
  277. x = width;
  278. break;
  279. case 'm':
  280. for(j = 0; j < argc; j++)
  281. manage_modifiers(argv[j], &fg, &bg,
  282. &save_fg, &save_bg, &bold, &reverse);
  283. if(bold && fg < 8)
  284. fg += 8;
  285. if(bold && bg < 8)
  286. bg += 8;
  287. if(reverse)
  288. cucul_set_color(cv, bg, fg);
  289. else
  290. cucul_set_color(cv, fg, bg);
  291. break;
  292. default:
  293. break;
  294. }
  295. continue;
  296. }
  297. /* We're going to paste a character. First make sure the canvas
  298. * is big enough. */
  299. if((unsigned int)x >= width)
  300. {
  301. x = 0;
  302. y++;
  303. }
  304. if((unsigned int)y >= height)
  305. {
  306. height = y + 1;
  307. cucul_set_canvas_size(cv, width, height);
  308. }
  309. /* Now paste our character */
  310. _cucul_putchar32(cv, x, y,_cucul_cp437_to_utf32(buffer[i]));
  311. x++;
  312. }
  313. return cv;
  314. }
  315. /* XXX : ANSI loader helper */
  316. static void manage_modifiers(int i, uint8_t *fg, uint8_t *bg, uint8_t *save_fg,
  317. uint8_t *save_bg, uint8_t *bold, uint8_t *reverse)
  318. {
  319. static uint8_t const ansi2cucul[] =
  320. {
  321. CUCUL_COLOR_BLACK,
  322. CUCUL_COLOR_RED,
  323. CUCUL_COLOR_GREEN,
  324. CUCUL_COLOR_BROWN,
  325. CUCUL_COLOR_BLUE,
  326. CUCUL_COLOR_MAGENTA,
  327. CUCUL_COLOR_CYAN,
  328. CUCUL_COLOR_LIGHTGRAY
  329. };
  330. if(i >= 30 && i <= 37)
  331. *fg = ansi2cucul[i - 30];
  332. else if(i >= 40 && i <= 47)
  333. *bg = ansi2cucul[i - 40];
  334. else if(i >= 90 && i <= 97)
  335. *fg = ansi2cucul[i - 90] + 8;
  336. else if(i >= 100 && i <= 107)
  337. *bg = ansi2cucul[i - 100] + 8;
  338. else switch(i)
  339. {
  340. case 0:
  341. *fg = CUCUL_COLOR_DEFAULT;
  342. *bg = CUCUL_COLOR_DEFAULT;
  343. *bold = 0;
  344. *reverse = 0;
  345. break;
  346. case 1: /* BOLD */
  347. *bold = 1;
  348. break;
  349. case 4: // Underline
  350. break;
  351. case 5: // blink
  352. break;
  353. case 7: // reverse
  354. *reverse = 1;
  355. break;
  356. case 8: // invisible
  357. *save_fg = *fg;
  358. *save_bg = *bg;
  359. *fg = CUCUL_COLOR_TRANSPARENT;
  360. *bg = CUCUL_COLOR_TRANSPARENT;
  361. break;
  362. case 28: // not invisible
  363. *fg = *save_fg;
  364. *bg = *save_bg;
  365. break;
  366. case 39:
  367. *fg = CUCUL_COLOR_DEFAULT;
  368. break;
  369. case 49:
  370. *bg = CUCUL_COLOR_DEFAULT;
  371. break;
  372. default:
  373. break;
  374. }
  375. }