/** * Serializes a list of Extra Fields of {@link #getExtraLength} bytes to the * byte array {@code data} at the zero based offset {@code off}. * Upon return, this collection shall not access {@code data} * subsequently. * * @param data The byte array to write the list of Extra Fields to. * @param off The zero based offset in the byte array where the first byte * of the list of Extra Fields is written to. * @throws IndexOutOfBoundsException If the byte array * {@code data} does not hold at least {@link #getExtraLength} * bytes at the zero based offset {@code off}. * @see #getExtraLength */ void writeTo(final byte[] data, int off) throws IndexOutOfBoundsException { for (final ExtraField ef : extra.values()) { writeShort(ef.getHeaderId(), data, off); off += 2; writeShort(ef.getDataSize(), data, off); off += 2; ef.writeTo(data, off); off += ef.getDataSize(); } } }
/** * Returns a protective copy of the data block. * * @see #getDataSize */ final byte[] getDataBlock() { final int size = getDataSize(); assert UShort.check(size); if (0 == size) return EMPTY; final byte[] data = new byte[size]; writeTo(data, 0); return data; }
@Test public void testCreate() { ExtraField ef; ExtraField.register(NullExtraField.class); ef = ExtraField.create(0x0000); assertTrue(ef instanceof NullExtraField); assertEquals(0x0000, ef.getHeaderId()); ef = ExtraField.create(0x0001); //assertTrue(ef instanceof Zip64ExtraField); assertTrue(ef instanceof DefaultExtraField); assertEquals(0x0001, ef.getHeaderId()); ef = ExtraField.create(0x0002); assertTrue(ef instanceof DefaultExtraField); assertEquals(0x0002, ef.getHeaderId()); ef = ExtraField.create(UShort.MAX_VALUE); assertTrue(ef instanceof DefaultExtraField); assertEquals(UShort.MAX_VALUE, ef.getHeaderId()); try { ef = ExtraField.create(UShort.MIN_VALUE - 1); fail(); } catch (IllegalArgumentException expected) { } try { ef = ExtraField.create(UShort.MAX_VALUE + 1); fail(); } catch (IllegalArgumentException expected) { } }
/** * Removes the Extra Field with the given Header ID. * * @param headerId The requested Header ID. * @return The Extra Field with the given Header ID or {@code null} * if no such Extra Field exists. * @throws IllegalArgumentException If {@code headerID} is not in * the range of {@code 0} to {@link UShort#MAX_VALUE} * ({@value de.schlichtherle.truezip.zip.UShort#MAX_VALUE}). */ @Nullable ExtraField remove(final int headerId) { assert UShort.check(headerId); final ExtraField ef = extra.remove(headerId); assert null == ef || ef.getHeaderId() == headerId; return ef; }
/** * Returns the number of bytes required to hold the Extra Fields. * * @return The length of the Extra Fields in bytes. * May be {@code 0}. * @see #getExtra */ int getExtraLength() { final Map<Integer, ExtraField> extra = this.extra; if (extra.isEmpty()) return 0; int l = 0; for (ExtraField ef : extra.values()) l += 4 + ef.getDataSize(); return l; }
@Test public void testRegister() { try { ExtraField.register(null); fail(); } catch (NullPointerException expected) { } try { ExtraField.register(TooSmallHeaderIDExtraField.class); fail(); } catch (IllegalArgumentException expected) { } try { ExtraField.register(TooLargeHeaderIDExtraField.class); fail(); } catch (IllegalArgumentException expected) { } ExtraField.register(NullExtraField.class); }
if (off > 0) { field = new DefaultExtraField(ZIP64_HEADER_ID); field.readFrom(data, 0, off); } else { field = null;
final ExtraField ef = fields.get(ZIP64_HEADER_ID); if (null == ef) return; final byte[] data = ef.getDataBlock(); int off = 0;
/** * Returns the Extra Field with the given Header ID or {@code null} * if no such Extra Field exists. * * @param headerId The requested Header ID. * @return The Extra Field with the given Header ID or {@code null} * if no such Extra Field exists. * @throws IllegalArgumentException If {@code headerID} is not in * the range of {@code 0} to {@link UShort#MAX_VALUE} * ({@value de.schlichtherle.truezip.zip.UShort#MAX_VALUE}). */ @CheckForNull ExtraField get(final int headerId) { assert UShort.check(headerId); final ExtraField ef = extra.get(headerId); assert null == ef || ef.getHeaderId() == headerId; return ef; }
@Test public void testCollection1() { assertEquals(0, fields.getExtra().length); final ExtraField ef = new DefaultExtraField(ExtraField.ZIP64_HEADER_ID); assertNull(fields.get(ExtraField.ZIP64_HEADER_ID)); assertNull(fields.add(ef)); byte[] got = fields.getExtra(); assertEquals(4 + ef.getDataSize(), got.length); assertSame(ef, fields.remove(ExtraField.ZIP64_HEADER_ID)); assertEquals(0, fields.getExtra().length); } }
/** * Stores the given Extra Field in this collection. * * @param ef The Extra Field to store in this collection. * @return The Extra Field previously associated with the Header ID of * of the given Extra Field or {@code null} if no such * Extra Field existed. * @throws NullPointerException If {@code ef} is {@code null}. * @throws IllegalArgumentException If the Header ID of the given Extra * Field is not in the range of {@code 0} to * {@link UShort#MAX_VALUE} * ({@value de.schlichtherle.truezip.zip.UShort#MAX_VALUE}). */ ExtraField add(final ExtraField ef) { final int headerId = ef.getHeaderId(); assert UShort.check(headerId); return extra.put(headerId, ef); }
/** * Registers a concrete implementation of this abstract base class for * use with the static factory method {@link #create}. * * @param c the implementation class of this abstract base class. * @throws IllegalArgumentException if {@code c} cannot get instantiated, * is not a subclass of {@code ExtraField} or its Header ID is out * of range. * A more descriptive exception may be associated to it as its * cause. * @see #create */ static void register(final Class<? extends ExtraField> c) { final ExtraField ef; try { ef = (ExtraField) c.newInstance(); } catch (NullPointerException ex) { throw ex; } catch (Exception ex) { throw new IllegalArgumentException(ex); } final int headerId = ef.getHeaderId(); assert UShort.check(headerId); registry.put(headerId, c); }
/** * A static contrstructor which creates a new extra field based on the * given header id. * The returned extra field still requires proper initialization, for * example by calling {@link #readFrom}. * * @param headerId An unsigned short integer (two bytes) which indicates * the type of the returned extra field. * @return A new extra field * @see #register */ static ExtraField create(final int headerId) { assert UShort.check(headerId); final Class<? extends ExtraField> c = registry.get(headerId); final ExtraField ef; try { ef = null != c ? (ExtraField) c.newInstance() : new DefaultExtraField(headerId); } catch (Exception cannotHappen) { throw new AssertionError(cannotHappen); } assert headerId == ef.getHeaderId(); return ef; }