shp_ts_file.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*
  2. XCC Utilities and Library
  3. Copyright (C) 2000 Olaf van der Spek <[email protected]>
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "stdafx.h"
  16. #include "shp_ts_file.h"
  17. #include "image_file.h"
  18. #include "shp_decode.h"
  19. #include "string_conversion.h"
  20. #ifndef XCC_MINIMAL_BUILD
  21. #include "xcc_log.h"
  22. #endif
  23. class Cshp_ts_decoder : public Cvideo_decoder
  24. {
  25. public:
  26. int cb_pixel() const
  27. {
  28. return m_f.cb_pixel();
  29. }
  30. int cf() const
  31. {
  32. return m_f.cf();
  33. }
  34. int cx() const
  35. {
  36. return m_f.cx();
  37. }
  38. int cy() const
  39. {
  40. return m_f.cy();
  41. }
  42. int decode(void* d0)
  43. {
  44. if (m_frame_i >= cf())
  45. return 1;
  46. byte* d = reinterpret_cast<byte*>(d0);
  47. Cvirtual_binary s;
  48. const int cx = m_f.get_cx(m_frame_i);
  49. const int cy = m_f.get_cy(m_frame_i);
  50. const byte* r;
  51. if (m_f.is_compressed(m_frame_i))
  52. {
  53. decode3(m_f.get_image(m_frame_i), s.write_start(cx * cy), cx, cy);
  54. r = s.data();
  55. }
  56. else
  57. r = m_f.get_image(m_frame_i);
  58. memset(d, 0, cb_image());
  59. byte* w = d + m_f.get_x(m_frame_i) + Cshp_ts_decoder::cx() * m_f.get_y(m_frame_i);
  60. for (int y = 0; y < cy; y++)
  61. {
  62. memcpy(w, r, cx);
  63. r += cx;
  64. w += Cshp_ts_decoder::cx();
  65. }
  66. m_frame_i++;
  67. return 0;
  68. }
  69. const t_palet_entry* palet() const
  70. {
  71. return m_palet;
  72. }
  73. int seek(int f)
  74. {
  75. m_frame_i = f;
  76. return 0;
  77. }
  78. Cshp_ts_decoder(const Cshp_ts_file& f, const t_palet_entry* palet)
  79. {
  80. m_f.load(f);
  81. m_frame_i = 0;
  82. memcpy(m_palet, palet, sizeof(t_palet));
  83. }
  84. private:
  85. Cshp_ts_file m_f;
  86. int m_frame_i;
  87. t_palet m_palet;
  88. };
  89. Cvideo_decoder* Cshp_ts_file::decoder(const t_palet_entry* palet)
  90. {
  91. return new Cshp_ts_decoder(*this, palet);
  92. }
  93. bool Cshp_ts_file::is_valid() const
  94. {
  95. const t_shp_ts_header& h = header();
  96. int size = get_size();
  97. if (sizeof(t_shp_ts_header) > size ||
  98. h.zero ||
  99. h.c_images < 1 || h.c_images > 10000 ||
  100. sizeof(t_shp_ts_header) + get_cb_index() > size)
  101. return false;
  102. for (int i = 0; i < min(cf(), 1000); i++)
  103. {
  104. const t_shp_ts_image_header& image_header = *get_image_header(i);
  105. if (!image_header.cx && !image_header.cy && !image_header.offset)
  106. continue;
  107. if (!image_header.cx || image_header.x + image_header.cx > h.cx ||
  108. !image_header.cy || image_header.y + image_header.cy > h.cy ||
  109. image_header.zero ||
  110. image_header.offset < sizeof(t_shp_ts_header) + get_cb_index())
  111. return false;
  112. if (is_compressed(i))
  113. {
  114. if (image_header.offset > size)
  115. return false;
  116. }
  117. else
  118. {
  119. if (image_header.offset + image_header.cx * image_header.cy > size)
  120. return false;
  121. }
  122. }
  123. return true;
  124. }
  125. int get_ofs(int x, int y, int cx, int cy)
  126. {
  127. return x + cx * y;
  128. }
  129. #ifndef XCC_MINIMAL_BUILD
  130. int Cshp_ts_file::extract_as_pcx(const Cfname& name, t_file_type ft, const t_palet _palet, bool combine_shadows) const
  131. {
  132. t_palet palet;
  133. convert_palet_18_to_24(_palet, palet);
  134. int error = 0;
  135. const int global_cx = cx();
  136. const int global_cy = cy();
  137. const int c_images = cf();
  138. if (combine_shadows && ~c_images & 1)
  139. {
  140. bool shadow = false;
  141. byte* image = new byte[global_cx * global_cy];
  142. byte* d = new byte[global_cx * global_cy * c_images >> 1];
  143. byte* w = d;
  144. for (int i = 0; i < c_images; i++)
  145. {
  146. const int cx = get_cx(i);
  147. const int cy = get_cy(i);
  148. const byte* r;
  149. if (is_compressed(i))
  150. {
  151. decode3(get_image(i), image, cx, cy);
  152. r = image;
  153. }
  154. else
  155. r = get_image(i);
  156. if (!shadow)
  157. {
  158. if (i == c_images >> 1)
  159. {
  160. shadow = true;
  161. w = d;
  162. }
  163. else
  164. memset(w, 0, global_cx * global_cy);
  165. }
  166. byte* w_start = w;
  167. w += get_x(i) + global_cx * get_y(i);
  168. for (int y = 0; y < cy; y++)
  169. {
  170. if (shadow)
  171. {
  172. for (int x = 0; x < cx; x++)
  173. {
  174. if (*r++)
  175. w[x] = 4;
  176. }
  177. }
  178. else
  179. {
  180. memcpy(w, r, cx);
  181. r += cx;
  182. }
  183. w += global_cx;
  184. }
  185. if (shadow)
  186. {
  187. Cfname t = name;
  188. t.set_title(name.get_ftitle() + " " + nwzl(4, i - (c_images >> 1)));
  189. error = image_file_write(t, ft, w_start, palet, global_cx, global_cy);
  190. if (error)
  191. break;
  192. }
  193. w = w_start + global_cx * global_cy;
  194. }
  195. delete[] d;
  196. delete[] image;
  197. }
  198. else
  199. {
  200. byte* image = new byte[global_cx * global_cy];
  201. byte* s = new byte[global_cx * global_cy];
  202. for (int i = 0; i < c_images; i++)
  203. {
  204. const int cx = get_cx(i);
  205. const int cy = get_cy(i);
  206. const byte* r;
  207. if (is_compressed(i))
  208. {
  209. decode3(get_image(i), image, cx, cy);
  210. r = image;
  211. }
  212. else
  213. r = get_image(i);
  214. memset(s, 0, global_cx * global_cy);
  215. byte* w = s + get_x(i) + global_cx * get_y(i);
  216. for (int y = 0; y < cy; y++)
  217. {
  218. memcpy(w, r, cx);
  219. r += cx;
  220. w += global_cx;
  221. }
  222. // xcc_log::write_line("<tr><td>" + name.get_ftitle() + "</td><td><img src=" + name.get_fname() + "></td></tr>");
  223. Cfname t = name;
  224. t.set_title(name.get_ftitle() + " " + nwzl(4, i));
  225. error = image_file_write(t, ft, s, palet, global_cx, global_cy);
  226. if (error)
  227. break;
  228. }
  229. delete[] s;
  230. delete[] image;
  231. }
  232. return error;
  233. }
  234. Cvirtual_image Cshp_ts_file::extract_as_pcx_single(const t_palet _palet, bool combine_shadows) const
  235. {
  236. t_palet palet;
  237. convert_palet_18_to_24(_palet, palet);
  238. const int global_cx = cx();
  239. const int global_cy = cy();
  240. int c_images = cf();
  241. combine_shadows &= ~c_images & 1;
  242. if (combine_shadows)
  243. c_images >>= 1;
  244. const int cblocks_x = min(c_images, 1024 / global_cx);
  245. const int cblocks_y = (c_images + cblocks_x - 1) / cblocks_x;
  246. int cx_s = cblocks_x * global_cx;
  247. int cy_s = cblocks_y * global_cy;
  248. Cvirtual_binary image;
  249. Cvirtual_binary s;
  250. memset(s.write_start(cx_s * cy_s), 0, cx_s * cy_s);
  251. if (combine_shadows)
  252. {
  253. c_images <<= 1;
  254. bool shadow = false;
  255. for (int i = 0; i < c_images; i++)
  256. {
  257. const int cx = get_cx(i);
  258. const int cy = get_cy(i);
  259. const byte* r;
  260. if (is_compressed(i))
  261. {
  262. decode3(get_image(i), image.write_start(global_cx * global_cy), cx, cy);
  263. r = image.data();
  264. }
  265. else
  266. r = get_image(i);
  267. if (!shadow && i == c_images >> 1)
  268. shadow = true;
  269. int j = i % (c_images >> 1);
  270. byte* w = s.data_edit() + get_ofs(j % cblocks_x * global_cx + get_x(i), j / cblocks_x * global_cy + get_y(i), cx_s, cy_s);
  271. for (int y = 0; y < cy; y++)
  272. {
  273. if (shadow)
  274. {
  275. for (int x = 0; x < cx; x++)
  276. {
  277. if (*r++)
  278. w[x] = 4;
  279. }
  280. }
  281. else
  282. {
  283. memcpy(w, r, cx);
  284. r += cx;
  285. }
  286. w += cx_s;
  287. }
  288. }
  289. }
  290. else
  291. {
  292. for (int i = 0; i < c_images; i++)
  293. {
  294. const int cx = get_cx(i);
  295. const int cy = get_cy(i);
  296. const byte* r;
  297. if (is_compressed(i))
  298. {
  299. decode3(get_image(i), image.write_start(global_cx * global_cy), cx, cy);
  300. r = image.data();
  301. }
  302. else
  303. r = get_image(i);
  304. byte* w = s.data_edit() + get_ofs(i % cblocks_x * global_cx + get_x(i), i / cblocks_x * global_cy + get_y(i), cx_s, cy_s);
  305. for (int y = 0; y < cy; y++)
  306. {
  307. memcpy(w, r, cx);
  308. r += cx;
  309. w += cx_s;
  310. }
  311. }
  312. }
  313. return Cvirtual_image(s, cx_s, cy_s, 1, palet);
  314. }
  315. void shp_split_frames(Cvirtual_image& image, int cblocks_x, int cblocks_y)
  316. {
  317. int cx = image.cx() / cblocks_x;
  318. int cy = image.cy() / cblocks_y;
  319. int cx_d = image.cx() / cblocks_x;
  320. int cy_d = image.cy() * cblocks_x;
  321. byte* d = new byte[cx_d * cy_d];
  322. byte* w = d;
  323. const byte* r_line = image.image();
  324. for (int yb = 0; yb < cblocks_y; yb++)
  325. {
  326. for (int xb = 0; xb < cblocks_x; xb++)
  327. {
  328. const byte* r = r_line + cx * xb;
  329. for (int y = 0; y < cy; y++)
  330. {
  331. memcpy(w, r, cx);
  332. r += image.cx();
  333. w += cx_d;
  334. }
  335. }
  336. r_line += image.cx() * cy;
  337. }
  338. image.load(d, cx_d, cy_d, image.cb_pixel(), image.palet());
  339. delete[] d;
  340. }
  341. void shp_split_shadows(Cvirtual_image& image)
  342. {
  343. int cx = image.cx();
  344. int cy = image.cy();
  345. int count = cx * cy;
  346. byte* d = new byte[count << 1];
  347. memcpy(d, image.image(), count);
  348. byte* r = d;
  349. byte* w = d + count;
  350. while (count--)
  351. {
  352. byte& v = *r++;
  353. if (v == 4)
  354. {
  355. v = 0;
  356. *w++ = 1;
  357. }
  358. else
  359. *w++ = 0;
  360. }
  361. image.load(d, cx, cy << 1, image.cb_pixel(), image.palet());
  362. delete[] d;
  363. }
  364. #endif
  365. /*
  366. void shp_xor_decode_frames(Cvirtual_image& image, int c_frames)
  367. {
  368. int cx = image.cx();
  369. int cy = image.cy() / c_frames;
  370. int count = cx * cy * (c_frames - 1);
  371. const byte* r = image.image();
  372. byte* w = image.image_edit() + cx * cy;
  373. while (count--)
  374. {
  375. *w++ ^= *r++;
  376. }
  377. }
  378. void shp_xor_encode_frames(Cvirtual_image& image, int c_frames)
  379. {
  380. int cx = image.cx();
  381. int cy = image.cy() / c_frames;
  382. int count = cx * cy * c_frames;
  383. byte* w = image.image_edit() + count;
  384. count -= cx * cy;
  385. const byte* r = image.image() + count;
  386. while (count--)
  387. {
  388. *--w ^= *--r;
  389. }
  390. }
  391. */
  392. static int get_left_margin(const byte* r, int cx)
  393. {
  394. int c = 0;
  395. while (cx-- && !*r++)
  396. c++;
  397. return c;
  398. }
  399. static int get_right_margin(const byte* r, int cx)
  400. {
  401. int c = 0;
  402. while (cx-- && !*--r)
  403. c++;
  404. return c;
  405. }
  406. static int encode4_line(const byte* r, byte* d, int cx)
  407. {
  408. const byte* s_end = r + cx;
  409. byte* w = d;
  410. while (r < s_end)
  411. {
  412. int v = *w++ = *r++;
  413. if (!v)
  414. {
  415. int c = min(get_run_length(r - 1, s_end), 0xff);
  416. r += c - 1;
  417. *w++ = c;
  418. }
  419. }
  420. return w - d;
  421. }
  422. static int decode4_line_size(const byte*& r, int cx)
  423. {
  424. int w = 0;
  425. while (cx--)
  426. {
  427. w++;
  428. if (!*r++)
  429. {
  430. cx -= *r++ - 1;
  431. w++;
  432. }
  433. }
  434. return w;
  435. }
  436. static int decode4_line(const byte* s, byte*& w, int cx)
  437. {
  438. const byte* r = s;
  439. while (cx--)
  440. {
  441. if (!(*w++ = *r++))
  442. cx -= (*w++ = *r++) - 1;
  443. }
  444. return r - s;
  445. }
  446. static int encode4(const byte* s, byte* d, int cx, int cy)
  447. {
  448. const byte* s_end = s + cx * cy;
  449. const byte* r = s;
  450. byte* w = d;
  451. for (int y = 0; y < cy; y++)
  452. {
  453. int lm = min(get_left_margin(r, cx), 0xff);
  454. int rm = min(get_right_margin(r + cx, cx - lm), 0xff);
  455. *w++ = lm;
  456. *w++ = rm;
  457. w += encode4_line(r + lm, w, cx - lm - rm);
  458. r += cx;
  459. }
  460. return w - d;
  461. }
  462. static int decode4_size(const byte*& r, int cx, int cy)
  463. {
  464. int w = 0;
  465. for (int y = 0; y < cy; y++)
  466. {
  467. int lm = *r++;
  468. int rm = *r++;
  469. w += 2;
  470. if (lm)
  471. w += 2;
  472. w += decode4_line_size(r, cx - lm - rm);
  473. if (rm)
  474. w += 2;
  475. }
  476. return w;
  477. }
  478. static int decode4(const byte* s, byte*& w, int cx, int cy)
  479. {
  480. const byte* r = s;
  481. for (int y = 0; y < cy; y++)
  482. {
  483. int lm = *r++;
  484. int rm = *r++;
  485. byte* w_line = w;
  486. w += 2;
  487. if (lm)
  488. {
  489. *w++ = 0;
  490. *w++ = lm;
  491. }
  492. r += decode4_line(r, w, cx - lm - rm);
  493. if (rm)
  494. {
  495. *w++ = 0;
  496. *w++ = rm;
  497. }
  498. *reinterpret_cast<unsigned __int16*>(w_line) = w - w_line;
  499. }
  500. return r - s;
  501. }
  502. struct t_shp4_header
  503. {
  504. unsigned __int16 cx;
  505. unsigned __int16 cy;
  506. unsigned __int16 c_frames;
  507. };
  508. struct t_shp4_frame_header
  509. {
  510. unsigned __int8 lm;
  511. unsigned __int8 rm;
  512. unsigned __int8 tm;
  513. unsigned __int8 bm;
  514. };
  515. int shp_encode4(const Cshp_ts_file& f, byte* d)
  516. {
  517. const int global_cx = f.cx();
  518. const int global_cy = f.cy();
  519. const int c_frames = f.cf();
  520. byte* w = d;
  521. t_shp4_header& header = *reinterpret_cast<t_shp4_header*>(w);
  522. header.cx = global_cx;
  523. header.cy = global_cy;
  524. header.c_frames = c_frames;
  525. w += sizeof(t_shp4_header);
  526. for (int i = 0; i < c_frames; i++)
  527. {
  528. const t_shp_ts_image_header& image_header = *f.get_image_header(i);
  529. const int cx = image_header.cx;
  530. const int cy = image_header.cy;
  531. t_shp4_frame_header& frame_header = *reinterpret_cast<t_shp4_frame_header*>(w);
  532. if (image_header.cx && image_header.cy)
  533. {
  534. frame_header.lm = image_header.x;
  535. frame_header.tm = image_header.y;
  536. }
  537. else
  538. {
  539. frame_header.lm = min(global_cx, 0xff);
  540. frame_header.tm = min(global_cy, 0xff);
  541. }
  542. if (global_cx - frame_header.lm - cx > 0xff
  543. || global_cy - frame_header.tm - cy > 0xff)
  544. return 0;
  545. frame_header.rm = global_cx - frame_header.lm - cx;
  546. frame_header.bm = global_cy - frame_header.tm - cy;
  547. w += sizeof(t_shp4_frame_header);
  548. if (f.is_compressed(i))
  549. {
  550. Cvirtual_binary image;
  551. decode3(f.get_image(i), image.write_start(cx * cy), cx, cy);
  552. w += encode4(image.data(), w, cx, cy);
  553. }
  554. else
  555. w += encode4(f.get_image(i), w, cx, cy);
  556. }
  557. return w - d;
  558. }
  559. int shp_decode4_size(const byte* s)
  560. {
  561. Cvirtual_binary d;
  562. const byte* r = s;
  563. const t_shp4_header& s_header = *reinterpret_cast<const t_shp4_header*>(r);
  564. const int global_cx = s_header.cx;
  565. const int global_cy = s_header.cy;
  566. const int c_frames = s_header.c_frames;
  567. r += sizeof(t_shp4_header);
  568. int w = 0;
  569. for (int i = 0; i < c_frames; i++)
  570. {
  571. const t_shp4_frame_header& frame_header = *reinterpret_cast<const t_shp4_frame_header*>(r);
  572. int x = frame_header.lm;
  573. int y = frame_header.tm;
  574. int cx = global_cx - x - frame_header.rm;
  575. int cy = global_cy - y - frame_header.bm;
  576. r += sizeof(t_shp4_frame_header);
  577. if (cy)
  578. w += decode4_size(r, cx, cy);
  579. w = w + 7 & ~7;
  580. }
  581. return w
  582. + sizeof(t_shp_ts_header)
  583. + c_frames * sizeof(t_shp_ts_image_header);
  584. }
  585. Cvirtual_binary shp_decode4(const byte* s, int cb_d)
  586. {
  587. Cvirtual_binary d;
  588. const byte* r = s;
  589. const t_shp4_header& s_header = *reinterpret_cast<const t_shp4_header*>(r);
  590. const int global_cx = s_header.cx;
  591. const int global_cy = s_header.cy;
  592. const int c_frames = s_header.c_frames;
  593. r += sizeof(t_shp4_header);
  594. byte* w = d.write_start(cb_d ? cb_d : Cshp_ts_file::get_max_size(global_cx, global_cy, c_frames));
  595. t_shp_ts_header& header = *reinterpret_cast<t_shp_ts_header*>(w);
  596. header.zero = 0;
  597. header.cx = global_cx;
  598. header.cy = global_cy;
  599. header.c_images = c_frames;
  600. w += sizeof(t_shp_ts_header);
  601. byte* w1 = w + c_frames * sizeof(t_shp_ts_image_header);
  602. for (int i = 0; i < c_frames; i++)
  603. {
  604. const t_shp4_frame_header& frame_header = *reinterpret_cast<const t_shp4_frame_header*>(r);
  605. int x = frame_header.lm;
  606. int y = frame_header.tm;
  607. int cx = global_cx - x - frame_header.rm;
  608. int cy = global_cy - y - frame_header.bm;
  609. r += sizeof(t_shp4_frame_header);
  610. t_shp_ts_image_header& image_header = *reinterpret_cast<t_shp_ts_image_header*>(w);
  611. image_header.x = x;
  612. image_header.y = y;
  613. image_header.cx = cx;
  614. image_header.cy = cy;
  615. image_header.compression = 3;
  616. image_header.unknown = 0;
  617. image_header.zero = 0;
  618. image_header.offset = w1 - d.data();
  619. w += sizeof(t_shp_ts_image_header);
  620. if (cy)
  621. r += decode4(r, w1, cx, cy);
  622. else
  623. image_header.offset = 0;
  624. w1 = d.data_edit() + (w1 - d.data() + 7 & ~7);
  625. }
  626. assert(!cb_d || d.size() == w1 - d.data());
  627. return cb_d ? d : Cvirtual_binary(d.data(), w1 - d.data());
  628. }