1. /*
  2. * Copyright 2001-2002,2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.zip;
  18. import java.util.Hashtable;
  19. import java.util.Vector;
  20. import java.util.zip.ZipException;
  21. /**
  22. * ZipExtraField related methods
  23. *
  24. * @version $Revision: 1.5.2.4 $
  25. */
  26. public class ExtraFieldUtils {
  27. /**
  28. * Static registry of known extra fields.
  29. *
  30. * @since 1.1
  31. */
  32. private static Hashtable implementations;
  33. static {
  34. implementations = new Hashtable();
  35. register(AsiExtraField.class);
  36. }
  37. /**
  38. * Register a ZipExtraField implementation.
  39. *
  40. * <p>The given class must have a no-arg constructor and implement
  41. * the {@link ZipExtraField ZipExtraField interface}.</p>
  42. *
  43. * @since 1.1
  44. */
  45. public static void register(Class c) {
  46. try {
  47. ZipExtraField ze = (ZipExtraField) c.newInstance();
  48. implementations.put(ze.getHeaderId(), c);
  49. } catch (ClassCastException cc) {
  50. throw new RuntimeException(c + " doesn\'t implement ZipExtraField");
  51. } catch (InstantiationException ie) {
  52. throw new RuntimeException(c + " is not a concrete class");
  53. } catch (IllegalAccessException ie) {
  54. throw new RuntimeException(c + "\'s no-arg constructor is not public");
  55. }
  56. }
  57. /**
  58. * Create an instance of the approriate ExtraField, falls back to
  59. * {@link UnrecognizedExtraField UnrecognizedExtraField}.
  60. *
  61. * @since 1.1
  62. */
  63. public static ZipExtraField createExtraField(ZipShort headerId)
  64. throws InstantiationException, IllegalAccessException {
  65. Class c = (Class) implementations.get(headerId);
  66. if (c != null) {
  67. return (ZipExtraField) c.newInstance();
  68. }
  69. UnrecognizedExtraField u = new UnrecognizedExtraField();
  70. u.setHeaderId(headerId);
  71. return u;
  72. }
  73. /**
  74. * Split the array into ExtraFields and populate them with the
  75. * give data.
  76. *
  77. * @since 1.1
  78. */
  79. public static ZipExtraField[] parse(byte[] data) throws ZipException {
  80. Vector v = new Vector();
  81. int start = 0;
  82. while (start <= data.length - 4) {
  83. ZipShort headerId = new ZipShort(data, start);
  84. int length = (new ZipShort(data, start + 2)).getValue();
  85. if (start + 4 + length > data.length) {
  86. throw new ZipException("data starting at " + start
  87. + " is in unknown format");
  88. }
  89. try {
  90. ZipExtraField ze = createExtraField(headerId);
  91. ze.parseFromLocalFileData(data, start + 4, length);
  92. v.addElement(ze);
  93. } catch (InstantiationException ie) {
  94. throw new ZipException(ie.getMessage());
  95. } catch (IllegalAccessException iae) {
  96. throw new ZipException(iae.getMessage());
  97. }
  98. start += (length + 4);
  99. }
  100. if (start != data.length) { // array not exhausted
  101. throw new ZipException("data starting at " + start
  102. + " is in unknown format");
  103. }
  104. ZipExtraField[] result = new ZipExtraField[v.size()];
  105. v.copyInto(result);
  106. return result;
  107. }
  108. /**
  109. * Merges the local file data fields of the given ZipExtraFields.
  110. *
  111. * @since 1.1
  112. */
  113. public static byte[] mergeLocalFileDataData(ZipExtraField[] data) {
  114. int sum = 4 * data.length;
  115. for (int i = 0; i < data.length; i++) {
  116. sum += data[i].getLocalFileDataLength().getValue();
  117. }
  118. byte[] result = new byte[sum];
  119. int start = 0;
  120. for (int i = 0; i < data.length; i++) {
  121. System.arraycopy(data[i].getHeaderId().getBytes(),
  122. 0, result, start, 2);
  123. System.arraycopy(data[i].getLocalFileDataLength().getBytes(),
  124. 0, result, start + 2, 2);
  125. byte[] local = data[i].getLocalFileDataData();
  126. System.arraycopy(local, 0, result, start + 4, local.length);
  127. start += (local.length + 4);
  128. }
  129. return result;
  130. }
  131. /**
  132. * Merges the central directory fields of the given ZipExtraFields.
  133. *
  134. * @since 1.1
  135. */
  136. public static byte[] mergeCentralDirectoryData(ZipExtraField[] data) {
  137. int sum = 4 * data.length;
  138. for (int i = 0; i < data.length; i++) {
  139. sum += data[i].getCentralDirectoryLength().getValue();
  140. }
  141. byte[] result = new byte[sum];
  142. int start = 0;
  143. for (int i = 0; i < data.length; i++) {
  144. System.arraycopy(data[i].getHeaderId().getBytes(),
  145. 0, result, start, 2);
  146. System.arraycopy(data[i].getCentralDirectoryLength().getBytes(),
  147. 0, result, start + 2, 2);
  148. byte[] local = data[i].getCentralDirectoryData();
  149. System.arraycopy(local, 0, result, start + 4, local.length);
  150. start += (local.length + 4);
  151. }
  152. return result;
  153. }
  154. }