/** * Write String {@code object} into the receiver. It is assumed the * String has not been dumped yet. Returns the handle for this object (String) which is dumped here. * Strings are saved encoded with {@link DataInput modified UTF-8}. * * @param object * the string to dump. * @return the handle assigned to the String being dumped * * @throws IOException * If an IO exception happened when writing the String. */ private int writeNewString(String object, boolean unshared) throws IOException { long count = ModifiedUtf8.countBytes(object, false); byte[] buffer; int offset = 0; if (count <= 0xffff) { buffer = new byte[1 + SizeOf.SHORT + (int) count]; buffer[offset++] = TC_STRING; Memory.pokeShort(buffer, offset, (short) count, ByteOrder.BIG_ENDIAN); offset += SizeOf.SHORT; } else { buffer = new byte[1 + SizeOf.LONG + (int) count]; buffer[offset++] = TC_LONGSTRING; Memory.pokeLong(buffer, offset, count, ByteOrder.BIG_ENDIAN); offset += SizeOf.LONG; } ModifiedUtf8.encode(buffer, offset, object); output.write(buffer, 0, buffer.length); int handle = nextHandle(); if (!unshared) { objectsWritten.put(object, handle); } return handle; }
/** * Returns the next entry from this {@code ZipInputStream} or {@code null} if * no more entries are present. * * @throws IOException if an {@code IOException} occurs. */ public ZipEntry getNextEntry() throws IOException { closeEntry(); if (entriesEnd) { return null; } // Read the signature to see whether there's another local file header. Streams.readFully(in, hdrBuf, 0, 4); int hdr = Memory.peekInt(hdrBuf, 0, ByteOrder.LITTLE_ENDIAN); if (hdr == CENSIG) { entriesEnd = true; return null; } if (hdr != LOCSIG) { return null; } // Read the local file header. Streams.readFully(in, hdrBuf, 0, (LOCHDR - LOCVER)); int version = peekShort(0) & 0xff; if (version > ZIPLocalHeaderVersionNeeded) { throw new ZipException("Cannot read local header version " + version); } int flags = peekShort(LOCFLG - LOCVER); if ((flags & ZipFile.GPBF_UNSUPPORTED_MASK) != 0) { throw new ZipException("Invalid General Purpose Bit Flag: " + flags); } hasDD = ((flags & ZipFile.GPBF_DATA_DESCRIPTOR_FLAG) != 0); int ceLastModifiedTime = peekShort(LOCTIM - LOCVER); int ceLastModifiedDate = peekShort(LOCTIM - LOCVER + 2); int ceCompressionMethod = peekShort(LOCHOW - LOCVER); long ceCrc = 0, ceCompressedSize = 0, ceSize = -1; if (!hasDD) { ceCrc = ((long) Memory.peekInt(hdrBuf, LOCCRC - LOCVER, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL; ceCompressedSize = ((long) Memory.peekInt(hdrBuf, LOCSIZ - LOCVER, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL; ceSize = ((long) Memory.peekInt(hdrBuf, LOCLEN - LOCVER, ByteOrder.LITTLE_ENDIAN)) & 0xffffffffL; } int nameLength = peekShort(LOCNAM - LOCVER); if (nameLength == 0) { throw new ZipException("Entry is not named"); } int extraLength = peekShort(LOCEXT - LOCVER); if (nameLength > nameBuf.length) { nameBuf = new byte[nameLength]; // The bytes are modified UTF-8, so the number of chars will always be less than or // equal to the number of bytes. It's fine if this buffer is too long. charBuf = new char[nameLength]; } Streams.readFully(in, nameBuf, 0, nameLength); currentEntry = createZipEntry(ModifiedUtf8.decode(nameBuf, charBuf, 0, nameLength)); currentEntry.time = ceLastModifiedTime; currentEntry.modDate = ceLastModifiedDate; currentEntry.setMethod(ceCompressionMethod); if (ceSize != -1) { currentEntry.setCrc(ceCrc); currentEntry.setSize(ceSize); currentEntry.setCompressedSize(ceCompressedSize); } if (extraLength > 0) { byte[] extraData = new byte[extraLength]; Streams.readFully(in, extraData, 0, extraLength); currentEntry.setExtra(extraData); } return currentEntry; }
public final void writeUTF(String str) throws IOException { write(ModifiedUtf8.encode(str)); }
private static String decodeUTF(int utfSize, DataInput in) throws IOException { byte[] buf = new byte[utfSize]; in.readFully(buf, 0, utfSize); return ModifiedUtf8.decode(buf, new char[utfSize], 0, utfSize); }
/** * Reads a string that is encoded in {@link DataInput modified UTF-8} from * this file. The number of bytes that must be read for the complete string * is determined by the first two bytes read from the file. Blocks until all * required bytes have been read, the end of the file is reached or an * exception is thrown. * * @return the next string encoded in {@link DataInput modified UTF-8} from * this file. * @throws EOFException * if the end of this file is detected. * @throws IOException * if this file is closed or another I/O error occurs. * @throws UTFDataFormatException * if the bytes read cannot be decoded into a character string. * @see #writeUTF(String) */ public final String readUTF() throws IOException { int utfSize = readUnsignedShort(); if (utfSize == 0) { return ""; } byte[] buf = new byte[utfSize]; if (read(buf, 0, buf.length) != buf.length) { throw new EOFException(); } return ModifiedUtf8.decode(buf, new char[utfSize], 0, utfSize); }
/** * Writes a string encoded with {@link DataInput modified UTF-8} to this * file, starting at the current file pointer. * * @param str * the string to write in {@link DataInput modified UTF-8} * format. * @throws IOException * if an I/O error occurs while writing to this file. * @throws UTFDataFormatException * if the encoded string is longer than 65535 bytes. * @see #readUTF() */ public final void writeUTF(String str) throws IOException { write(ModifiedUtf8.encode(str)); }