n2_99.ch 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /* n2_99.ch -- implementation of the NRV2[BDE]-99 compression algorithms
  2. This file is part of the UCL data compression library.
  3. Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
  4. All Rights Reserved.
  5. The UCL library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of
  8. the License, or (at your option) any later version.
  9. The UCL library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with the UCL library; see the file COPYING.
  15. If not, write to the Free Software Foundation, Inc.,
  16. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. Markus F.X.J. Oberhumer
  18. <markus@oberhumer.com>
  19. http://www.oberhumer.com/opensource/ucl/
  20. */
  21. #include "uclconf.h"
  22. #include "ucl.h"
  23. #include "ucl_conf.h"
  24. #if 0
  25. #undef UCL_DEBUG
  26. #define UCL_DEBUG
  27. #endif
  28. #include <stdio.h>
  29. #if 0 && !defined(UCL_DEBUG)
  30. #undef NDEBUG
  31. #include <assert.h>
  32. #endif
  33. /***********************************************************************
  34. //
  35. ************************************************************************/
  36. #if 0
  37. #define N (128*1024ul) /* size of ring buffer */
  38. #else
  39. #define N (1024*1024ul) /* size of ring buffer */
  40. #define SWD_USE_MALLOC
  41. #define SWD_HSIZE 65536ul
  42. #endif
  43. #define THRESHOLD 1 /* lower limit for match length */
  44. #define F 2048 /* upper limit for match length */
  45. #if defined(NRV2B)
  46. # define UCL_COMPRESS_T ucl_nrv2b_t
  47. # define ucl_swd_t ucl_nrv2b_swd_t
  48. # define ucl_nrv_99_compress ucl_nrv2b_99_compress
  49. # define M2_MAX_OFFSET 0xd00
  50. #elif defined(NRV2D)
  51. # define UCL_COMPRESS_T ucl_nrv2d_t
  52. # define ucl_swd_t ucl_nrv2d_swd_t
  53. # define ucl_nrv_99_compress ucl_nrv2d_99_compress
  54. # define M2_MAX_OFFSET 0x500
  55. #elif defined(NRV2E)
  56. # define UCL_COMPRESS_T ucl_nrv2e_t
  57. # define ucl_swd_t ucl_nrv2e_swd_t
  58. # define ucl_nrv_99_compress ucl_nrv2e_99_compress
  59. # define M2_MAX_OFFSET 0x500
  60. #else
  61. # error
  62. #endif
  63. #define ucl_swd_p ucl_swd_t * __UCL_MMODEL
  64. #if 0
  65. # define HEAD3(b,p) \
  66. ((((((ucl_uint32)b[p]<<3)^b[p+1])<<3)^b[p+2]) & (SWD_HSIZE-1))
  67. #endif
  68. #if 0 && defined(UCL_UNALIGNED_OK_4) && (UCL_BYTE_ORDER == UCL_LITTLE_ENDIAN)
  69. # define HEAD3(b,p) \
  70. (((* (ucl_uint32p) &b[p]) ^ ((* (ucl_uint32p) &b[p])>>10)) & (SWD_HSIZE-1))
  71. #endif
  72. #include "ucl_mchw.ch"
  73. /***********************************************************************
  74. //
  75. ************************************************************************/
  76. static void code_prefix_ss11(UCL_COMPRESS_T *c, ucl_uint32 i)
  77. {
  78. if (i >= 2)
  79. {
  80. ucl_uint32 t = 4;
  81. i += 2;
  82. do {
  83. t <<= 1;
  84. } while (i >= t);
  85. t >>= 1;
  86. do {
  87. t >>= 1;
  88. bbPutBit(c, (i & t) ? 1 : 0);
  89. bbPutBit(c, 0);
  90. } while (t > 2);
  91. }
  92. bbPutBit(c, (unsigned)i & 1);
  93. bbPutBit(c, 1);
  94. }
  95. #if defined(NRV2D) || defined(NRV2E)
  96. static void code_prefix_ss12(UCL_COMPRESS_T *c, ucl_uint32 i)
  97. {
  98. if (i >= 2)
  99. {
  100. ucl_uint32 t = 2;
  101. do {
  102. i -= t;
  103. t <<= 2;
  104. } while (i >= t);
  105. do {
  106. t >>= 1;
  107. bbPutBit(c, (i & t) ? 1 : 0);
  108. bbPutBit(c, 0);
  109. t >>= 1;
  110. bbPutBit(c, (i & t) ? 1 : 0);
  111. } while (t > 2);
  112. }
  113. bbPutBit(c, (unsigned)i & 1);
  114. bbPutBit(c, 1);
  115. }
  116. #endif
  117. static void
  118. code_match(UCL_COMPRESS_T *c, ucl_uint m_len, const ucl_uint m_off)
  119. {
  120. unsigned m_low = 0;
  121. while (m_len > c->conf.max_match)
  122. {
  123. code_match(c, c->conf.max_match - 3, m_off);
  124. m_len -= c->conf.max_match - 3;
  125. }
  126. c->match_bytes += m_len;
  127. if (m_len > c->result[3])
  128. c->result[3] = m_len;
  129. if (m_off > c->result[1])
  130. c->result[1] = m_off;
  131. bbPutBit(c, 0);
  132. #if defined(NRV2B)
  133. if (m_off == c->last_m_off)
  134. {
  135. bbPutBit(c, 0);
  136. bbPutBit(c, 1);
  137. }
  138. else
  139. {
  140. code_prefix_ss11(c, 1 + ((m_off - 1) >> 8));
  141. bbPutByte(c, (unsigned)m_off - 1);
  142. }
  143. m_len = m_len - 1 - (m_off > M2_MAX_OFFSET);
  144. if (m_len >= 4)
  145. {
  146. bbPutBit(c,0);
  147. bbPutBit(c,0);
  148. code_prefix_ss11(c, m_len - 4);
  149. }
  150. else
  151. {
  152. bbPutBit(c, m_len > 1);
  153. bbPutBit(c, (unsigned)m_len & 1);
  154. }
  155. #elif defined(NRV2D)
  156. m_len = m_len - 1 - (m_off > M2_MAX_OFFSET);
  157. assert(m_len > 0);
  158. m_low = (m_len >= 4) ? 0u : (unsigned) m_len;
  159. if (m_off == c->last_m_off)
  160. {
  161. bbPutBit(c, 0);
  162. bbPutBit(c, 1);
  163. bbPutBit(c, m_low > 1);
  164. bbPutBit(c, m_low & 1);
  165. }
  166. else
  167. {
  168. code_prefix_ss12(c, 1 + ((m_off - 1) >> 7));
  169. bbPutByte(c, ((((unsigned)m_off - 1) & 0x7f) << 1) | ((m_low > 1) ? 0 : 1));
  170. bbPutBit(c, m_low & 1);
  171. }
  172. if (m_len >= 4)
  173. code_prefix_ss11(c, m_len - 4);
  174. #elif defined(NRV2E)
  175. m_len = m_len - 1 - (m_off > M2_MAX_OFFSET);
  176. assert(m_len > 0);
  177. m_low = (m_len <= 2);
  178. if (m_off == c->last_m_off)
  179. {
  180. bbPutBit(c, 0);
  181. bbPutBit(c, 1);
  182. bbPutBit(c, m_low);
  183. }
  184. else
  185. {
  186. code_prefix_ss12(c, 1 + ((m_off - 1) >> 7));
  187. bbPutByte(c, ((((unsigned)m_off - 1) & 0x7f) << 1) | (m_low ^ 1));
  188. }
  189. if (m_low)
  190. bbPutBit(c, (unsigned)m_len - 1);
  191. else if (m_len <= 4)
  192. {
  193. bbPutBit(c, 1);
  194. bbPutBit(c, (unsigned)m_len - 3);
  195. }
  196. else
  197. {
  198. bbPutBit(c, 0);
  199. code_prefix_ss11(c, m_len - 5);
  200. }
  201. #else
  202. # error
  203. #endif
  204. c->last_m_off = m_off;
  205. UCL_UNUSED(m_low);
  206. }
  207. static void
  208. code_run(UCL_COMPRESS_T *c, const ucl_byte *ii, ucl_uint lit)
  209. {
  210. if (lit == 0)
  211. return;
  212. c->lit_bytes += lit;
  213. if (lit > c->result[5])
  214. c->result[5] = lit;
  215. do {
  216. bbPutBit(c, 1);
  217. bbPutByte(c, *ii++);
  218. } while (--lit > 0);
  219. }
  220. /***********************************************************************
  221. //
  222. ************************************************************************/
  223. static int
  224. len_of_coded_match(UCL_COMPRESS_T *c, ucl_uint m_len, ucl_uint m_off)
  225. {
  226. int b;
  227. if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
  228. || m_off > c->conf.max_offset)
  229. return -1;
  230. assert(m_off > 0);
  231. m_len = m_len - 2 - (m_off > M2_MAX_OFFSET);
  232. if (m_off == c->last_m_off)
  233. b = 1 + 2;
  234. else
  235. {
  236. #if defined(NRV2B)
  237. b = 1 + 10;
  238. m_off = (m_off - 1) >> 8;
  239. while (m_off > 0)
  240. {
  241. b += 2;
  242. m_off >>= 1;
  243. }
  244. #elif defined(NRV2D) || defined(NRV2E)
  245. b = 1 + 9;
  246. m_off = (m_off - 1) >> 7;
  247. while (m_off > 0)
  248. {
  249. b += 3;
  250. m_off >>= 2;
  251. }
  252. #else
  253. # error
  254. #endif
  255. }
  256. #if defined(NRV2B) || defined(NRV2D)
  257. b += 2;
  258. if (m_len < 3)
  259. return b;
  260. m_len -= 3;
  261. #elif defined(NRV2E)
  262. b += 2;
  263. if (m_len < 2)
  264. return b;
  265. if (m_len < 4)
  266. return b + 1;
  267. m_len -= 4;
  268. #else
  269. # error
  270. #endif
  271. do {
  272. b += 2;
  273. m_len >>= 1;
  274. } while (m_len > 0);
  275. return b;
  276. }
  277. /***********************************************************************
  278. //
  279. ************************************************************************/
  280. #if !defined(NDEBUG)
  281. static
  282. void assert_match( const ucl_swd_p swd, ucl_uint m_len, ucl_uint m_off )
  283. {
  284. const UCL_COMPRESS_T *c = swd->c;
  285. ucl_uint d_off;
  286. assert(m_len >= 2);
  287. if (m_off <= (ucl_uint) (c->bp - c->in))
  288. {
  289. assert(c->bp - m_off + m_len < c->ip);
  290. assert(ucl_memcmp(c->bp, c->bp - m_off, m_len) == 0);
  291. }
  292. else
  293. {
  294. assert(swd->dict != NULL);
  295. d_off = m_off - (ucl_uint) (c->bp - c->in);
  296. assert(d_off <= swd->dict_len);
  297. if (m_len > d_off)
  298. {
  299. assert(ucl_memcmp(c->bp, swd->dict_end - d_off, d_off) == 0);
  300. assert(c->in + m_len - d_off < c->ip);
  301. assert(ucl_memcmp(c->bp + d_off, c->in, m_len - d_off) == 0);
  302. }
  303. else
  304. {
  305. assert(ucl_memcmp(c->bp, swd->dict_end - d_off, m_len) == 0);
  306. }
  307. }
  308. }
  309. #else
  310. # define assert_match(a,b,c) ((void)0)
  311. #endif
  312. #if defined(SWD_BEST_OFF)
  313. static void
  314. better_match ( const ucl_swd_p swd, ucl_uint *m_len, ucl_uint *m_off )
  315. {
  316. }
  317. #endif
  318. /***********************************************************************
  319. //
  320. ************************************************************************/
  321. UCL_PUBLIC(int)
  322. ucl_nrv_99_compress ( const ucl_bytep in, ucl_uint in_len,
  323. ucl_bytep out, ucl_uintp out_len,
  324. ucl_progress_callback_p cb,
  325. int level,
  326. const struct ucl_compress_config_p conf,
  327. ucl_uintp result)
  328. {
  329. const ucl_byte *ii;
  330. ucl_uint lit;
  331. ucl_uint m_len, m_off;
  332. UCL_COMPRESS_T c_buffer;
  333. UCL_COMPRESS_T * const c = &c_buffer;
  334. #undef swd
  335. #if 1 && defined(SWD_USE_MALLOC)
  336. ucl_swd_t the_swd;
  337. # define swd (&the_swd)
  338. #else
  339. ucl_swd_p swd;
  340. #endif
  341. ucl_uint result_buffer[16];
  342. int r;
  343. struct swd_config_t
  344. {
  345. unsigned try_lazy;
  346. ucl_uint good_length;
  347. ucl_uint max_lazy;
  348. ucl_uint nice_length;
  349. ucl_uint max_chain;
  350. ucl_uint32 flags;
  351. ucl_uint32 max_offset;
  352. };
  353. const struct swd_config_t *sc;
  354. static const struct swd_config_t swd_config[10] = {
  355. /* faster compression */
  356. { 0, 0, 0, 8, 4, 0, 48*1024L },
  357. { 0, 0, 0, 16, 8, 0, 48*1024L },
  358. { 0, 0, 0, 32, 16, 0, 48*1024L },
  359. { 1, 4, 4, 16, 16, 0, 48*1024L },
  360. { 1, 8, 16, 32, 32, 0, 48*1024L },
  361. { 1, 8, 16, 128, 128, 0, 48*1024L },
  362. { 2, 8, 32, 128, 256, 0, 128*1024L },
  363. { 2, 32, 128, F, 2048, 1, 128*1024L },
  364. { 2, 32, 128, F, 2048, 1, 256*1024L },
  365. { 2, F, F, F, 4096, 1, N }
  366. /* max. compression */
  367. };
  368. if (level < 1 || level > 10)
  369. return UCL_E_INVALID_ARGUMENT;
  370. sc = &swd_config[level - 1];
  371. memset(c, 0, sizeof(*c));
  372. c->ip = c->in = in;
  373. c->in_end = in + in_len;
  374. c->out = out;
  375. if (cb && cb->callback)
  376. c->cb = cb;
  377. cb = NULL;
  378. c->result = result ? result : (ucl_uintp) result_buffer;
  379. memset(c->result, 0, 16*sizeof(*c->result));
  380. c->result[0] = c->result[2] = c->result[4] = UCL_UINT_MAX;
  381. result = NULL;
  382. memset(&c->conf, 0xff, sizeof(c->conf));
  383. if (conf)
  384. memcpy(&c->conf, conf, sizeof(c->conf));
  385. conf = NULL;
  386. r = bbConfig(c, 0, 8);
  387. if (r == 0)
  388. r = bbConfig(c, c->conf.bb_endian, c->conf.bb_size);
  389. if (r != 0)
  390. return UCL_E_INVALID_ARGUMENT;
  391. c->bb_op = out;
  392. ii = c->ip; /* point to start of literal run */
  393. lit = 0;
  394. #if !defined(swd)
  395. swd = (ucl_swd_p) ucl_alloc(1, ucl_sizeof(*swd));
  396. if (!swd)
  397. return UCL_E_OUT_OF_MEMORY;
  398. #endif
  399. swd->f = UCL_MIN(F, c->conf.max_match);
  400. swd->n = UCL_MIN(N, sc->max_offset);
  401. if (c->conf.max_offset != UCL_UINT_MAX)
  402. swd->n = UCL_MIN(N, c->conf.max_offset);
  403. if (in_len >= 256 && in_len < swd->n)
  404. swd->n = in_len;
  405. if (swd->f < 8 || swd->n < 256)
  406. return UCL_E_INVALID_ARGUMENT;
  407. r = init_match(c,swd,NULL,0,sc->flags);
  408. if (r != UCL_E_OK)
  409. {
  410. #if !defined(swd)
  411. ucl_free(swd);
  412. #endif
  413. return r;
  414. }
  415. if (sc->max_chain > 0)
  416. swd->max_chain = sc->max_chain;
  417. if (sc->nice_length > 0)
  418. swd->nice_length = sc->nice_length;
  419. if (c->conf.max_match < swd->nice_length)
  420. swd->nice_length = c->conf.max_match;
  421. if (c->cb)
  422. (*c->cb->callback)(0,0,-1,c->cb->user);
  423. c->last_m_off = 1;
  424. r = find_match(c,swd,0,0);
  425. if (r != UCL_E_OK)
  426. return r;
  427. while (c->look > 0)
  428. {
  429. ucl_uint ahead;
  430. ucl_uint max_ahead;
  431. int l1, l2;
  432. c->codesize = c->bb_op - out;
  433. m_len = c->m_len;
  434. m_off = c->m_off;
  435. assert(c->bp == c->ip - c->look);
  436. assert(c->bp >= in);
  437. if (lit == 0)
  438. ii = c->bp;
  439. assert(ii + lit == c->bp);
  440. assert(swd->b_char == *(c->bp));
  441. if (m_len < 2 || (m_len == 2 && (m_off > M2_MAX_OFFSET))
  442. || m_off > c->conf.max_offset)
  443. {
  444. /* a literal */
  445. lit++;
  446. swd->max_chain = sc->max_chain;
  447. r = find_match(c,swd,1,0);
  448. assert(r == 0);
  449. continue;
  450. }
  451. /* a match */
  452. #if defined(SWD_BEST_OFF)
  453. if (swd->use_best_off)
  454. better_match(swd,&m_len,&m_off);
  455. #endif
  456. assert_match(swd,m_len,m_off);
  457. /* shall we try a lazy match ? */
  458. ahead = 0;
  459. if (sc->try_lazy <= 0 || m_len >= sc->max_lazy || m_off == c->last_m_off)
  460. {
  461. /* no */
  462. l1 = 0;
  463. max_ahead = 0;
  464. }
  465. else
  466. {
  467. /* yes, try a lazy match */
  468. l1 = len_of_coded_match(c,m_len,m_off);
  469. assert(l1 > 0);
  470. max_ahead = UCL_MIN(sc->try_lazy, m_len - 1);
  471. }
  472. while (ahead < max_ahead && c->look > m_len)
  473. {
  474. if (m_len >= sc->good_length)
  475. swd->max_chain = sc->max_chain >> 2;
  476. else
  477. swd->max_chain = sc->max_chain;
  478. r = find_match(c,swd,1,0);
  479. ahead++;
  480. assert(r == 0);
  481. assert(c->look > 0);
  482. assert(ii + lit + ahead == c->bp);
  483. if (c->m_len < 2)
  484. continue;
  485. #if defined(SWD_BEST_OFF)
  486. if (swd->use_best_off)
  487. better_match(swd,&c->m_len,&c->m_off);
  488. #endif
  489. l2 = len_of_coded_match(c,c->m_len,c->m_off);
  490. if (l2 < 0)
  491. continue;
  492. #if 1
  493. if (l1 + (int)(ahead + c->m_len - m_len) * 5 > l2 + (int)(ahead) * 9)
  494. #else
  495. if (l1 > l2)
  496. #endif
  497. {
  498. c->lazy++;
  499. assert_match(swd,c->m_len,c->m_off);
  500. #if 0
  501. if (l3 > 0)
  502. {
  503. /* code previous run */
  504. code_run(c,ii,lit);
  505. lit = 0;
  506. /* code shortened match */
  507. code_match(c,ahead,m_off);
  508. }
  509. else
  510. #endif
  511. {
  512. lit += ahead;
  513. assert(ii + lit == c->bp);
  514. }
  515. goto lazy_match_done;
  516. }
  517. }
  518. assert(ii + lit + ahead == c->bp);
  519. /* 1 - code run */
  520. code_run(c,ii,lit);
  521. lit = 0;
  522. /* 2 - code match */
  523. code_match(c,m_len,m_off);
  524. swd->max_chain = sc->max_chain;
  525. r = find_match(c,swd,m_len,1+ahead);
  526. assert(r == 0);
  527. lazy_match_done: ;
  528. }
  529. /* store final run */
  530. code_run(c,ii,lit);
  531. /* EOF */
  532. bbPutBit(c, 0);
  533. #if defined(NRV2B)
  534. code_prefix_ss11(c, UCL_UINT32_C(0x1000000));
  535. bbPutByte(c, 0xff);
  536. #elif defined(NRV2D) || defined(NRV2E)
  537. code_prefix_ss12(c, UCL_UINT32_C(0x1000000));
  538. bbPutByte(c, 0xff);
  539. #else
  540. # error
  541. #endif
  542. bbFlushBits(c, 0);
  543. assert(c->textsize == in_len);
  544. c->codesize = c->bb_op - out;
  545. *out_len = c->bb_op - out;
  546. if (c->cb)
  547. (*c->cb->callback)(c->textsize,c->codesize,4,c->cb->user);
  548. #if 0
  549. printf("%7ld %7ld -> %7ld %7ld %7ld %ld (max: %d %d %d)\n",
  550. (long) c->textsize, (long) in_len, (long) c->codesize,
  551. c->match_bytes, c->lit_bytes, c->lazy,
  552. c->result[1], c->result[3], c->result[5]);
  553. #endif
  554. assert(c->lit_bytes + c->match_bytes == in_len);
  555. swd_exit(swd);
  556. #if !defined(swd)
  557. ucl_free(swd);
  558. #endif
  559. return UCL_E_OK;
  560. #undef swd
  561. }
  562. /*
  563. vi:ts=4:et
  564. */