1 /*
   2  * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.imageio.plugins.common;
  27 
  28 import java.io.IOException;
  29 import javax.imageio.stream.ImageOutputStream;
  30 
  31 /*
  32  * Came from GIFEncoder initially.
  33  * Modified - to allow for output compressed data without the block counts
  34  * which breakup the compressed data stream for GIF.
  35  */
  36 public class BitFile {
  37     ImageOutputStream output;
  38     byte[] buffer;
  39     int index;
  40     int bitsLeft; // bits left at current index that are avail.
  41 
  42     /** note this also indicates gif format BITFile. **/
  43     boolean blocks = false;
  44 
  45     /*
  46      * @param output destination for output data
  47      * @param blocks GIF LZW requires block counts for output data
  48      */
  49     public BitFile(ImageOutputStream output, boolean blocks) {
  50         this.output = output;
  51         this.blocks = blocks;
  52         buffer = new byte[256];
  53         index = 0;
  54         bitsLeft = 8;
  55     }
  56 
  57     public void flush() throws IOException {
  58         int numBytes = index + (bitsLeft == 8 ? 0 : 1);
  59         if (numBytes > 0) {
  60             if (blocks) {
  61                 output.write(numBytes);
  62             }
  63             output.write(buffer, 0, numBytes);
  64             buffer[0] = 0;
  65             index = 0;
  66             bitsLeft = 8;
  67         }
  68     }
  69 
  70     public void writeBits(int bits, int numbits) throws IOException {
  71         int bitsWritten = 0;
  72         int numBytes = 255;  // gif block count
  73         do {
  74             // This handles the GIF block count stuff
  75             if ((index == 254 && bitsLeft == 0) || index > 254) {
  76                 if (blocks) {
  77                     output.write(numBytes);
  78                 }
  79 
  80                 output.write(buffer, 0, numBytes);
  81 
  82                 buffer[0] = 0;
  83                 index = 0;
  84                 bitsLeft = 8;
  85             }
  86 
  87             if (numbits <= bitsLeft) { // bits contents fit in current index byte
  88                 if (blocks) { // GIF
  89                     buffer[index] |= (bits & ((1 << numbits) - 1)) << (8 - bitsLeft);
  90                     bitsWritten += numbits;
  91                     bitsLeft -= numbits;
  92                     numbits = 0;
  93                 } else {
  94                     buffer[index] |= (bits & ((1 << numbits) - 1)) << (bitsLeft - numbits);
  95                     bitsWritten += numbits;
  96                     bitsLeft -= numbits;
  97                     numbits = 0;
  98                 }
  99             } else { // bits overflow from current byte to next.
 100                 if (blocks) { // GIF
 101                     // if bits  > space left in current byte then the lowest order bits
 102                     // of code are taken and put in current byte and rest put in next.
 103                     buffer[index] |= (bits & ((1 << bitsLeft) - 1)) << (8 - bitsLeft);
 104                     bitsWritten += bitsLeft;
 105                     bits >>= bitsLeft;
 106                     numbits -= bitsLeft;
 107                     buffer[++index] = 0;
 108                     bitsLeft = 8;
 109                 } else {
 110                     // if bits  > space left in current byte then the highest order bits
 111                     // of code are taken and put in current byte and rest put in next.
 112                     // at highest order bit location !!
 113                     int topbits = (bits >>> (numbits - bitsLeft)) & ((1 << bitsLeft) - 1);
 114                     buffer[index] |= topbits;
 115                     numbits -= bitsLeft;  // ok this many bits gone off the top
 116                     bitsWritten += bitsLeft;
 117                     buffer[++index] = 0;  // next index
 118                     bitsLeft = 8;
 119                 }
 120             }
 121         } while (numbits != 0);
 122     }
 123 }