ExtraFieldsCollection.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <?php
  2. namespace PhpZip\Extra;
  3. use PhpZip\Exception\InvalidArgumentException;
  4. use PhpZip\Exception\ZipException;
  5. /**
  6. * Represents a collection of Extra Fields as they may
  7. * be present at several locations in ZIP files.
  8. *
  9. * @author Ne-Lexa alexey@nelexa.ru
  10. * @license MIT
  11. */
  12. class ExtraFieldsCollection implements \Countable, \ArrayAccess, \Iterator
  13. {
  14. /**
  15. * The map of Extra Fields.
  16. * Maps from Header ID to Extra Field.
  17. * Must not be null, but may be empty if no Extra Fields are used.
  18. * The map is sorted by Header IDs in ascending order.
  19. *
  20. * @var ExtraField[]
  21. */
  22. protected $collection = [];
  23. /**
  24. * Returns the number of Extra Fields in this collection.
  25. *
  26. * @return int
  27. */
  28. public function count()
  29. {
  30. return sizeof($this->collection);
  31. }
  32. /**
  33. * Returns the Extra Field with the given Header ID or null
  34. * if no such Extra Field exists.
  35. *
  36. * @param int $headerId The requested Header ID.
  37. * @return ExtraField The Extra Field with the given Header ID or
  38. * if no such Extra Field exists.
  39. * @throws ZipException If headerId is out of range.
  40. */
  41. public function get($headerId)
  42. {
  43. if (0x0000 > $headerId || $headerId > 0xffff) {
  44. throw new ZipException('headerId out of range');
  45. }
  46. if (isset($this->collection[$headerId])) {
  47. return $this->collection[$headerId];
  48. }
  49. return null;
  50. }
  51. /**
  52. * Stores the given Extra Field in this collection.
  53. *
  54. * @param ExtraField $extraField The Extra Field to store in this collection.
  55. * @return ExtraField The Extra Field previously associated with the Header ID of
  56. * of the given Extra Field or null if no such Extra Field existed.
  57. * @throws ZipException If headerId is out of range.
  58. */
  59. public function add(ExtraField $extraField)
  60. {
  61. $headerId = $extraField::getHeaderId();
  62. if (0x0000 > $headerId || $headerId > 0xffff) {
  63. throw new ZipException('headerId out of range');
  64. }
  65. $this->collection[$headerId] = $extraField;
  66. return $extraField;
  67. }
  68. /**
  69. * Returns Extra Field exists
  70. *
  71. * @param int $headerId The requested Header ID.
  72. * @return bool
  73. */
  74. public function has($headerId)
  75. {
  76. return isset($this->collection[$headerId]);
  77. }
  78. /**
  79. * Removes the Extra Field with the given Header ID.
  80. *
  81. * @param int $headerId The requested Header ID.
  82. * @return ExtraField The Extra Field with the given Header ID or null
  83. * if no such Extra Field exists.
  84. * @throws ZipException If headerId is out of range or extra field not found.
  85. */
  86. public function remove($headerId)
  87. {
  88. if (0x0000 > $headerId || $headerId > 0xffff) {
  89. throw new ZipException('headerId out of range');
  90. }
  91. if (isset($this->collection[$headerId])) {
  92. $ef = $this->collection[$headerId];
  93. unset($this->collection[$headerId]);
  94. return $ef;
  95. }
  96. throw new ZipException('ExtraField not found');
  97. }
  98. /**
  99. * Whether a offset exists
  100. * @link http://php.net/manual/en/arrayaccess.offsetexists.php
  101. * @param mixed $offset <p>
  102. * An offset to check for.
  103. * </p>
  104. * @return boolean true on success or false on failure.
  105. * </p>
  106. * <p>
  107. * The return value will be casted to boolean if non-boolean was returned.
  108. * @since 5.0.0
  109. */
  110. public function offsetExists($offset)
  111. {
  112. return isset($this->collection[$offset]);
  113. }
  114. /**
  115. * Offset to retrieve
  116. * @link http://php.net/manual/en/arrayaccess.offsetget.php
  117. * @param mixed $offset <p>
  118. * The offset to retrieve.
  119. * </p>
  120. * @return mixed Can return all value types.
  121. * @since 5.0.0
  122. */
  123. public function offsetGet($offset)
  124. {
  125. return $this->get($offset);
  126. }
  127. /**
  128. * Offset to set
  129. * @link http://php.net/manual/en/arrayaccess.offsetset.php
  130. * @param mixed $offset <p>
  131. * The offset to assign the value to.
  132. * </p>
  133. * @param mixed $value <p>
  134. * The value to set.
  135. * </p>
  136. * @return void
  137. * @throws InvalidArgumentException
  138. * @since 5.0.0
  139. */
  140. public function offsetSet($offset, $value)
  141. {
  142. if ($value instanceof ExtraField) {
  143. assert($offset == $value::getHeaderId());
  144. $this->add($value);
  145. } else {
  146. throw new InvalidArgumentException('value is not instanceof ' . ExtraField::class);
  147. }
  148. }
  149. /**
  150. * Offset to unset
  151. * @link http://php.net/manual/en/arrayaccess.offsetunset.php
  152. * @param mixed $offset <p>
  153. * The offset to unset.
  154. * </p>
  155. * @return void
  156. * @since 5.0.0
  157. */
  158. public function offsetUnset($offset)
  159. {
  160. $this->remove($offset);
  161. }
  162. /**
  163. * Return the current element
  164. * @link http://php.net/manual/en/iterator.current.php
  165. * @return mixed Can return any type.
  166. * @since 5.0.0
  167. */
  168. public function current()
  169. {
  170. return current($this->collection);
  171. }
  172. /**
  173. * Move forward to next element
  174. * @link http://php.net/manual/en/iterator.next.php
  175. * @return void Any returned value is ignored.
  176. * @since 5.0.0
  177. */
  178. public function next()
  179. {
  180. next($this->collection);
  181. }
  182. /**
  183. * Return the key of the current element
  184. * @link http://php.net/manual/en/iterator.key.php
  185. * @return mixed scalar on success, or null on failure.
  186. * @since 5.0.0
  187. */
  188. public function key()
  189. {
  190. return key($this->collection);
  191. }
  192. /**
  193. * Checks if current position is valid
  194. * @link http://php.net/manual/en/iterator.valid.php
  195. * @return boolean The return value will be casted to boolean and then evaluated.
  196. * Returns true on success or false on failure.
  197. * @since 5.0.0
  198. */
  199. public function valid()
  200. {
  201. return $this->offsetExists($this->key());
  202. }
  203. /**
  204. * Rewind the Iterator to the first element
  205. * @link http://php.net/manual/en/iterator.rewind.php
  206. * @return void Any returned value is ignored.
  207. * @since 5.0.0
  208. */
  209. public function rewind()
  210. {
  211. reset($this->collection);
  212. }
  213. /**
  214. * If clone extra fields.
  215. */
  216. public function __clone()
  217. {
  218. foreach ($this->collection as $k => $v) {
  219. $this->collection[$k] = clone $v;
  220. }
  221. }
  222. }