Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

414 righe
13 KiB

  1. /*
  2. * libcaca Colour ASCII-Art library
  3. * Copyright (c) 2002-2009 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains various import functions.
  16. */
  17. #include "config.h"
  18. #if !defined __KERNEL__
  19. # include <stdlib.h>
  20. # include <string.h>
  21. # include <stdio.h>
  22. #endif
  23. #include "caca.h"
  24. #include "caca_internals.h"
  25. #include "codec.h"
  26. static inline uint32_t sscanu32(void const *s)
  27. {
  28. uint32_t x;
  29. memcpy(&x, s, 4);
  30. return hton32(x);
  31. }
  32. static inline uint16_t sscanu16(void const *s)
  33. {
  34. uint16_t x;
  35. memcpy(&x, s, 2);
  36. return hton16(x);
  37. }
  38. static ssize_t import_caca(caca_canvas_t *, void const *, size_t);
  39. /** \brief Import a memory buffer into a canvas
  40. *
  41. * Import a memory buffer into the given libcaca canvas's current
  42. * frame. The current frame is resized accordingly and its contents are
  43. * replaced with the imported data.
  44. *
  45. * Valid values for \c format are:
  46. * - \c "": attempt to autodetect the file format.
  47. * - \c "caca": import native libcaca files.
  48. * - \c "text": import ASCII text files.
  49. * - \c "ansi": import ANSI files.
  50. * - \c "utf8": import UTF-8 files with ANSI colour codes.
  51. *
  52. * The number of bytes read is returned. If the file format is valid, but
  53. * not enough data was available, 0 is returned.
  54. *
  55. * If an error occurs, -1 is returned and \b errno is set accordingly:
  56. * - \c ENOMEM Not enough memory to allocate canvas.
  57. * - \c EINVAL Invalid format requested.
  58. *
  59. * \param cv A libcaca canvas in which to import the file.
  60. * \param data A memory area containing the data to be loaded into the canvas.
  61. * \param len The size in bytes of the memory area.
  62. * \param format A string describing the input format.
  63. * \return The number of bytes read, or 0 if there was not enough data,
  64. * or -1 if an error occurred.
  65. */
  66. ssize_t caca_import_canvas_from_memory(caca_canvas_t *cv, void const *data,
  67. size_t len, char const *format)
  68. {
  69. if(!strcasecmp("caca", format))
  70. return import_caca(cv, data, len);
  71. if(!strcasecmp("utf8", format))
  72. return _import_ansi(cv, data, len, 1);
  73. if(!strcasecmp("text", format))
  74. return _import_text(cv, data, len);
  75. if(!strcasecmp("ansi", format))
  76. return _import_ansi(cv, data, len, 0);
  77. /* Autodetection */
  78. if(!strcasecmp("", format))
  79. {
  80. unsigned char const *str = data;
  81. unsigned int i;
  82. /* If 4 first bytes are 0xcaca + 'CV' */
  83. if(len >= 4 && str[0] == 0xca &&
  84. str[1] == 0xca && str[2] == 'C' && str[3] == 'V')
  85. return import_caca(cv, data, len);
  86. /* If we find ESC[ argv, we guess it's an ANSI file */
  87. for(i = 0; i + 1 < len; i++)
  88. if((str[i] == '\033') && (str[i + 1] == '['))
  89. return _import_ansi(cv, data, len, 0);
  90. /* Otherwise, import it as text */
  91. return _import_text(cv, data, len);
  92. }
  93. seterrno(EINVAL);
  94. return -1;
  95. }
  96. /** \brief Import a file into a canvas
  97. *
  98. * Import a file into the given libcaca canvas's current frame. The
  99. * current frame is resized accordingly and its contents are replaced
  100. * with the imported data.
  101. *
  102. * Valid values for \c format are:
  103. * - \c "": attempt to autodetect the file format.
  104. * - \c "caca": import native libcaca files.
  105. * - \c "text": import ASCII text files.
  106. * - \c "ansi": import ANSI files.
  107. * - \c "utf8": import UTF-8 files with ANSI colour codes.
  108. *
  109. * The number of bytes read is returned. If the file format is valid, but
  110. * not enough data was available, 0 is returned.
  111. *
  112. * If an error occurs, -1 is returned and \b errno is set accordingly:
  113. * - \c ENOSYS File access is not implemented on this system.
  114. * - \c ENOMEM Not enough memory to allocate canvas.
  115. * - \c EINVAL Invalid format requested.
  116. * caca_import_file() may also fail and set \b errno for any of the
  117. * errors specified for the routine fopen().
  118. *
  119. * \param cv A libcaca canvas in which to import the file.
  120. * \param filename The name of the file to load.
  121. * \param format A string describing the input format.
  122. * \return The number of bytes read, or 0 if there was not enough data,
  123. * or -1 if an error occurred.
  124. */
  125. ssize_t caca_import_canvas_from_file(caca_canvas_t *cv, char const *filename,
  126. char const *format)
  127. {
  128. #if defined __KERNEL__
  129. seterrno(ENOSYS);
  130. return -1;
  131. #else
  132. caca_file_t *f;
  133. char *data = NULL;
  134. ssize_t ret, size = 0;
  135. f = caca_file_open(filename, "rb");
  136. if(!f)
  137. return -1; /* fopen already set errno */
  138. while(!caca_file_eof(f))
  139. {
  140. data = realloc(data, size + 1024);
  141. if(!data)
  142. {
  143. caca_file_close(f);
  144. seterrno(ENOMEM);
  145. return -1;
  146. }
  147. ret = (ssize_t)caca_file_read(f, data + size, 1024);
  148. if(ret >= 0)
  149. size += ret;
  150. }
  151. caca_file_close(f);
  152. ret = caca_import_canvas_from_memory(cv, data, size, format);
  153. free(data);
  154. return ret;
  155. #endif
  156. }
  157. /** \brief Import a memory buffer into a canvas area
  158. *
  159. * Import a memory buffer into the given libcaca canvas's current
  160. * frame, at the specified position. For more information, see
  161. * caca_import_canvas_from_memory().
  162. *
  163. * If an error occurs, -1 is returned and \b errno is set accordingly:
  164. * - \c EINVAL Unsupported format requested or invalid coordinates.
  165. * - \c ENOMEM Not enough memory to allocate canvas.
  166. *
  167. * \param cv A libcaca canvas in which to import the file.
  168. * \param x The leftmost coordinate of the area to import to.
  169. * \param y The topmost coordinate of the area to import to.
  170. * \param data A memory area containing the data to be loaded into the canvas.
  171. * \param len The size in bytes of the memory area.
  172. * \param format A string describing the input format.
  173. * \return The number of bytes read, or 0 if there was not enough data,
  174. * or -1 if an error occurred.
  175. */
  176. ssize_t caca_import_area_from_memory(caca_canvas_t *cv, int x, int y,
  177. void const *data, size_t len,
  178. char const *format)
  179. {
  180. caca_canvas_t *tmp;
  181. ssize_t ret;
  182. tmp = caca_create_canvas(0, 0);
  183. ret = caca_import_canvas_from_memory(tmp, data, len, format);
  184. if(ret > 0)
  185. caca_blit(cv, x, y, tmp, NULL);
  186. caca_free_canvas(tmp);
  187. return ret;
  188. }
  189. /** \brief Import a file into a canvas area
  190. *
  191. * Import a file into the given libcaca canvas's current frame, at the
  192. * specified position. For more information, see
  193. * caca_import_canvas_from_file().
  194. *
  195. * If an error occurs, -1 is returned and \b errno is set accordingly:
  196. * - \c ENOSYS File access is not implemented on this system.
  197. * - \c ENOMEM Not enough memory to allocate canvas.
  198. * - \c EINVAL Unsupported format requested or invalid coordinates.
  199. * caca_import_file() may also fail and set \b errno for any of the
  200. * errors specified for the routine fopen().
  201. *
  202. * \param cv A libcaca canvas in which to import the file.
  203. * \param x The leftmost coordinate of the area to import to.
  204. * \param y The topmost coordinate of the area to import to.
  205. * \param filename The name of the file to load.
  206. * \param format A string describing the input format.
  207. * \return The number of bytes read, or 0 if there was not enough data,
  208. * or -1 if an error occurred.
  209. */
  210. ssize_t caca_import_area_from_file(caca_canvas_t *cv, int x, int y,
  211. char const *filename, char const *format)
  212. {
  213. caca_canvas_t *tmp;
  214. ssize_t ret;
  215. tmp = caca_create_canvas(0, 0);
  216. ret = caca_import_canvas_from_file(tmp, filename, format);
  217. if(ret > 0)
  218. caca_blit(cv, x, y, tmp, NULL);
  219. caca_free_canvas(tmp);
  220. return ret;
  221. }
  222. /** \brief Get available import formats
  223. *
  224. * Return a list of available import formats. The list is a NULL-terminated
  225. * array of strings, interleaving a string containing the internal value for
  226. * the import format, to be used with caca_import_canvas(), and a string
  227. * containing the natural language description for that import format.
  228. *
  229. * This function never fails.
  230. *
  231. * \return An array of strings.
  232. */
  233. char const * const * caca_get_import_list(void)
  234. {
  235. static char const * const list[] =
  236. {
  237. "", "autodetect",
  238. "caca", "native libcaca format",
  239. "text", "plain text",
  240. "ansi", "ANSI coloured text",
  241. "utf8", "UTF-8 files with ANSI colour codes",
  242. NULL, NULL
  243. };
  244. return list;
  245. }
  246. /*
  247. * XXX: the following functions are local.
  248. */
  249. static ssize_t import_caca(caca_canvas_t *cv, void const *data, size_t size)
  250. {
  251. uint8_t const *buf = (uint8_t const *)data;
  252. size_t control_size, data_size, expected_size;
  253. unsigned int frames, f, n, offset;
  254. uint16_t version, flags;
  255. int32_t xmin = 0, ymin = 0, xmax = 0, ymax = 0;
  256. if(size < 20)
  257. return 0;
  258. if(buf[0] != 0xca || buf[1] != 0xca || buf[2] != 'C' || buf[3] != 'V')
  259. {
  260. debug("caca import error: expected \\xca\\xcaCV header");
  261. goto invalid_caca;
  262. }
  263. control_size = sscanu32(buf + 4);
  264. data_size = sscanu32(buf + 8);
  265. version = sscanu16(buf + 12);
  266. frames = sscanu32(buf + 14);
  267. flags = sscanu16(buf + 18);
  268. if(size < 4 + control_size + data_size)
  269. return 0;
  270. if(control_size < 16 + frames * 32)
  271. {
  272. debug("caca import error: control size %u < expected %u",
  273. (unsigned int)control_size, 16 + frames * 32);
  274. goto invalid_caca;
  275. }
  276. for(expected_size = 0, f = 0; f < frames; f++)
  277. {
  278. unsigned int width, height, duration;
  279. uint32_t attr;
  280. int x, y, handlex, handley;
  281. width = sscanu32(buf + 4 + 16 + f * 32);
  282. height = sscanu32(buf + 4 + 16 + f * 32 + 4);
  283. duration = sscanu32(buf + 4 + 16 + f * 32 + 8);
  284. attr = sscanu32(buf + 4 + 16 + f * 32 + 12);
  285. x = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 16);
  286. y = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 20);
  287. handlex = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 24);
  288. handley = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 28);
  289. expected_size += width * height * 8;
  290. if(-handlex < xmin)
  291. xmin = -handlex;
  292. if(-handley < ymin)
  293. ymin = -handley;
  294. if((((int32_t) width) - handlex) > xmax)
  295. xmax = ((int32_t) width) - handlex;
  296. if((((int32_t) height) - handley) > ymax)
  297. ymax = ((int32_t) height) - handley;
  298. }
  299. if(expected_size != data_size)
  300. {
  301. debug("caca import error: data size %u < expected %u",
  302. (unsigned int)data_size, (unsigned int)expected_size);
  303. goto invalid_caca;
  304. }
  305. caca_set_canvas_size(cv, 0, 0);
  306. caca_set_canvas_size(cv, xmax - xmin, ymax - ymin);
  307. for (f = caca_get_frame_count(cv); f--; )
  308. {
  309. caca_free_frame(cv, f);
  310. }
  311. for (offset = 0, f = 0; f < frames; f ++)
  312. {
  313. unsigned int width, height;
  314. width = sscanu32(buf + 4 + 16 + f * 32);
  315. height = sscanu32(buf + 4 + 16 + f * 32 + 4);
  316. caca_create_frame(cv, f);
  317. caca_set_frame(cv, f);
  318. cv->curattr = sscanu32(buf + 4 + 16 + f * 32 + 12);
  319. cv->frames[f].x = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 16);
  320. cv->frames[f].y = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 20);
  321. cv->frames[f].handlex = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 24);
  322. cv->frames[f].handley = (int32_t)sscanu32(buf + 4 + 16 + f * 32 + 28);
  323. /* FIXME: check for return value */
  324. for(n = width * height; n--; )
  325. {
  326. int x = (n % width) - cv->frames[f].handlex - xmin;
  327. int y = (n / width) - cv->frames[f].handley - ymin;
  328. caca_put_char(cv, x, y, sscanu32(buf + 4 + control_size
  329. + offset + 8 * n));
  330. caca_put_attr(cv, x, y, sscanu32(buf + 4 + control_size
  331. + offset + 8 * n + 4));
  332. }
  333. offset += width * height * 8;
  334. cv->frames[f].x -= cv->frames[f].handlex;
  335. cv->frames[f].y -= cv->frames[f].handley;
  336. cv->frames[f].handlex = -xmin;
  337. cv->frames[f].handley = -ymin;
  338. }
  339. caca_set_frame(cv, 0);
  340. return (ssize_t)(4 + control_size + data_size);
  341. invalid_caca:
  342. seterrno(EINVAL);
  343. return -1;
  344. }
  345. /*
  346. * XXX: The following functions are aliases.
  347. */
  348. ssize_t cucul_import_memory(cucul_canvas_t *, void const *, size_t,
  349. char const *) CACA_ALIAS(caca_import_canvas_from_memory);
  350. ssize_t cucul_import_file(cucul_canvas_t *, char const *,
  351. char const *) CACA_ALIAS(caca_import_canvas_from_file);
  352. ssize_t caca_import_memory(caca_canvas_t *, void const *, size_t, char const *)
  353. CACA_ALIAS(caca_import_canvas_from_memory);
  354. ssize_t caca_import_file(caca_canvas_t *, char const *, char const *)
  355. CACA_ALIAS(caca_import_canvas_from_file);
  356. char const * const * cucul_get_import_list(void)
  357. CACA_ALIAS(caca_get_import_list);