1. /*
  2. * @(#)ZipEntry.java 1.36 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util.zip;
  8. import java.util.Date;
  9. /**
  10. * This class is used to represent a ZIP file entry.
  11. *
  12. * @version 1.36, 12/19/03
  13. * @author David Connelly
  14. */
  15. public
  16. class ZipEntry implements ZipConstants, Cloneable {
  17. String name; // entry name
  18. long time = -1; // modification time (in DOS time)
  19. long crc = -1; // crc-32 of entry data
  20. long size = -1; // uncompressed size of entry data
  21. long csize = -1; // compressed size of entry data
  22. int method = -1; // compression method
  23. byte[] extra; // optional extra field data for entry
  24. String comment; // optional comment string for entry
  25. // The following flags are used only by Zip{Input,Output}Stream
  26. int flag; // bit flags
  27. int version; // version needed to extract
  28. long offset; // offset of loc header
  29. /**
  30. * Compression method for uncompressed entries.
  31. */
  32. public static final int STORED = 0;
  33. /**
  34. * Compression method for compressed (deflated) entries.
  35. */
  36. public static final int DEFLATED = 8;
  37. static {
  38. /* load the zip library */
  39. java.security.AccessController.doPrivileged(
  40. new sun.security.action.LoadLibraryAction("zip"));
  41. initIDs();
  42. }
  43. private static native void initIDs();
  44. /**
  45. * Creates a new zip entry with the specified name.
  46. *
  47. * @param name the entry name
  48. * @exception NullPointerException if the entry name is null
  49. * @exception IllegalArgumentException if the entry name is longer than
  50. * 0xFFFF bytes
  51. */
  52. public ZipEntry(String name) {
  53. if (name == null) {
  54. throw new NullPointerException();
  55. }
  56. if (name.length() > 0xFFFF) {
  57. throw new IllegalArgumentException("entry name too long");
  58. }
  59. this.name = name;
  60. }
  61. /**
  62. * Creates a new zip entry with fields taken from the specified
  63. * zip entry.
  64. * @param e a zip Entry object
  65. */
  66. public ZipEntry(ZipEntry e) {
  67. name = e.name;
  68. time = e.time;
  69. crc = e.crc;
  70. size = e.size;
  71. csize = e.csize;
  72. method = e.method;
  73. extra = e.extra;
  74. comment = e.comment;
  75. }
  76. /*
  77. * Creates a new zip entry for the given name with fields initialized
  78. * from the specified jzentry data.
  79. */
  80. ZipEntry(String name, long jzentry) {
  81. this.name = name;
  82. initFields(jzentry);
  83. }
  84. private native void initFields(long jzentry);
  85. /*
  86. * Creates a new zip entry with fields initialized from the specified
  87. * jzentry data.
  88. */
  89. ZipEntry(long jzentry) {
  90. initFields(jzentry);
  91. }
  92. /**
  93. * Returns the name of the entry.
  94. * @return the name of the entry
  95. */
  96. public String getName() {
  97. return name;
  98. }
  99. /**
  100. * Sets the modification time of the entry.
  101. * @param time the entry modification time in number of milliseconds
  102. * since the epoch
  103. * @see #getTime()
  104. */
  105. public void setTime(long time) {
  106. this.time = javaToDosTime(time);
  107. }
  108. /**
  109. * Returns the modification time of the entry, or -1 if not specified.
  110. * @return the modification time of the entry, or -1 if not specified
  111. * @see #setTime(long)
  112. */
  113. public long getTime() {
  114. return time != -1 ? dosToJavaTime(time) : -1;
  115. }
  116. /**
  117. * Sets the uncompressed size of the entry data.
  118. * @param size the uncompressed size in bytes
  119. * @exception IllegalArgumentException if the specified size is less
  120. * than 0 or greater than 0xFFFFFFFF bytes
  121. * @see #getSize()
  122. */
  123. public void setSize(long size) {
  124. if (size < 0 || size > 0xFFFFFFFFL) {
  125. throw new IllegalArgumentException("invalid entry size");
  126. }
  127. this.size = size;
  128. }
  129. /**
  130. * Returns the uncompressed size of the entry data, or -1 if not known.
  131. * @return the uncompressed size of the entry data, or -1 if not known
  132. * @see #setSize(long)
  133. */
  134. public long getSize() {
  135. return size;
  136. }
  137. /**
  138. * Returns the size of the compressed entry data, or -1 if not known.
  139. * In the case of a stored entry, the compressed size will be the same
  140. * as the uncompressed size of the entry.
  141. * @return the size of the compressed entry data, or -1 if not known
  142. * @see #setCompressedSize(long)
  143. */
  144. public long getCompressedSize() {
  145. return csize;
  146. }
  147. /**
  148. * Sets the size of the compressed entry data.
  149. * @param csize the compressed size to set to
  150. * @see #getCompressedSize()
  151. */
  152. public void setCompressedSize(long csize) {
  153. this.csize = csize;
  154. }
  155. /**
  156. * Sets the CRC-32 checksum of the uncompressed entry data.
  157. * @param crc the CRC-32 value
  158. * @exception IllegalArgumentException if the specified CRC-32 value is
  159. * less than 0 or greater than 0xFFFFFFFF
  160. * @see #setCrc(long)
  161. */
  162. public void setCrc(long crc) {
  163. if (crc < 0 || crc > 0xFFFFFFFFL) {
  164. throw new IllegalArgumentException("invalid entry crc-32");
  165. }
  166. this.crc = crc;
  167. }
  168. /**
  169. * Returns the CRC-32 checksum of the uncompressed entry data, or -1 if
  170. * not known.
  171. * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
  172. * not known
  173. * @see #getCrc()
  174. */
  175. public long getCrc() {
  176. return crc;
  177. }
  178. /**
  179. * Sets the compression method for the entry.
  180. * @param method the compression method, either STORED or DEFLATED
  181. * @exception IllegalArgumentException if the specified compression
  182. * method is invalid
  183. * @see #getMethod()
  184. */
  185. public void setMethod(int method) {
  186. if (method != STORED && method != DEFLATED) {
  187. throw new IllegalArgumentException("invalid compression method");
  188. }
  189. this.method = method;
  190. }
  191. /**
  192. * Returns the compression method of the entry, or -1 if not specified.
  193. * @return the compression method of the entry, or -1 if not specified
  194. * @see #setMethod(int)
  195. */
  196. public int getMethod() {
  197. return method;
  198. }
  199. /**
  200. * Sets the optional extra field data for the entry.
  201. * @param extra the extra field data bytes
  202. * @exception IllegalArgumentException if the length of the specified
  203. * extra field data is greater than 0xFFFF bytes
  204. * @see #getExtra()
  205. */
  206. public void setExtra(byte[] extra) {
  207. if (extra != null && extra.length > 0xFFFF) {
  208. throw new IllegalArgumentException("invalid extra field length");
  209. }
  210. this.extra = extra;
  211. }
  212. /**
  213. * Returns the extra field data for the entry, or null if none.
  214. * @return the extra field data for the entry, or null if none
  215. * @see #setExtra(byte[])
  216. */
  217. public byte[] getExtra() {
  218. return extra;
  219. }
  220. /**
  221. * Sets the optional comment string for the entry.
  222. * @param comment the comment string
  223. * @exception IllegalArgumentException if the length of the specified
  224. * comment string is greater than 0xFFFF bytes
  225. * @see #getComment()
  226. */
  227. public void setComment(String comment) {
  228. if (comment != null && comment.length() > 0xffff3
  229. && ZipOutputStream.getUTF8Length(comment) > 0xffff) {
  230. throw new IllegalArgumentException("invalid entry comment length");
  231. }
  232. this.comment = comment;
  233. }
  234. /**
  235. * Returns the comment string for the entry, or null if none.
  236. * @return the comment string for the entry, or null if none
  237. * @see #setComment(String)
  238. */
  239. public String getComment() {
  240. return comment;
  241. }
  242. /**
  243. * Returns true if this is a directory entry. A directory entry is
  244. * defined to be one whose name ends with a '/'.
  245. * @return true if this is a directory entry
  246. */
  247. public boolean isDirectory() {
  248. return name.endsWith("/");
  249. }
  250. /**
  251. * Returns a string representation of the ZIP entry.
  252. */
  253. public String toString() {
  254. return getName();
  255. }
  256. /*
  257. * Converts DOS time to Java time (number of milliseconds since epoch).
  258. */
  259. private static long dosToJavaTime(long dtime) {
  260. Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
  261. (int)(((dtime >> 21) & 0x0f) - 1),
  262. (int)((dtime >> 16) & 0x1f),
  263. (int)((dtime >> 11) & 0x1f),
  264. (int)((dtime >> 5) & 0x3f),
  265. (int)((dtime << 1) & 0x3e));
  266. return d.getTime();
  267. }
  268. /*
  269. * Converts Java time to DOS time.
  270. */
  271. private static long javaToDosTime(long time) {
  272. Date d = new Date(time);
  273. int year = d.getYear() + 1900;
  274. if (year < 1980) {
  275. return (1 << 21) | (1 << 16);
  276. }
  277. return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
  278. d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
  279. d.getSeconds() >> 1;
  280. }
  281. /**
  282. * Returns the hash code value for this entry.
  283. */
  284. public int hashCode() {
  285. return name.hashCode();
  286. }
  287. /**
  288. * Returns a copy of this entry.
  289. */
  290. public Object clone() {
  291. try {
  292. ZipEntry e = (ZipEntry)super.clone();
  293. e.extra = (extra == null ? null : (byte[])extra.clone());
  294. return e;
  295. } catch (CloneNotSupportedException e) {
  296. // This should never happen, since we are Cloneable
  297. throw new InternalError();
  298. }
  299. }
  300. }