Home | History | Annotate | Download | only in src
      1 /* lzo_swd.ch -- sliding window dictionary
      2 
      3    This file is part of the LZO real-time data compression library.
      4 
      5    Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
      6    All Rights Reserved.
      7 
      8    The LZO 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.
     12 
     13    The LZO 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.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with the LZO library; see the file COPYING.
     20    If not, write to the Free Software Foundation, Inc.,
     21    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
     22 
     23    Markus F.X.J. Oberhumer
     24    <markus (at) oberhumer.com>
     25    http://www.oberhumer.com/opensource/lzo/
     26  */
     27 
     28 
     29 #if (LZO_UINT_MAX < LZO_0xffffffffL)
     30 #  error "LZO_UINT_MAX"
     31 #endif
     32 #if defined(LZO_DEBUG)
     33 #  include <stdio.h>
     34 #endif
     35 #if defined(__LZO_CHECKER)
     36 #  include <stdlib.h>
     37 #endif
     38 
     39 
     40 /***********************************************************************
     41 //
     42 ************************************************************************/
     43 
     44 /* unsigned type for dictionary access - don't waste memory here */
     45 #if (0UL + SWD_N + SWD_F + SWD_F < 65535UL)
     46    typedef lzo_uint16_t     swd_uint;
     47 #  define SWD_UINT_MAX      0xffffu
     48 #else
     49    typedef lzo_uint32_t     swd_uint;
     50 #  define SWD_UINT_MAX      0xffffffffu
     51 #endif
     52 #define swd_uintp           swd_uint *
     53 #define SWD_UINT(x)         ((swd_uint)(x))
     54 
     55 
     56 #ifndef SWD_HSIZE
     57 #  define SWD_HSIZE         16384
     58 #endif
     59 #ifndef SWD_MAX_CHAIN
     60 #  define SWD_MAX_CHAIN     2048
     61 #endif
     62 
     63 #if !defined(HEAD3)
     64 #if 1
     65 #  define HEAD3(b,p) \
     66     ((DMUL(0x9f5f,(((((lzo_xint)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
     67 #else
     68 #  define HEAD3(b,p) \
     69     ((DMUL(0x9f5f,(((((lzo_xint)b[p+2]<<5)^b[p+1])<<5)^b[p]))>>5) & (SWD_HSIZE-1))
     70 #endif
     71 #endif
     72 
     73 #if !(SWD_NO_HEAD2) && (SWD_THRESHOLD == 1) && !defined(HEAD2)
     74 #  if 1 && (LZO_OPT_UNALIGNED16)
     75 #    define HEAD2(b,p)      UA_GET_NE16((b)+(p))
     76 #  else
     77 #    define HEAD2(b,p)      (b[p] ^ ((unsigned)b[(p)+1]<<8))
     78 #  endif
     79 #  define NIL2              SWD_UINT_MAX
     80 #endif
     81 #ifndef IF_HEAD2
     82 #define IF_HEAD2(s)         /*empty*/
     83 #endif
     84 
     85 
     86 typedef struct
     87 {
     88 /* public - "built-in" */
     89     lzo_uint swd_n;
     90     lzo_uint swd_f;
     91     lzo_uint swd_threshold;
     92 
     93 /* public - configuration */
     94     lzo_uint max_chain;
     95     lzo_uint nice_length;
     96     lzo_bool use_best_off;
     97     lzo_uint lazy_insert;
     98 
     99 /* public - output */
    100     lzo_uint m_len;
    101     lzo_uint m_off;
    102     lzo_uint look;
    103     int b_char;
    104 #if defined(SWD_BEST_OFF)
    105     lzo_uint best_off[ SWD_BEST_OFF ];
    106 #endif
    107 
    108 /* semi public */
    109     LZO_COMPRESS_T *c;
    110     lzo_uint m_pos;
    111 #if defined(SWD_BEST_OFF)
    112     lzo_uint best_pos[ SWD_BEST_OFF ];
    113 #endif
    114 
    115 /* private */
    116     const lzo_bytep dict;
    117     const lzo_bytep dict_end;
    118     lzo_uint dict_len;
    119 
    120 /* private */
    121     lzo_uint ip;                /* input pointer (lookahead) */
    122     lzo_uint bp;                /* buffer pointer */
    123     lzo_uint rp;                /* remove pointer */
    124     lzo_uint b_size;
    125 
    126     lzo_bytep b_wrap;
    127 
    128     lzo_uint node_count;
    129     lzo_uint first_rp;
    130 
    131 #if defined(__LZO_CHECKER)
    132     /* malloc arrays of the exact size to detect any overrun */
    133     unsigned char *b;
    134     swd_uint *head3;
    135     swd_uint *succ3;
    136     swd_uint *best3;
    137     swd_uint *llen3;
    138 # ifdef HEAD2
    139     swd_uint *head2;
    140 # endif
    141 
    142 #else
    143     unsigned char b [ SWD_N + SWD_F + SWD_F ];
    144     swd_uint head3 [ SWD_HSIZE ];
    145     swd_uint succ3 [ SWD_N + SWD_F ];
    146     swd_uint best3 [ SWD_N + SWD_F ];
    147     swd_uint llen3 [ SWD_HSIZE ];
    148 # ifdef HEAD2
    149     swd_uint head2 [ 65536L ];
    150 # endif
    151 #endif
    152 }
    153 lzo_swd_t;
    154 #define lzo_swd_p   lzo_swd_t *
    155 
    156 
    157 #define s_b(s)      s->b
    158 #define s_head3(s)  s->head3
    159 #define s_succ3(s)  s->succ3
    160 #define s_best3(s)  s->best3
    161 #define s_llen3(s)  s->llen3
    162 #ifdef HEAD2
    163 #define s_head2(s)  s->head2
    164 #endif
    165 #define SIZEOF_LZO_SWD_T    (sizeof(lzo_swd_t))
    166 
    167 
    168 /* Access macro for head3.
    169  * head3[key] may be uninitialized if the list is emtpy,
    170  * but then its value will never be used.
    171  */
    172 #if 1 || defined(__LZO_CHECKER)
    173 #  define s_get_head3(s,key) \
    174         ((swd_uint)((s_llen3(s)[key] == 0) ? SWD_UINT_MAX : s_head3(s)[key]))
    175 #else
    176 #  define s_get_head3(s,key)    (s_head3(s)[key])
    177 #endif
    178 
    179 
    180 /***********************************************************************
    181 //
    182 ************************************************************************/
    183 
    184 static
    185 void swd_initdict(lzo_swd_p s, const lzo_bytep dict, lzo_uint dict_len)
    186 {
    187     s->dict = s->dict_end = NULL;
    188     s->dict_len = 0;
    189 
    190     if (!dict || dict_len == 0)
    191         return;
    192     if (dict_len > s->swd_n)
    193     {
    194         dict += dict_len - s->swd_n;
    195         dict_len = s->swd_n;
    196     }
    197 
    198     s->dict = dict;
    199     s->dict_len = dict_len;
    200     s->dict_end = dict + dict_len;
    201     lzo_memcpy(s_b(s),dict,dict_len);
    202     s->ip = dict_len;
    203 }
    204 
    205 
    206 static
    207 void swd_insertdict(lzo_swd_p s, lzo_uint node, lzo_uint len)
    208 {
    209     lzo_uint key;
    210 
    211     s->node_count = s->swd_n - len;
    212     s->first_rp = node;
    213 
    214     if (len) do
    215     {
    216         key = HEAD3(s_b(s),node);
    217         s_succ3(s)[node] = s_get_head3(s,key);
    218         s_head3(s)[key] = SWD_UINT(node);
    219         s_best3(s)[node] = SWD_UINT(s->swd_f + 1);
    220         s_llen3(s)[key]++;
    221         assert(s_llen3(s)[key] <= s->swd_n);
    222 
    223 #ifdef HEAD2
    224         IF_HEAD2(s) {
    225             key = HEAD2(s_b(s),node);
    226             s_head2(s)[key] = SWD_UINT(node);
    227         }
    228 #endif
    229 
    230         node++;
    231     }
    232     while (--len != 0);
    233 }
    234 
    235 
    236 /***********************************************************************
    237 //
    238 ************************************************************************/
    239 
    240 static
    241 int swd_init(lzo_swd_p s, const lzo_bytep dict, lzo_uint dict_len)
    242 {
    243 #if defined(__LZO_CHECKER)
    244     s->b = (lzo_bytep) malloc(SWD_N + SWD_F + SWD_F);
    245     s->head3 = (swd_uintp) malloc(sizeof(swd_uint) * SWD_HSIZE);
    246     s->succ3 = (swd_uintp) malloc(sizeof(swd_uint) * (SWD_N + SWD_F));
    247     s->best3 = (swd_uintp) malloc(sizeof(swd_uint) * (SWD_N + SWD_F));
    248     s->llen3 = (swd_uintp) malloc(sizeof(swd_uint) * SWD_HSIZE);
    249 #ifdef HEAD2
    250     IF_HEAD2(s) {
    251         s->head2 = (swd_uintp) malloc(sizeof(swd_uint) * 65536L);
    252     }
    253 #endif
    254 #endif
    255 
    256     s->m_len = 0;
    257     s->m_off = 0;
    258 #if defined(SWD_BEST_OFF)
    259     {
    260         unsigned i;
    261         for (i = 0; i < SWD_BEST_OFF; i++)
    262             s->best_off[i] = s->best_pos[i] = 0;
    263     }
    264 #endif
    265 
    266     s->swd_n = SWD_N;
    267     s->swd_f = SWD_F;
    268     s->swd_threshold = SWD_THRESHOLD;
    269 
    270     /* defaults */
    271     s->max_chain = SWD_MAX_CHAIN;
    272     s->nice_length = s->swd_f;
    273     s->use_best_off = 0;
    274     s->lazy_insert = 0;
    275 
    276     s->b_size = s->swd_n + s->swd_f;
    277 #if 0
    278     if (2 * s->swd_f >= s->swd_n || s->b_size + s->swd_f >= SWD_UINT_MAX)
    279         return LZO_E_ERROR;
    280 #else
    281     LZO_COMPILE_TIME_ASSERT(!(0ul + 2 * SWD_F >= SWD_N))
    282     LZO_COMPILE_TIME_ASSERT(!(0ul + SWD_N + SWD_F + SWD_F >= SWD_UINT_MAX))
    283 #endif
    284     s->b_wrap = s_b(s) + s->b_size;
    285     s->node_count = s->swd_n;
    286 
    287     lzo_memset(s_llen3(s), 0, (lzo_uint)sizeof(s_llen3(s)[0]) * (lzo_uint)SWD_HSIZE);
    288 #ifdef HEAD2
    289     IF_HEAD2(s) {
    290 #if 1
    291         lzo_memset(s_head2(s), 0xff, (lzo_uint)sizeof(s_head2(s)[0]) * 65536L);
    292         assert(s_head2(s)[0] == NIL2);
    293 #else
    294         lzo_xint i;
    295         for (i = 0; i < 65536L; i++)
    296             s_head2(s)[i] = NIL2;
    297 #endif
    298     }
    299 #endif
    300 
    301     s->ip = 0;
    302     swd_initdict(s,dict,dict_len);
    303     s->bp = s->ip;
    304     s->first_rp = s->ip;
    305 
    306     assert(s->ip + s->swd_f <= s->b_size);
    307 #if 1
    308     s->look = (lzo_uint) (s->c->in_end - s->c->ip);
    309     if (s->look > 0)
    310     {
    311         if (s->look > s->swd_f)
    312             s->look = s->swd_f;
    313         lzo_memcpy(&s_b(s)[s->ip],s->c->ip,s->look);
    314         s->c->ip += s->look;
    315         s->ip += s->look;
    316     }
    317 #else
    318     s->look = 0;
    319     while (s->look < s->swd_f)
    320     {
    321         int c;
    322         if ((c = getbyte(*(s->c))) < 0)
    323             break;
    324         s_b(s)[s->ip] = LZO_BYTE(c);
    325         s->ip++;
    326         s->look++;
    327     }
    328 #endif
    329     if (s->ip == s->b_size)
    330         s->ip = 0;
    331 
    332     if (s->look >= 2 && s->dict_len > 0)
    333         swd_insertdict(s,0,s->dict_len);
    334 
    335     s->rp = s->first_rp;
    336     if (s->rp >= s->node_count)
    337         s->rp -= s->node_count;
    338     else
    339         s->rp += s->b_size - s->node_count;
    340 
    341 #if 1 || defined(__LZO_CHECKER)
    342     /* initialize memory for the first few HEAD3 (if s->ip is not far
    343      * enough ahead to do this job for us). The value doesn't matter. */
    344     if (s->look < 3) {
    345         lzo_bytep p = &s_b(s)[s->bp+s->look];
    346         p[0] = p[1] = p[2] = 0;
    347     }
    348 #endif
    349 
    350     return LZO_E_OK;
    351 }
    352 
    353 
    354 static
    355 void swd_exit(lzo_swd_p s)
    356 {
    357 #if defined(__LZO_CHECKER)
    358     /* free in reverse order of allocations */
    359 #ifdef HEAD2
    360     free(s->head2); s->head2 = NULL;
    361 #endif
    362     free(s->llen3); s->llen3 = NULL;
    363     free(s->best3); s->best3 = NULL;
    364     free(s->succ3); s->succ3 = NULL;
    365     free(s->head3); s->head3 = NULL;
    366     free(s->b); s->b = NULL;
    367 #else
    368     LZO_UNUSED(s);
    369 #endif
    370 }
    371 
    372 
    373 #define swd_pos2off(s,pos) \
    374     (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
    375 
    376 
    377 /***********************************************************************
    378 //
    379 ************************************************************************/
    380 
    381 static __lzo_inline
    382 void swd_getbyte(lzo_swd_p s)
    383 {
    384     int c;
    385 
    386     if ((c = getbyte(*(s->c))) < 0)
    387     {
    388         if (s->look > 0)
    389             --s->look;
    390 #if 1 || defined(__LZO_CHECKER)
    391         /* initialize memory - value doesn't matter */
    392         s_b(s)[s->ip] = 0;
    393         if (s->ip < s->swd_f)
    394             s->b_wrap[s->ip] = 0;
    395 #endif
    396     }
    397     else
    398     {
    399         s_b(s)[s->ip] = LZO_BYTE(c);
    400         if (s->ip < s->swd_f)
    401             s->b_wrap[s->ip] = LZO_BYTE(c);
    402     }
    403     if (++s->ip == s->b_size)
    404         s->ip = 0;
    405     if (++s->bp == s->b_size)
    406         s->bp = 0;
    407     if (++s->rp == s->b_size)
    408         s->rp = 0;
    409 }
    410 
    411 
    412 /***********************************************************************
    413 // remove node from lists
    414 ************************************************************************/
    415 
    416 static __lzo_inline
    417 void swd_remove_node(lzo_swd_p s, lzo_uint node)
    418 {
    419     if (s->node_count == 0)
    420     {
    421         lzo_uint key;
    422 
    423 #ifdef LZO_DEBUG
    424         if (s->first_rp != LZO_UINT_MAX)
    425         {
    426             if (node != s->first_rp)
    427                 printf("Remove %5ld: %5ld %5ld %5ld %5ld  %6ld %6ld\n",
    428                         (long)node, (long)s->rp, (long)s->ip, (long)s->bp,
    429                         (long)s->first_rp, (long)(s->ip - node),
    430                         (long)(s->ip - s->bp));
    431             assert(node == s->first_rp);
    432             s->first_rp = LZO_UINT_MAX;
    433         }
    434 #endif
    435 
    436         key = HEAD3(s_b(s),node);
    437         assert(s_llen3(s)[key] > 0);
    438         --s_llen3(s)[key];
    439 
    440 #ifdef HEAD2
    441         IF_HEAD2(s) {
    442             key = HEAD2(s_b(s),node);
    443             assert(s_head2(s)[key] != NIL2);
    444             if ((lzo_uint) s_head2(s)[key] == node)
    445                 s_head2(s)[key] = NIL2;
    446         }
    447 #endif
    448     }
    449     else
    450         --s->node_count;
    451 }
    452 
    453 
    454 /***********************************************************************
    455 //
    456 ************************************************************************/
    457 
    458 static
    459 void swd_accept(lzo_swd_p s, lzo_uint n)
    460 {
    461     assert(n <= s->look);
    462 
    463     if (n) do
    464     {
    465         lzo_uint key;
    466 
    467         swd_remove_node(s,s->rp);
    468 
    469         /* add bp into HEAD3 */
    470         key = HEAD3(s_b(s),s->bp);
    471         s_succ3(s)[s->bp] = s_get_head3(s,key);
    472         s_head3(s)[key] = SWD_UINT(s->bp);
    473         s_best3(s)[s->bp] = SWD_UINT(s->swd_f + 1);
    474         s_llen3(s)[key]++;
    475         assert(s_llen3(s)[key] <= s->swd_n);
    476 
    477 #ifdef HEAD2
    478         /* add bp into HEAD2 */
    479         IF_HEAD2(s) {
    480             key = HEAD2(s_b(s),s->bp);
    481             s_head2(s)[key] = SWD_UINT(s->bp);
    482         }
    483 #endif
    484 
    485         swd_getbyte(s);
    486     } while (--n != 0);
    487 }
    488 
    489 
    490 /***********************************************************************
    491 //
    492 ************************************************************************/
    493 
    494 static
    495 void swd_search(lzo_swd_p s, lzo_uint node, lzo_uint cnt)
    496 {
    497     const lzo_bytep p1;
    498     const lzo_bytep p2;
    499     const lzo_bytep px;
    500     lzo_uint m_len = s->m_len;
    501     const lzo_bytep b  = s_b(s);
    502     const lzo_bytep bp = s_b(s) + s->bp;
    503     const lzo_bytep bx = s_b(s) + s->bp + s->look;
    504     unsigned char scan_end1;
    505 
    506     assert(s->m_len > 0);
    507 
    508     scan_end1 = bp[m_len - 1];
    509     for ( ; cnt-- > 0; node = s_succ3(s)[node])
    510     {
    511         p1 = bp;
    512         p2 = b + node;
    513         px = bx;
    514 
    515         assert(m_len < s->look);
    516 
    517         if (
    518 #if 1
    519             p2[m_len - 1] == scan_end1 &&
    520             p2[m_len] == p1[m_len] &&
    521 #endif
    522             p2[0] == p1[0] &&
    523             p2[1] == p1[1])
    524         {
    525             lzo_uint i;
    526             assert(lzo_memcmp(bp,&b[node],3) == 0);
    527 
    528 #if 0 && (LZO_OPT_UNALIGNED32)
    529             p1 += 3; p2 += 3;
    530             while (p1 + 4 <= px && UA_GET_NE32(p1) == UA_GET_NE32(p2))
    531                 p1 += 4, p2 += 4;
    532             while (p1 < px && *p1 == *p2)
    533                 p1 += 1, p2 += 1;
    534 #else
    535             p1 += 2; p2 += 2;
    536             do {} while (++p1 < px && *p1 == *++p2);
    537 #endif
    538             i = pd(p1, bp);
    539 
    540 #ifdef LZO_DEBUG
    541             if (lzo_memcmp(bp,&b[node],i) != 0)
    542                 printf("%5ld %5ld %5ld %02x/%02x %02x/%02x\n",
    543                         (long)s->bp, (long) node, (long) i,
    544                         bp[0], bp[1], b[node], b[node+1]);
    545 #endif
    546             assert(lzo_memcmp(bp,&b[node],i) == 0);
    547 
    548 #if defined(SWD_BEST_OFF)
    549             if (i < SWD_BEST_OFF)
    550             {
    551                 if (s->best_pos[i] == 0)
    552                     s->best_pos[i] = node + 1;
    553             }
    554 #endif
    555             if (i > m_len)
    556             {
    557                 s->m_len = m_len = i;
    558                 s->m_pos = node;
    559                 if (m_len == s->look)
    560                     return;
    561                 if (m_len >= s->nice_length)
    562                     return;
    563                 if (m_len > (lzo_uint) s_best3(s)[node])
    564                     return;
    565                 scan_end1 = bp[m_len - 1];
    566             }
    567         }
    568     }
    569 }
    570 
    571 
    572 /***********************************************************************
    573 //
    574 ************************************************************************/
    575 
    576 #ifdef HEAD2
    577 
    578 static
    579 lzo_bool swd_search2(lzo_swd_p s)
    580 {
    581     lzo_uint key;
    582 
    583     assert(s->look >= 2);
    584     assert(s->m_len > 0);
    585 
    586     key = s_head2(s)[ HEAD2(s_b(s),s->bp) ];
    587     if (key == NIL2)
    588         return 0;
    589 #ifdef LZO_DEBUG
    590     if (lzo_memcmp(&s_b(s)[s->bp],&s_b(s)[key],2) != 0)
    591         printf("%5ld %5ld %02x/%02x %02x/%02x\n", (long)s->bp, (long)key,
    592                 s_b(s)[s->bp], s_b(s)[s->bp+1], s_b(s)[key], s_b(s)[key+1]);
    593 #endif
    594     assert(lzo_memcmp(&s_b(s)[s->bp],&s_b(s)[key],2) == 0);
    595 #if defined(SWD_BEST_OFF)
    596     if (s->best_pos[2] == 0)
    597         s->best_pos[2] = key + 1;
    598 #endif
    599 
    600     if (s->m_len < 2)
    601     {
    602         s->m_len = 2;
    603         s->m_pos = key;
    604     }
    605     return 1;
    606 }
    607 
    608 #endif
    609 
    610 
    611 /***********************************************************************
    612 //
    613 ************************************************************************/
    614 
    615 static
    616 void swd_findbest(lzo_swd_p s)
    617 {
    618     lzo_uint key;
    619     lzo_uint cnt, node;
    620     lzo_uint len;
    621 
    622     assert(s->m_len > 0);
    623 
    624     /* get current head, add bp into HEAD3 */
    625     key = HEAD3(s_b(s),s->bp);
    626     node = s_succ3(s)[s->bp] = s_get_head3(s,key);
    627     cnt = s_llen3(s)[key]++;
    628     assert(s_llen3(s)[key] <= s->swd_n + s->swd_f);
    629     if (cnt > s->max_chain && s->max_chain > 0)
    630         cnt = s->max_chain;
    631     s_head3(s)[key] = SWD_UINT(s->bp);
    632 
    633     s->b_char = s_b(s)[s->bp];
    634     len = s->m_len;
    635     if (s->m_len >= s->look)
    636     {
    637         if (s->look == 0)
    638             s->b_char = -1;
    639         s->m_off = 0;
    640         s_best3(s)[s->bp] = SWD_UINT(s->swd_f + 1);
    641     }
    642     else
    643     {
    644 #if defined(HEAD2)
    645         if (swd_search2(s) && s->look >= 3)
    646             swd_search(s,node,cnt);
    647 #else
    648         if (s->look >= 3)
    649             swd_search(s,node,cnt);
    650 #endif
    651         if (s->m_len > len)
    652             s->m_off = swd_pos2off(s,s->m_pos);
    653         s_best3(s)[s->bp] = SWD_UINT(s->m_len);
    654 
    655 #if defined(SWD_BEST_OFF)
    656         if (s->use_best_off)
    657         {
    658             unsigned i;
    659             for (i = 2; i < SWD_BEST_OFF; i++)
    660                 if (s->best_pos[i] > 0)
    661                     s->best_off[i] = swd_pos2off(s,s->best_pos[i]-1);
    662                 else
    663                     s->best_off[i] = 0;
    664         }
    665 #endif
    666     }
    667 
    668     swd_remove_node(s,s->rp);
    669 
    670 #ifdef HEAD2
    671     /* add bp into HEAD2 */
    672     IF_HEAD2(s) {
    673         key = HEAD2(s_b(s),s->bp);
    674         s_head2(s)[key] = SWD_UINT(s->bp);
    675     }
    676 #endif
    677 }
    678 
    679 
    680 #undef HEAD3
    681 #undef HEAD2
    682 #undef IF_HEAD2
    683 #undef s_get_head3
    684 
    685 
    686 /*
    687 vi:ts=4:et
    688 */
    689 
    690