copypaste.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * sfnedit/copypaste.c
  3. *
  4. * Copyright (C) 2019 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief Copypaste functions
  27. *
  28. */
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include "libsfn.h"
  33. #ifdef __WIN32__
  34. #include <windows.h>
  35. #endif
  36. /* Don't use zlib, too slow on big sets. Disk cache is much faster. */
  37. /*
  38. #ifdef HAS_ZLIB
  39. #include <zlib.h>
  40. #define CPFILE gzFile
  41. #define CPOPEN gzopen
  42. #define CPCLOSE gzclose
  43. #define CPWRITE(a,b,c) gzwrite(c,a,b)
  44. #define CPREAD(a,b,c) gzread(c,a,b)
  45. #define CPEOF gzeof
  46. #else
  47. */
  48. #define CPFILE FILE*
  49. #define CPOPEN fopen
  50. #define CPCLOSE fclose
  51. #define CPWRITE(a,b,c) fwrite(a,b,1,c)
  52. #define CPREAD(a,b,c) fread(a,b,1,c)
  53. #define CPEOF feof
  54. /*
  55. #endif
  56. */
  57. /* clipboard file */
  58. char *copypaste_fn = NULL;
  59. /**
  60. * Initialize clipboard file.Uses local files as that's the simplest and most portable way to
  61. * share data between separate processes (sfnedit might run in multiple instances).
  62. */
  63. int copypaste_init()
  64. {
  65. #ifdef __WIN32__
  66. char *s;
  67. wchar_t tmp[MAX_PATH];
  68. DWORD i, l;
  69. #else
  70. char *home;
  71. #endif
  72. if(!copypaste_fn) {
  73. #ifdef __WIN32__
  74. tmp[0] = 0; l = GetTempPathW(MAX_PATH, tmp);
  75. if(!tmp[0] || l < 1 || l >= MAX_PATH || !(copypaste_fn = (char*)malloc(l + 16))) return 0;
  76. for(i = 0, s = copypaste_fn; tmp[i]; i++) {
  77. if(tmp[i] < 0x80) {
  78. *s++ = tmp[i];
  79. } else if(tmp[i] < 0x800) {
  80. *s++ = ((tmp[i]>>6)&0x1F)|0xC0;
  81. *s++ = (tmp[i]&0x3F)|0x80;
  82. } else {
  83. *s++ = ((tmp[i]>>12)&0x0F)|0xE0;
  84. *s++ = ((tmp[i]>>6)&0x3F)|0x80;
  85. *s++ = (tmp[i]&0x3F)|0x80;
  86. }
  87. }
  88. strcpy(s, "\\sfneditcb.dat");
  89. #else
  90. home = getenv("HOME");
  91. if(!home) home = "/tmp";
  92. copypaste_fn = (char*)malloc(strlen(home) + 16);
  93. if(copypaste_fn) sprintf(copypaste_fn, "%s/.sfneditcb", home);
  94. else return 0;
  95. #endif
  96. }
  97. return 1;
  98. }
  99. /**
  100. * Clean up resources
  101. */
  102. void copypaste_fini()
  103. {
  104. if(copypaste_fn) free(copypaste_fn);
  105. copypaste_fn = NULL;
  106. }
  107. /**
  108. * Clear clipboard and start copy session
  109. */
  110. void copypaste_start(int minunicode)
  111. {
  112. CPFILE f;
  113. if(!copypaste_init()) return;
  114. f = CPOPEN(copypaste_fn, "wb");
  115. if(f) {
  116. CPWRITE("CLBD", 4, f);
  117. CPWRITE(&minunicode, sizeof(int), f);
  118. CPCLOSE(f);
  119. }
  120. }
  121. /**
  122. * Copy a layer or all layers to clipboard (aka serialize to binary blob)
  123. */
  124. void copypaste_copy(int fromunicode, int layer)
  125. {
  126. CPFILE f;
  127. int i, j, s, e, r;
  128. uint32_t c;
  129. (void)r;
  130. if(!copypaste_init() || fromunicode < 0 || fromunicode > 0x10FFFF || layer >= ctx.glyphs[fromunicode].numlayer ||
  131. (!ctx.glyphs[fromunicode].numlayer && !ctx.glyphs[fromunicode].adv_x && !ctx.glyphs[fromunicode].adv_y)) return;
  132. f = CPOPEN(copypaste_fn, "ab");
  133. if(f) {
  134. if(layer < 0) {
  135. r = CPWRITE("C", 1, f);
  136. r = CPWRITE(&fromunicode, sizeof(int), f);
  137. r = CPWRITE(&ctx.glyphs[fromunicode].width, 1, f);
  138. r = CPWRITE(&ctx.glyphs[fromunicode].height, 1, f);
  139. r = CPWRITE(&ctx.glyphs[fromunicode].ovl_x, 1, f);
  140. r = CPWRITE(&ctx.glyphs[fromunicode].adv_x, 1, f);
  141. r = CPWRITE(&ctx.glyphs[fromunicode].adv_y, 1, f);
  142. r = CPWRITE(&ctx.glyphs[fromunicode].rtl, 1, f);
  143. r = CPWRITE(&ctx.glyphs[fromunicode].hintv, 33, f);
  144. r = CPWRITE(&ctx.glyphs[fromunicode].hinth, 33, f);
  145. r = CPWRITE(&ctx.glyphs[fromunicode].numkern, sizeof(int), f);
  146. if(ctx.glyphs[fromunicode].numkern)
  147. r = CPWRITE(ctx.glyphs[fromunicode].kern, sizeof(sfnkern_t) * ctx.glyphs[fromunicode].numkern, f);
  148. s = 0; e = ctx.glyphs[fromunicode].numlayer;
  149. } else { s = layer; e = layer + 1; }
  150. for(i = s; i < e; i++) {
  151. r = CPWRITE("L", 1, f);
  152. r = CPWRITE(&fromunicode, sizeof(int), f);
  153. r = CPWRITE(&ctx.glyphs[fromunicode].layers[i].type, 1, f);
  154. c = ctx.glyphs[fromunicode].layers[i].color == 0xFF ? 0x00FFFFFF : (ctx.glyphs[fromunicode].layers[i].color == 0xFE ?
  155. 0x00FEFEFE : ctx.cpal[ctx.glyphs[fromunicode].layers[i].color]);
  156. r = CPWRITE(&c, 4, f);
  157. r = CPWRITE(&ctx.glyphs[fromunicode].width, 1, f);
  158. r = CPWRITE(&ctx.glyphs[fromunicode].height, 1, f);
  159. if(ctx.glyphs[fromunicode].layers[i].data)
  160. switch(ctx.glyphs[fromunicode].layers[i].type) {
  161. case SSFN_FRAG_CONTOUR:
  162. r = CPWRITE(&ctx.glyphs[fromunicode].layers[i].len, sizeof(int), f);
  163. r = CPWRITE(ctx.glyphs[fromunicode].layers[i].data, sizeof(sfncont_t) * ctx.glyphs[fromunicode].layers[i].len,
  164. f);
  165. break;
  166. case SSFN_FRAG_BITMAP:
  167. r = CPWRITE(ctx.glyphs[fromunicode].layers[i].data, ctx.glyphs[fromunicode].width *
  168. ctx.glyphs[fromunicode].height, f);
  169. break;
  170. case SSFN_FRAG_PIXMAP:
  171. for(j = 0; j < ctx.glyphs[fromunicode].width * ctx.glyphs[fromunicode].height; j++) {
  172. c = ctx.glyphs[fromunicode].layers[i].data[j] == 0xFF ? 0x00FFFFFF :
  173. (ctx.glyphs[fromunicode].layers[i].data[j] == 0xFE ?
  174. 0x00FEFEFE : ctx.cpal[ctx.glyphs[fromunicode].layers[i].data[j]]);
  175. r = CPWRITE(&c, 4, f);
  176. }
  177. break;
  178. }
  179. }
  180. CPCLOSE(f);
  181. }
  182. }
  183. /**
  184. * Paste data from clipboard (aka deserialize from binary blob)
  185. */
  186. void copypaste_paste(int tounicode, int oneunicode)
  187. {
  188. CPFILE f;
  189. char tmp;
  190. unsigned char c[72], *data = NULL;
  191. int unicode = 0, minunicode = 0, last = -1, i, j, l = 0, t = 0, w = 0, h = 0, r;
  192. sfnlayer_t *lyr;
  193. (void)r;
  194. if(!copypaste_init()) return;
  195. f = CPOPEN(copypaste_fn, "rb");
  196. if(f) {
  197. r = CPREAD(&c, 4, f);
  198. r = CPREAD(&minunicode, sizeof(int), f);
  199. if(c[0] == 'C' && c[1] == 'L' && c[2] == 'B' && c[3] == 'D')
  200. while(!CPEOF(f)) {
  201. tmp = 0; r = CPREAD(&tmp, 1, f); if(!tmp) break;
  202. switch(tmp) {
  203. case 'C': /* character chunk */
  204. r = CPREAD(&unicode, sizeof(int), f); if(tounicode) { unicode -= minunicode; unicode += tounicode; }
  205. if(oneunicode) {
  206. unicode = tounicode;
  207. r = CPREAD(&c, 72, f);
  208. r = CPREAD(&i, sizeof(int), f);
  209. for(; i > 0; i--)
  210. r = CPREAD(&c, sizeof(sfnkern_t), f);
  211. } else {
  212. sfn_chardel(unicode);
  213. r = CPREAD(&ctx.glyphs[unicode].width, 1, f);
  214. r = CPREAD(&ctx.glyphs[unicode].height, 1, f);
  215. r = CPREAD(&ctx.glyphs[unicode].ovl_x, 1, f);
  216. r = CPREAD(&ctx.glyphs[unicode].adv_x, 1, f);
  217. r = CPREAD(&ctx.glyphs[unicode].adv_y, 1, f);
  218. r = CPREAD(&ctx.glyphs[unicode].rtl, 1, f);
  219. r = CPREAD(&ctx.glyphs[unicode].hintv, 33, f);
  220. r = CPREAD(&ctx.glyphs[unicode].hinth, 33, f);
  221. r = CPREAD(&ctx.glyphs[unicode].numkern, sizeof(int), f);
  222. if(ctx.glyphs[unicode].numkern) {
  223. ctx.glyphs[unicode].kern = (sfnkern_t*)malloc(sizeof(sfnkern_t) * ctx.glyphs[unicode].numkern);
  224. if(ctx.glyphs[unicode].kern)
  225. r = CPREAD(ctx.glyphs[unicode].kern, sizeof(sfnkern_t) * ctx.glyphs[unicode].numkern, f);
  226. }
  227. }
  228. break;
  229. case 'L': /* glyph layer chunk */
  230. r = CPREAD(&unicode, sizeof(int), f); if(tounicode) { unicode -= minunicode; unicode += tounicode; }
  231. if(last == -1) last = unicode;
  232. else if(oneunicode && last != unicode) { CPCLOSE(f); return; }
  233. if(oneunicode) unicode = tounicode;
  234. r = CPREAD(&t, 1, f);
  235. r = CPREAD(&c, 4, f); i = !c[3] && c[0] == 0xFE ? 0xFE : (!c[3] && c[0] == 0xFF ? 0xFF :
  236. sfn_cpaladd(c[2], c[1], c[0], c[3]));
  237. w = 0; r = CPREAD(&w, 1, f);
  238. h = 0; r = CPREAD(&h, 1, f);
  239. switch(t) {
  240. case SSFN_FRAG_CONTOUR:
  241. r = CPREAD(&l, sizeof(int), f);
  242. if(l > 0 && (lyr = sfn_layeradd(unicode, t, 0, 0, w, h, i, NULL)) != NULL) {
  243. lyr->data = realloc(lyr->data, l * sizeof(sfncont_t));
  244. if(lyr->data) { lyr->len = l; r = CPREAD(lyr->data, l * sizeof(sfncont_t), f); }
  245. }
  246. break;
  247. case SSFN_FRAG_BITMAP:
  248. data = realloc(data, w * h);
  249. if(data) {
  250. r = CPREAD(data, w * h, f);
  251. sfn_layeradd(unicode, t, 0, 0, w, h, i, data);
  252. }
  253. break;
  254. case SSFN_FRAG_PIXMAP:
  255. data = realloc(data, w * h);
  256. if(data) {
  257. for(j = 0; j < w * h; j++) {
  258. r = CPREAD(&c, 4, f);
  259. data[j] = !c[3] && c[0] == 0xFE ? 0xFE : (!c[3] && c[0] == 0xFF ? 0xFF :
  260. sfn_cpaladd(c[2], c[1], c[0], c[3]));
  261. }
  262. sfn_layeradd(unicode, t, 0, 0, w, h, i, data);
  263. }
  264. break;
  265. }
  266. if(ctx.glyphs[unicode].width > ctx.width) ctx.width = ctx.glyphs[unicode].width;
  267. if(ctx.glyphs[unicode].height > ctx.height) ctx.height = ctx.glyphs[unicode].height;
  268. if(ctx.glyphs[unicode].ovl_x > 63) ctx.glyphs[unicode].ovl_x = 63;
  269. if(ctx.glyphs[unicode].adv_x) ctx.glyphs[unicode].adv_y = 0;
  270. break;
  271. case 'P': /* contour path chunk */
  272. break;
  273. }
  274. }
  275. CPCLOSE(f);
  276. }
  277. }