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