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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [util/] [zip/] [DeflaterEngine.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* DeflaterEngine.java --
2
   Copyright (C) 2001, 2004, 2005  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 long 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 long 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
 
383
      if (scan > best_end) {
384
//      if (DeflaterConstants.DEBUGGING && ins_h == 0)
385
//        System.err.println("Found match: "+curMatch+"-"+(scan-strstart));
386
        matchStart = curMatch;
387
        best_end = scan;
388
        best_len = scan - strstart;
389
        if (best_len >= niceLength)
390
          break;
391
 
392
        scan_end1  = window[best_end-1];
393
        scan_end   = window[best_end];
394
      }
395
      scan = strstart;
396
    } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit
397
             && --chainLength != 0);
398
 
399
    matchLen = Math.min(best_len, lookahead);
400
    return matchLen >= MIN_MATCH;
401
  }
402
 
403
  void setDictionary(byte[] buffer, int offset, int length) {
404
    if (DeflaterConstants.DEBUGGING && strstart != 1)
405
      throw new IllegalStateException("strstart not 1");
406
    adler.update(buffer, offset, length);
407
    if (length < MIN_MATCH)
408
      return;
409
    if (length > MAX_DIST) {
410
      offset += length - MAX_DIST;
411
      length = MAX_DIST;
412
    }
413
 
414
    System.arraycopy(buffer, offset, window, strstart, length);
415
 
416
    updateHash();
417
    length--;
418
    while (--length > 0)
419
      {
420
        insertString();
421
        strstart++;
422
      }
423
    strstart += 2;
424
    blockStart = strstart;
425
  }
426
 
427
  private boolean deflateStored(boolean flush, boolean finish)
428
  {
429
    if (!flush && lookahead == 0)
430
      return false;
431
 
432
    strstart += lookahead;
433
    lookahead = 0;
434
 
435
    int storedLen = strstart - blockStart;
436
 
437
    if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE)
438
        /* Block is full */
439
        || (blockStart < WSIZE && storedLen >= MAX_DIST)
440
        /* Block may move out of window */
441
        || flush)
442
      {
443
        boolean lastBlock = finish;
444
        if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE)
445
          {
446
            storedLen = DeflaterConstants.MAX_BLOCK_SIZE;
447
            lastBlock = false;
448
          }
449
 
450
        if (DeflaterConstants.DEBUGGING)
451
          System.err.println("storedBlock["+storedLen+","+lastBlock+"]");
452
 
453
        huffman.flushStoredBlock(window, blockStart, storedLen, lastBlock);
454
        blockStart += storedLen;
455
        return !lastBlock;
456
      }
457
    return true;
458
  }
459
 
460
  private boolean deflateFast(boolean flush, boolean finish)
461
  {
462
    if (lookahead < MIN_LOOKAHEAD && !flush)
463
      return false;
464
 
465
    while (lookahead >= MIN_LOOKAHEAD || flush)
466
      {
467
        if (lookahead == 0)
468
          {
469
            /* We are flushing everything */
470
            huffman.flushBlock(window, blockStart, strstart - blockStart,
471
                               finish);
472
            blockStart = strstart;
473
            return false;
474
          }
475
 
476
        if (strstart > 2 * WSIZE - MIN_LOOKAHEAD)
477
          {
478
            /* slide window, as findLongestMatch need this.
479
             * This should only happen when flushing and the window
480
             * is almost full.
481
             */
482
            slideWindow();
483
          }
484
 
485
        int hashHead;
486
        if (lookahead >= MIN_MATCH
487
            && (hashHead = insertString()) != 0
488
            && strategy != Deflater.HUFFMAN_ONLY
489
            && strstart - hashHead <= MAX_DIST
490
            && findLongestMatch(hashHead))
491
          {
492
            /* longestMatch sets matchStart and matchLen */
493
            if (DeflaterConstants.DEBUGGING)
494
              {
495
                for (int i = 0 ; i < matchLen; i++)
496
                  {
497
                    if (window[strstart+i] != window[matchStart + i])
498
                      throw new InternalError();
499
                  }
500
              }
501
            boolean full = huffman.tallyDist(strstart - matchStart, matchLen);
502
 
503
            lookahead -= matchLen;
504
            if (matchLen <= max_lazy && lookahead >= MIN_MATCH)
505
              {
506
                while (--matchLen > 0)
507
                  {
508
                    strstart++;
509
                    insertString();
510
                  }
511
                strstart++;
512
              }
513
            else
514
              {
515
                strstart += matchLen;
516
                if (lookahead >= MIN_MATCH - 1)
517
                  updateHash();
518
              }
519
            matchLen = MIN_MATCH - 1;
520
            if (!full)
521
              continue;
522
          }
523
        else
524
          {
525
            /* No match found */
526
            huffman.tallyLit(window[strstart] & 0xff);
527
            strstart++;
528
            lookahead--;
529
          }
530
 
531
        if (huffman.isFull())
532
          {
533
            boolean lastBlock = finish && lookahead == 0;
534
            huffman.flushBlock(window, blockStart, strstart - blockStart,
535
                               lastBlock);
536
            blockStart = strstart;
537
            return !lastBlock;
538
          }
539
      }
540
    return true;
541
  }
542
 
543
  private boolean deflateSlow(boolean flush, boolean finish)
544
  {
545
    if (lookahead < MIN_LOOKAHEAD && !flush)
546
      return false;
547
 
548
    while (lookahead >= MIN_LOOKAHEAD || flush)
549
      {
550
        if (lookahead == 0)
551
          {
552
            if (prevAvailable)
553
              huffman.tallyLit(window[strstart-1] & 0xff);
554
            prevAvailable = false;
555
 
556
            /* We are flushing everything */
557
            if (DeflaterConstants.DEBUGGING && !flush)
558
              throw new InternalError("Not flushing, but no lookahead");
559
            huffman.flushBlock(window, blockStart, strstart - blockStart,
560
                               finish);
561
            blockStart = strstart;
562
            return false;
563
          }
564
 
565
        if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD)
566
          {
567
            /* slide window, as findLongestMatch need this.
568
             * This should only happen when flushing and the window
569
             * is almost full.
570
             */
571
            slideWindow();
572
          }
573
 
574
        int prevMatch = matchStart;
575
        int prevLen = matchLen;
576
        if (lookahead >= MIN_MATCH)
577
          {
578
            int hashHead = insertString();
579
            if (strategy != Deflater.HUFFMAN_ONLY
580
                && hashHead != 0 && strstart - hashHead <= MAX_DIST
581
                && findLongestMatch(hashHead))
582
              {
583
                /* longestMatch sets matchStart and matchLen */
584
 
585
                /* Discard match if too small and too far away */
586
                if (matchLen <= 5
587
                    && (strategy == Deflater.FILTERED
588
                        || (matchLen == MIN_MATCH
589
                            && strstart - matchStart > TOO_FAR))) {
590
                  matchLen = MIN_MATCH - 1;
591
                }
592
              }
593
          }
594
 
595
        /* previous match was better */
596
        if (prevLen >= MIN_MATCH && matchLen <= prevLen)
597
          {
598
            if (DeflaterConstants.DEBUGGING)
599
              {
600
                for (int i = 0 ; i < matchLen; i++)
601
                  {
602
                    if (window[strstart-1+i] != window[prevMatch + i])
603
                      throw new InternalError();
604
                  }
605
              }
606
            huffman.tallyDist(strstart - 1 - prevMatch, prevLen);
607
            prevLen -= 2;
608
            do
609
              {
610
                strstart++;
611
                lookahead--;
612
                if (lookahead >= MIN_MATCH)
613
                  insertString();
614
              }
615
            while (--prevLen > 0);
616
            strstart ++;
617
            lookahead--;
618
            prevAvailable = false;
619
            matchLen = MIN_MATCH - 1;
620
          }
621
        else
622
          {
623
            if (prevAvailable)
624
              huffman.tallyLit(window[strstart-1] & 0xff);
625
            prevAvailable = true;
626
            strstart++;
627
            lookahead--;
628
          }
629
 
630
        if (huffman.isFull())
631
          {
632
            int len = strstart - blockStart;
633
            if (prevAvailable)
634
              len--;
635
            boolean lastBlock = (finish && lookahead == 0 && !prevAvailable);
636
            huffman.flushBlock(window, blockStart, len, lastBlock);
637
            blockStart += len;
638
            return !lastBlock;
639
          }
640
      }
641
    return true;
642
  }
643
 
644
  public boolean deflate(boolean flush, boolean finish)
645
  {
646
    boolean progress;
647
    do
648
      {
649
        fillWindow();
650
        boolean canFlush = flush && inputOff == inputEnd;
651
        if (DeflaterConstants.DEBUGGING)
652
          System.err.println("window: ["+blockStart+","+strstart+","
653
                             +lookahead+"], "+comprFunc+","+canFlush);
654
        switch (comprFunc)
655
          {
656
          case DEFLATE_STORED:
657
            progress = deflateStored(canFlush, finish);
658
            break;
659
          case DEFLATE_FAST:
660
            progress = deflateFast(canFlush, finish);
661
            break;
662
          case DEFLATE_SLOW:
663
            progress = deflateSlow(canFlush, finish);
664
            break;
665
          default:
666
            throw new InternalError();
667
          }
668
      }
669
    while (pending.isFlushed()  /* repeat while we have no pending output */
670
           && progress);        /* and progress was made */
671
 
672
    return progress;
673
  }
674
 
675
  public void setInput(byte[] buf, int off, int len)
676
  {
677
    if (inputOff < inputEnd)
678
      throw new IllegalStateException
679
        ("Old input was not completely processed");
680
 
681
    int end = off + len;
682
 
683
    /* We want to throw an ArrayIndexOutOfBoundsException early.  The
684
     * check is very tricky: it also handles integer wrap around.
685
     */
686
    if (0 > off || off > end || end > buf.length)
687
      throw new ArrayIndexOutOfBoundsException();
688
 
689
    inputBuf = buf;
690
    inputOff = off;
691
    inputEnd = end;
692
  }
693
 
694
  public final boolean needsInput()
695
  {
696
    return inputEnd == inputOff;
697
  }
698
}

powered by: WebSVN 2.1.0

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