gt:         if (current == null) {
context: /*
   * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  package java.util.zip;
  
  import java.io.OutputStream;
  import java.io.IOException;
  import java.nio.charset.Charset;
  import java.nio.charset.StandardCharsets;
  import java.util.Vector;
  import java.util.HashSet;
  import static java.util.zip.ZipConstants64.*;
  import static java.util.zip.ZipUtils.*;
  
  /**
   * This class implements an output stream filter for writing files in the
   * ZIP file format. Includes support for both compressed and uncompressed
   * entries.
   *
   * @author      David Connelly
   */
  public
  class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
  
      /**
       * Whether to use ZIP64 for zip files with more than 64k entries.
       * Until ZIP64 support in zip implementations is ubiquitous, this
       * system property allows the creation of zip files which can be
       * read by legacy zip implementations which tolerate "incorrect"
       * total entry count fields, such as the ones in jdk6, and even
       * some in jdk7.
       */
      private static final boolean inhibitZip64 =
          Boolean.parseBoolean(
              java.security.AccessController.doPrivileged(
                  new sun.security.action.GetPropertyAction(
                      "jdk.util.zip.inhibitZip64", "false")));
  
      private static class XEntry {
          final ZipEntry entry;
          final long offset;
          long dostime;    // last modification time in msdos format
          public XEntry(ZipEntry entry, long offset) {
              this.entry = entry;
              this.offset = offset;
          }
      }
  
      private XEntry current;
      private Vector<XEntry> xentries = new Vector<>();
      private HashSet<String> names = new HashSet<>();
      private CRC32 crc = new CRC32();
      private long written = 0;
      private long locoff = 0;
      private byte[] comment;
      private int method = DEFLATED;
      private boolean finished;
  
      private boolean closed = false;
  
      private final ZipCoder zc;
  
      private static int version(ZipEntry e) throws ZipException {
          switch (e.method) {
          case DEFLATED: return 20;
          case STORED:   return 10;
          default: throw new ZipException("unsupported compression method");
          }
      }
  
      /**
       * Checks to make sure that this stream has not been closed.
       */
      private void ensureOpen() throws IOException {
          if (closed) {
              throw new IOException("Stream closed");
          }
      }
      /**
       * Compression method for uncompressed (STORED) entries.
       */
      public static final int STORED = ZipEntry.STORED;
  
      /**
       * Compression method for compressed (DEFLATED) entries.
       */
      public static final int DEFLATED = ZipEntry.DEFLATED;
  
      /**
       * Creates a new ZIP output stream.
       *
       * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
       * to encode the entry names and comments.
       *
       * @param out the actual output stream
       */
      public ZipOutputStream(OutputStream out) {
          this(out, StandardCharsets.UTF_8);
      }
  
      /**
       * Creates a new ZIP output stream.
       *
       * @param out the actual output stream
       *
       * @param charset the {@linkplain java.nio.charset.Charset charset}
       *                to be used to encode the entry names and comments
       *
       * @since 1.7
       */
      public ZipOutputStream(OutputStream out, Charset charset) {
          super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
          if (charset == null)
              throw new NullPointerException("charset is null");
          this.zc = ZipCoder.get(charset);
          usesDefaultDeflater = true;
      }
  
      /**
       * Sets the ZIP file comment.
       * @param comment the comment string
       * @exception IllegalArgumentException if the length of the specified
       *            ZIP file comment is greater than 0xFFFF bytes
       */
      public void setComment(String comment) {
          if (comment != null) {
              this.comment = zc.getBytes(comment);
              if (this.comment.length > 0xffff)
                  throw new IllegalArgumentException("ZIP file comment too long.");
          }
      }
  
      /**
       * Sets the default compression method for subsequent entries. This
       * default will be used whenever the compression method is not specified
       * for an individual ZIP file entry, and is initially set to DEFLATED.
       * @param method the default compression method
       * @exception IllegalArgumentException if the specified compression method
       *            is invalid
       */
      public void setMethod(int method) {
          if (method != DEFLATED && method != STORED) {
              throw new IllegalArgumentException("invalid compression method");
          }
          this.method = method;
      }
  
      /**
       * Sets the compression level for subsequent entries which are DEFLATED.
       * The default setting is DEFAULT_COMPRESSION.
       * @param level the compression level (0-9)
       * @exception IllegalArgumentException if the compression level is invalid
       */
      public void setLevel(int level) {
          def.setLevel(level);
      }
  
      /**
       * Begins writing a new ZIP file entry and positions the stream to the
       * start of the entry data. Closes the current entry if still active.
       * The default compression method will be used if no compression method
       * was specified for the entry, and the current time will be used if
       * the entry has no set modification time.
       * @param e the ZIP entry to be written
       * @exception ZipException if a ZIP format error has occurred
       * @exception IOException if an I/O error has occurred
       */
      public void putNextEntry(ZipEntry e) throws IOException {
          ensureOpen();
          if (current != null) {
              closeEntry();       // close previous entry
          }
          if (e.time == -1) {
              // by default, do NOT use extended timestamps in extra
              // data, for now.
              e.setTime(System.currentTimeMillis());
          }
          if (e.method == -1) {
              e.method = method;  // use default method
          }
          // store size, compressed size, and crc-32 in LOC header
          e.flag = 0;
          switch (e.method) {
          case DEFLATED:
              // store size, compressed size, and crc-32 in data descriptor
              // immediately following the compressed entry data
              if (e.size  == -1 || e.csize == -1 || e.crc   == -1)
                  e.flag = 8;
  
              break;
          case STORED:
              // compressed size, uncompressed size, and crc-32 must all be
              // set for entries using STORED compression method
              if (e.size == -1) {
                  e.size = e.csize;
              } else if (e.csize == -1) {
                  e.csize = e.size;
              } else if (e.size != e.csize) {
                  throw new ZipException(
                      "STORED entry where compressed != uncompressed size");
              }
              if (e.size == -1 || e.crc == -1) {
                  throw new ZipException(
                      "STORED entry missing size, compressed size, or crc-32");
              }
              break;
          default:
              throw new ZipException("unsupported compression method");
          }
          if (! names.add(e.name)) {
              throw new ZipException("duplicate entry: " + e.name);
          }
          if (zc.isUTF8())
              e.flag |= EFS;
          current = new XEntry(e, written);
          xentries.add(current);
          writeLOC(current);
      }
  
      /**
       * Closes the current ZIP entry and positions the stream for writing
       * the next entry.
       * @exception ZipException if a ZIP format error has occurred
       * @exception IOException if an I/O error has occurred
       */
      public void closeEntry() throws IOException {
          ensureOpen();
          if (current != null) {
              ZipEntry e = current.entry;
              switch (e.method) {
              case DEFLATED:
                  def.finish();
                  while (!def.finished()) {
                      deflate();
                  }
                  if ((e.flag & 8) == 0) {
                      // verify size, compressed size, and crc-32 settings
                      if (e.size != def.getBytesRead()) {
                          throw new ZipException(
                              "invalid entry size (expected " + e.size +
                              " but got " + def.getBytesRead() + " bytes)");
                      }
                      if (e.csize != def.getBytesWritten()) {
                          throw new ZipException(
                              "invalid entry compressed size (expected " +
                              e.csize + " but got " + def.getBytesWritten() + " bytes)");
                      }
                      if (e.crc != crc.getValue()) {
                          throw new ZipException(
                              "invalid entry CRC-32 (expected 0x" +
                              Long.toHexString(e.crc) + " but got 0x" +
                              Long.toHexString(crc.getValue()) + ")");
                      }
                  } else {
                      e.size  = def.getBytesRead();
                      e.csize = def.getBytesWritten();
                      e.crc = crc.getValue();
                      writeEXT(e);
                  }
                  def.reset();
                  written += e.csize;
                  break;
              case STORED:
                  // we already know that both e.size and e.csize are the same
                  if (e.size != written - locoff) {
                      throw new ZipException(
                          "invalid entry size (expected " + e.size +
                          " but got " + (written - locoff) + " bytes)");
                  }
                  if (e.crc != crc.getValue()) {
                      throw new ZipException(
                           "invalid entry crc-32 (expected 0x" +
                           Long.toHexString(e.crc) + " but got 0x" +
                           Long.toHexString(crc.getValue()) + ")");
                  }
                  break;
              default:
                  throw new ZipException("invalid compression method");
              }
              crc.reset();
              current = null;
          }
      }
  
      /**
       * Writes an array of bytes to the current ZIP entry data. This method
       * will block until all the bytes are written.
       * @param b the data to be written
       * @param off the start offset in the data
       * @param len the number of bytes that are written
       * @exception ZipException if a ZIP file error has occurred
       * @exception IOException if an I/O error has occurred
       */
      public synchronized void write(byte[] b, int off, int len)
          throws IOException
      {
          ensureOpen();
          if (off < 0 || len < 0 || off > b.length - len) {
              throw new IndexOutOfBoundsException();
          } else if (len == 0) {
              return;
          }
  
  