docs: public void instrumentZipFile(File zf) throws IOException {
          if (!zf.canRead() || !zf.canWrite()) {
              throw new IOException(zf + " can not be replaced");
          }
  
          File tempFile = File.createTempFile(zf.getName(), null, zf.getParentFile());
          if (tempFile.exists() && !tempFile.delete()) {
              throw new IOException("Unable to delete existing temp file " + tempFile.getName());
          }
          if (!zf.renameTo(tempFile)) {
              throw new IOException("Unable to rename existing jar " + zf);
          }
  
          ZipFile zipFile = new ZipFile(tempFile);
          FileOutputStream fos = new FileOutputStream(zf);
          ZipOutputStream zos = new ZipOutputStream(fos);
          boolean restoreZipFile = false;
          try {
              byte[] buffer = new byte[8192];
              Enumeration<? extends ZipEntry> e = zipFile.entries();
              while (e.hasMoreElements()) {
                  ZipEntry oldEntry = e.nextElement();
                  InputStream zis = zipFile.getInputStream(oldEntry);
                  byte[] transformedClass = null;
  
                  if (oldEntry.getName().endsWith(".class")) {
                      transformedClass = transform(zis);
                      if (transformedClass == null) {
                          zis = zipFile.getInputStream(oldEntry);
                      }
                  }
  
                  ZipEntry newEntry = new ZipEntry(oldEntry.getName());
                  newEntry.setTime(transformedClass == null ? oldEntry.getTime() : System.currentTimeMillis());
                  newEntry.setComment(oldEntry.getComment());
                  newEntry.setExtra(oldEntry.getExtra());
                  newEntry.setSize(transformedClass == null ? oldEntry.getSize() : transformedClass.length);
  
                  if (newEntry.getSize() > Integer.MAX_VALUE) {
                      throw new IOException("ZipEntry too large: " + newEntry.getSize());
                  }
  
                  int entrySize = (int) newEntry.getSize();
                  if (entrySize > buffer.length) {
                      buffer = new byte[entrySize];
                  }
  
                  if (transformedClass != null) {
                      System.arraycopy(transformedClass, 0, buffer, 0, entrySize);
                  } else {
                      int totalBytesRead = 0;
                      while (totalBytesRead < entrySize) {
                          int bytesRead = zis.read(buffer, totalBytesRead, entrySize - totalBytesRead);
                          if (bytesRead == -1) {
                              throw new IOException("End of file encountered");
                          }
                          totalBytesRead += bytesRead;
                      }
                  }
  
                  zos.putNextEntry(newEntry);
                  zos.write(buffer, 0, entrySize);
              }
          } catch (IOException ioe) {
              restoreZipFile = true;
              throw ioe;
          } catch (Throwable t) {
              restoreZipFile = true;
              IOException ioe = new IOException("Unexpected exception encountered during instrumentation");
              ioe.initCause(t);
              throw ioe;
          } finally {
              zos.close();
              fos.close();
              zipFile.close();
              if (restoreZipFile) {
                  zf.delete();
                  tempFile.renameTo(zf);
              } else {
                  tempFile.delete();
              }
          }
      }