OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [util/] [zip/] [DeflaterEngine.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* DeflaterEngine.java --
2
   Copyright (C) 2001, 2004  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package java.util.zip;
39
 
40
class DeflaterEngine implements DeflaterConstants
41
{
42
  private static final int TOO_FAR = 4096;
43
 
44
  private int ins_h;
45
 
46
  /**
47
   * Hashtable, hashing three characters to an index for window, so
48
   * that window[index]..window[index+2] have this hash code.
49
   * Note that the array should really be unsigned short, so you need
50
   * to and the values with 0xffff.
51
   */
52
  private short[] head;
53
 
54
  /**
55
   * prev[index & WMASK] points to the previous index that has the
56
   * same hash code as the string starting at index.  This way
57
   * entries with the same hash code are in a linked list.
58
   * Note that the array should really be unsigned short, so you need
59
   * to and the values with 0xffff.
60
   */
61
  private short[] prev;
62
 
63
  private int matchStart, matchLen;
64
  private boolean prevAvailable;
65
  private int blockStart;
66
 
67
  /**
68
   * strstart points to the current character in window.
69
   */
70
  private int strstart;
71
 
72
  /**
73
   * lookahead is the number of characters starting at strstart in
74
   * window that are valid.
75
   * So window[strstart] until window[strstart+lookahead-1] are valid
76
   * characters.
77
   */
78
  private int lookahead;
79
 
80
  /**
81
   * This array contains the part of the uncompressed stream that
82
   * is of relevance.  The current character is indexed by strstart.
83
   */
84
  private byte[] window;
85
 
86
  private int strategy, max_chain, max_lazy, niceLength, goodLength;
87
 
88
  /** The current compression function. */
89
  private int comprFunc;
90
 
91
  /** The input data for compression. */
92
  private byte[] inputBuf;
93
 
94
  /** The total bytes of input read. */
95
  private int totalIn;
96
 
97
  /** The offset into inputBuf, where input data starts. */
98
  private int inputOff;
99
 
100
  /** The end offset of the input data. */
101
  private int inputEnd;
102
 
103
  private DeflaterPending pending;
104
  private DeflaterHuffman huffman;
105
 
106
  /** The adler checksum */
107
  private Adler32 adler;
108
 
109
  /* DEFLATE ALGORITHM:
110
   *
111
   * The uncompressed stream is inserted into the window array.  When
112
   * the window array is full the first half is thrown away and the
113
   * second half is copied to the beginning.
114
   *
115
   * The head array is a hash table.  Three characters build a hash value
116
   * and they the value points to the corresponding index in window of
117
   * the last string with this hash.  The prev array implements a
118
   * linked list of matches with the same hash: prev[index & WMASK] points
119
   * to the previous index with the same hash.
120
   *
121
   *
122
   */
123
 
124
 
125
  DeflaterEngine(DeflaterPending pending) {
126
    this.pending = pending;
127
    huffman = new DeflaterHuffman(pending);
128
    adler = new Adler32();
129
 
130
    window = new byte[2*WSIZE];
131
    head   = new short[HASH_SIZE];
132
    prev   = new short[WSIZE];
133
 
134
    /* We start at index 1, to avoid a implementation deficiency, that
135
     * we cannot build a repeat pattern at index 0.
136
     */
137
    blockStart = strstart = 1;
138
  }
139
 
140
  public void reset()
141
  {
142
    huffman.reset();
143
    adler.reset();
144
    blockStart = strstart = 1;
145
    lookahead = 0;
146
    totalIn = 0;
147
    prevAvailable = false;
148
    matchLen = MIN_MATCH - 1;
149
    for (int i = 0; i < HASH_SIZE; i++)
150
      head[i] = 0;
151
    for (int i = 0; i < WSIZE; i++)
152
      prev[i] = 0;
153
  }
154
 
155
  public final void resetAdler()
156
  {
157
    adler.reset();
158
  }
159
 
160
  public final int getAdler()
161
  {
162
    int chksum = (int) adler.getValue();
163
    return chksum;
164
  }
165
 
166
  public final int getTotalIn()
167
  {
168
    return totalIn;
169
  }
170
 
171
  public final void setStrategy(int strat)
172
  {
173
    strategy = strat;
174
  }
175
 
176
  public void setLevel(int lvl)
177
  {
178
    goodLength = DeflaterConstants.GOOD_LENGTH[lvl];
179
    max_lazy    = DeflaterConstants.MAX_LAZY[lvl];
180
    niceLength = DeflaterConstants.NICE_LENGTH[lvl];
181
    max_chain   = DeflaterConstants.MAX_CHAIN[lvl];
182
 
183
    if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc)
184
      {
185
        if (DeflaterConstants.DEBUGGING)
186
          System.err.println("Change from "+comprFunc +" to "
187
                             + DeflaterConstants.COMPR_FUNC[lvl]);
188
        switch (comprFunc)
189
          {
190
          case DEFLATE_STORED:
191
            if (strstart > blockStart)
192
              {
193
                huffman.flushStoredBlock(window, blockStart,
194
                                         strstart - blockStart, false);
195
                blockStart = strstart;
196
              }
197
            updateHash();
198
            break;
199
          case DEFLATE_FAST:
200
            if (strstart > blockStart)
201
              {
202
                huffman.flushBlock(window, blockStart, strstart - blockStart,
203
                                   false);
204
                blockStart = strstart;
205
              }
206
            break;
207
          case DEFLATE_SLOW:
208
            if (prevAvailable)
209
              huffman.tallyLit(window[strstart-1] & 0xff);
210
            if (strstart > blockStart)
211
              {
212
                huffman.flushBlock(window, blockStart, strstart - blockStart,
213
                                   false);
214
                blockStart = strstart;
215
              }
216
            prevAvailable = false;
217
            matchLen = MIN_MATCH - 1;
218
            break;
219
          }
220
        comprFunc = COMPR_FUNC[lvl];
221
      }
222
  }
223
 
224
  private void updateHash() {
225
    if (DEBUGGING)
226
      System.err.println("updateHash: "+strstart);
227
    ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
228
  }
229
 
230
  /**
231
   * Inserts the current string in the head hash and returns the previous
232
   * value for this hash.
233
   */
234
  private int insertString() {
235
    short match;
236
    int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)])
237
      & HASH_MASK;
238
 
239
    if (DEBUGGING)
240
      {
241
        if (hash != (((window[strstart] << (2*HASH_SHIFT))
242
                      ^ (window[strstart + 1] << HASH_SHIFT)
243
                      ^ (window[strstart + 2])) & HASH_MASK))
244
          throw new InternalError("hash inconsistent: "+hash+"/"
245
                                  +window[strstart]+","
246
                                  +window[strstart+1]+","
247
                                  +window[strstart+2]+","+HASH_SHIFT);
248
      }
249
 
250
    prev[strstart & WMASK] = match = head[hash];
251
    head[hash] = (short) strstart;
252
    ins_h = hash;
253
    return match & 0xffff;
254
  }
255
 
256
  private void slideWindow()
257
  {
258
    System.arraycopy(window, WSIZE, window, 0, WSIZE);
259
    matchStart -= WSIZE;
260
    strstart -= WSIZE;
261
    blockStart -= WSIZE;
262
 
263
    /* Slide the hash table (could be avoided with 32 bit values
264
     * at the expense of memory usage).
265
     */
266
    for (int i = 0; i < HASH_SIZE; i++)
267
      {
268
        int m = head[i] & 0xffff;
269
        head[i] = m >= WSIZE ? (short) (m - WSIZE) : 0;
270
      }
271
 
272
    /* Slide the prev table.
273
     */
274
    for (int i = 0; i < WSIZE; i++)
275
      {
276
        int m = prev[i] & 0xffff;
277
        prev[i] = m >= WSIZE ? (short) (m - WSIZE) : 0;
278
      }
279
  }
280
 
281
  /**
282
   * Fill the window when the lookahead becomes insufficient.
283
   * Updates strstart and lookahead.
284
   *
285
   * OUT assertions: strstart + lookahead <= 2*WSIZE
286
   *    lookahead >= MIN_LOOKAHEAD or inputOff == inputEnd
287
   */
288
  private void fillWindow()
289
  {
290
    /* If the window is almost full and there is insufficient lookahead,
291
     * move the upper half to the lower one to make room in the upper half.
292
     */
293
    if (strstart >= WSIZE + MAX_DIST)
294
      slideWindow();
295
 
296
    /* If there is not enough lookahead, but still some input left,
297
     * read in the input
298
     */
299
    while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd)
300
      {
301
        int more = 2*WSIZE - lookahead - strstart;
302
 
303
        if (more > inputEnd - inputOff)
304
          more = inputEnd - inputOff;
305
 
306
        System.arraycopy(inputBuf, inputOff,
307
                         window, strstart + lookahead, more);
308
        adler.update(inputBuf, inputOff, more);
309
        inputOff += more;
310
        totalIn  += more;
311
        lookahead += more;
312
      }
313
 
314
    if (lookahead >= MIN_MATCH)
315
      updateHash();
316
  }
317
 
318
  /**
319
   * Find the best (longest) string in the window matching the
320
   * string starting at strstart.
321
   *
322
   * Preconditions:
323
   *    strstart + MAX_MATCH <= window.length.
324
   *
325
   *
326
   * @param curMatch
327
   */
328
  private boolean findLongestMatch(int curMatch) {
329
    int chainLength = this.max_chain;
330
    int niceLength = this.niceLength;
331
    short[] prev = this.prev;
332
    int scan  = this.strstart;
333
    int match;
334
    int best_end = this.strstart + matchLen;
335
    int best_len = Math.max(matchLen, MIN_MATCH - 1);
336
 
337
    int limit = Math.max(strstart - MAX_DIST, 0);
338
 
339
    int strend = scan + MAX_MATCH - 1;
340
    byte scan_end1 = window[best_end - 1];
341
    byte scan_end  = window[best_end];
342
 
343
    /* Do not waste too much time if we already have a good match: */
344
    if (best_len >= this.goodLength)
345
      chainLength >>= 2;
346
 
347
    /* Do not look for matches beyond the end of the input. This is necessary
348
     * to make deflate deterministic.
349
     */
350
    if (niceLength > lookahead)
351
      niceLength = lookahead;
352
 
353
    if (DeflaterConstants.DEBUGGING
354
        && strstart > 2*WSIZE - MIN_LOOKAHEAD)
355
      throw new InternalError("need lookahead");
356
 
357
    do {
358
      if (DeflaterConstants.DEBUGGING && curMatch >= strstart)
359
        throw new InternalError("future match");
360
      if (window[curMatch + best_len] != scan_end
361
          || window[curMatch + best_len - 1] != scan_end1
362
          || window[curMatch] != window[scan]
363
          || window[curMatch+1] != window[scan + 1])
364
        continue;
365
 
366
      match = curMatch + 2;
367
      scan += 2;
368
 
369
      /* We check for insufficient lookahead only every 8th comparison;
370
       * the 256th check will be made at strstart+258.
371
       */
372
      while (window[++scan] == window[++match]
373
             && window[++scan] == window[++match]
374
             && window[++scan] == window[++match]
375
             && window[++scan] == window[++match]
376
             && window[++scan] == window[++match]
377
             && window[++scan] == window[++match]
378
             && window[++scan] == window[++match]
379
             && window[++scan] == window[++match]
380
             && scan < strend);
381
 
382
      if (scan > best_end) {
383
//      if (DeflaterConstants.DEBUGGING && ins_h == 0)
384
//        System.err.println("Found match: "+curMatch+"-"+(scan-strstart));
385
        matchStart = curMatch;
386
        best_end = scan;
387
        best_len = scan - strstart;
388
        if (best_len >= niceLength)
389
          break;
390
 
391
        scan_end1  = window[best_end-1];
392
        scan_end   = window[best_end];
393
      }
394
      scan = strstart;
395
    } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit
396
             && --chainLength != 0);
397
 
398
    matchLen = Math.min(best_len, lookahead);
399
    return matchLen >= MIN_MATCH;
400
  }
401
 
402
  void setDictionary(byte[] buffer, int offset, int length) {
403
    if (DeflaterConstants.DEBUGGING && strstart != 1)
404
      throw new IllegalStateException("strstart not 1");
405
    adler.update(buffer, offset, length);
406
    if (length < MIN_MATCH)
407
      return;
408
    if (length > MAX_DIST) {
409
      offset += length - MAX_DIST;
410
      length = MAX_DIST;
411
    }
412
 
413
    System.arraycopy(buffer, offset, window, strstart, length);
414
 
415
    updateHash();
416
    length--;
417
    while (--length > 0)
418
      {
419
        insertString();
420
        strstart++;
421
      }
422
    strstart += 2;
423
    blockStart = strstart;
424
  }
425
 
426
  private boolean deflateStored(boolean flush, boolean finish)
427
  {
428
    if (!flush && lookahead == 0)
429
      return false;
430
 
431
    strstart += lookahead;
432
    lookahead = 0;
433
 
434
    int storedLen = strstart - blockStart;
435
 
436
    if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE)
437
        /* Block is full */
438
        || (blockStart < WSIZE && storedLen >= MAX_DIST)
439
        /* Block may move out of window */
440
        || flush)
441
      {
442
        boolean lastBlock = finish;
443
        if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE)
444
          {
445
            storedLen = DeflaterConstants.MAX_BLOCK_SIZE;
446
            lastBlock = false;
447
          }
448
 
449
        if (DeflaterConstants.DEBUGGING)
450
          System.err.println("storedBlock["+storedLen+","+lastBlock+"]");
451
 
452
        huffman.flushStoredBlock(window, blockStart, storedLen, lastBlock);
453
        blockStart += storedLen;
454
        return !lastBlock;
455
      }
456
    return true;
457
  }
458
 
459
  private boolean deflateFast(boolean flush, boolean finish)
460
  {
461
    if (lookahead < MIN_LOOKAHEAD && !flush)
462
      return false;
463
 
464
    while (lookahead >= MIN_LOOKAHEAD || flush)
465
      {
466
        if (lookahead == 0)
467
          {
468
            /* We are flushing everything */
469
            huffman.flushBlock(window, blockStart, strstart - blockStart,
470
                               finish);
471
            blockStart = strstart;
472
            return false;
473
          }
474
 
475
        if (strstart > 2 * WSIZE - MIN_LOOKAHEAD)
476
          {
477
            /* slide window, as findLongestMatch need this.
478
             * This should only happen when flushing and the window
479
             * is almost full.
480
             */
481
            slideWindow();
482
          }
483
 
484
        int hashHead;
485
        if (lookahead >= MIN_MATCH
486
            && (hashHead = insertString()) != 0
487
            && strategy != Deflater.HUFFMAN_ONLY
488
            && strstart - hashHead <= MAX_DIST
489
            && findLongestMatch(hashHead))
490
          {
491
            /* longestMatch sets matchStart and matchLen */
492
            if (DeflaterConstants.DEBUGGING)
493
              {
494
                for (int i = 0 ; i < matchLen; i++)
495
                  {
496
                    if (window[strstart+i] != window[matchStart + i])
497
                      throw new InternalError();
498
                  }
499
              }
500
            huffman.tallyDist(strstart - matchStart, matchLen);
501
 
502
            lookahead -= matchLen;
503
            if (matchLen <= max_lazy && lookahead >= MIN_MATCH)
504
              {
505
                while (--matchLen > 0)
506
                  {
507
                    strstart++;
508
                    insertString();
509
                  }
510
                strstart++;
511
              }
512
            else
513
              {
514
                strstart += matchLen;
515
                if (lookahead >= MIN_MATCH - 1)
516
                  updateHash();
517
              }
518
            matchLen = MIN_MATCH - 1;
519
            continue;
520
          }
521
        else
522
          {
523
            /* No match found */
524
            huffman.tallyLit(window[strstart] & 0xff);
525
            strstart++;
526
            lookahead--;
527
          }
528
 
529
        if (huffman.isFull())
530
          {
531
            boolean lastBlock = finish && lookahead == 0;
532
            huffman.flushBlock(window, blockStart, strstart - blockStart,
533
                               lastBlock);
534
            blockStart = strstart;
535
            return !lastBlock;
536
          }
537
      }
538
    return true;
539
  }
540
 
541
  private boolean deflateSlow(boolean flush, boolean finish)
542
  {
543
    if (lookahead < MIN_LOOKAHEAD && !flush)
544
      return false;
545
 
546
    while (lookahead >= MIN_LOOKAHEAD || flush)
547
      {
548
        if (lookahead == 0)
549
          {
550
            if (prevAvailable)
551
              huffman.tallyLit(window[strstart-1] & 0xff);
552
            prevAvailable = false;
553
 
554
            /* We are flushing everything */
555
            if (DeflaterConstants.DEBUGGING && !flush)
556
              throw new InternalError("Not flushing, but no lookahead");
557
            huffman.flushBlock(window, blockStart, strstart - blockStart,
558
                               finish);
559
            blockStart = strstart;
560
            return false;
561
          }
562
 
563
        if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD)
564
          {
565
            /* slide window, as findLongestMatch need this.
566
             * This should only happen when flushing and the window
567
             * is almost full.
568
             */
569
            slideWindow();
570
          }
571
 
572
        int prevMatch = matchStart;
573
        int prevLen = matchLen;
574
        if (lookahead >= MIN_MATCH)
575
          {
576
            int hashHead = insertString();
577
            if (strategy != Deflater.HUFFMAN_ONLY
578
                && hashHead != 0 && strstart - hashHead <= MAX_DIST
579
                && findLongestMatch(hashHead))
580
              {
581
                /* longestMatch sets matchStart and matchLen */
582
 
583
                /* Discard match if too small and too far away */
584
                if (matchLen <= 5
585
                    && (strategy == Deflater.FILTERED
586
                        || (matchLen == MIN_MATCH
587
                            && strstart - matchStart > TOO_FAR))) {
588
                  matchLen = MIN_MATCH - 1;
589
                }
590
              }
591
          }
592
 
593
        /* previous match was better */
594
        if (prevLen >= MIN_MATCH && matchLen <= prevLen)
595
          {
596
            if (DeflaterConstants.DEBUGGING)
597
              {
598
                for (int i = 0 ; i < matchLen; i++)
599
                  {
600
                    if (window[strstart-1+i] != window[prevMatch + i])
601
                      throw new InternalError();
602
                  }
603
              }
604
            huffman.tallyDist(strstart - 1 - prevMatch, prevLen);
605
            prevLen -= 2;
606
            do
607
              {
608
                strstart++;
609
                lookahead--;
610
                if (lookahead >= MIN_MATCH)
611
                  insertString();
612
              }
613
            while (--prevLen > 0);
614
            strstart ++;
615
            lookahead--;
616
            prevAvailable = false;
617
            matchLen = MIN_MATCH - 1;
618
          }
619
        else
620
          {
621
            if (prevAvailable)
622
              huffman.tallyLit(window[strstart-1] & 0xff);
623
            prevAvailable = true;
624
            strstart++;
625
            lookahead--;
626
          }
627
 
628
        if (huffman.isFull())
629
          {
630
            int len = strstart - blockStart;
631
            if (prevAvailable)
632
              len--;
633
            boolean lastBlock = (finish && lookahead == 0 && !prevAvailable);
634
            huffman.flushBlock(window, blockStart, len, lastBlock);
635
            blockStart += len;
636
            return !lastBlock;
637
          }
638
      }
639
    return true;
640
  }
641
 
642
  public boolean deflate(boolean flush, boolean finish)
643
  {
644
    boolean progress;
645
    do
646
      {
647
        fillWindow();
648
        boolean canFlush = flush && inputOff == inputEnd;
649
        if (DeflaterConstants.DEBUGGING)
650
          System.err.println("window: ["+blockStart+","+strstart+","
651
                             +lookahead+"], "+comprFunc+","+canFlush);
652
        switch (comprFunc)
653
          {
654
          case DEFLATE_STORED:
655
            progress = deflateStored(canFlush, finish);
656
            break;
657
          case DEFLATE_FAST:
658
            progress = deflateFast(canFlush, finish);
659
            break;
660
          case DEFLATE_SLOW:
661
            progress = deflateSlow(canFlush, finish);
662
            break;
663
          default:
664
            throw new InternalError();
665
          }
666
      }
667
    while (pending.isFlushed()  /* repeat while we have no pending output */
668
           && progress);        /* and progress was made */
669
 
670
    return progress;
671
  }
672
 
673
  public void setInput(byte[] buf, int off, int len)
674
  {
675
    if (inputOff < inputEnd)
676
      throw new IllegalStateException
677
        ("Old input was not completely processed");
678
 
679
    int end = off + len;
680
 
681
    /* We want to throw an ArrayIndexOutOfBoundsException early.  The
682
     * check is very tricky: it also handles integer wrap around.
683
     */
684
    if (0 > off || off > end || end > buf.length)
685
      throw new ArrayIndexOutOfBoundsException();
686
 
687
    inputBuf = buf;
688
    inputOff = off;
689
    inputEnd = end;
690
  }
691
 
692
  public final boolean needsInput()
693
  {
694
    return inputEnd == inputOff;
695
  }
696
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.