Source for file PelDataWindow.php

Documentation is available at PelDataWindow.php

  1. <?php
  2.  
  3. /* PEL: PHP EXIF Library. A library with support for reading and
  4. * writing all EXIF headers in JPEG and TIFF images using PHP.
  5. *
  6. * Copyright (C) 2004 Martin Geisler <gimpster@users.sourceforge.net>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program in the file COPYING; if not, write to the
  20. * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  21. * Boston, MA 02111-1307 USA
  22. */
  23.  
  24. /* PelDataWindow.php,v 1.14 2004/06/27 20:52:06 gimpster Exp */
  25.  
  26.  
  27. /**
  28. * A container for bytes with a limited window of accessible bytes.
  29. *
  30. * @author Martin Geisler <gimpster@users.sourceforge.net>
  31. * @version 1.14
  32. * @date 2004/06/27 20:52:06
  33. * @license http://www.gnu.org/licenses/gpl.html GNU General Public License (GPL)
  34. * @package PEL
  35. */
  36.  
  37. /**#@+ Required class definitions. */
  38. ('PelException.php');
  39. require_once('PelConvert.php');
  40. /**#@-*/ * An exception thrown when an invalid offset is encountered.
  41. *
  42. * @package PEL
  43. * @subpackage Exception
  44. */
  45. class PelDataWindowOffsetException extends PelException {}
  46.  
  47. /**
  48. * An exception thrown when an invalid window is encountered.
  49. *
  50. * @package PEL
  51. * @subpackage Exception
  52. */
  53. class PelDataWindowWindowException extends PelException {}
  54.  
  55. /**
  56. * The window.
  57. *
  58. * @package PEL
  59. */
  60. class PelDataWindow {
  61.  
  62. /**
  63. * The data held by this window.
  64. *
  65. * The string can contain any kind of data, including binary data.
  66. *
  67. * @var string
  68. */
  69. private $data = '';
  70.  
  71. /**
  72. * The byte order currently in use.
  73. *
  74. * This will be the byte order used when data is read using the for
  75. * example the {@link getShort} function. It must be one of {@link }
  76. * PelConvert::LITTLE_ENDIAN} and {@link PelConvert::BIG_ENDIAN}.
  77. *
  78. * @var PelByteOrder
  79. * @see setByteOrder, getByteOrder
  80. */
  81. private $order;
  82.  
  83. /**
  84. * The start of the current window.
  85. *
  86. * All offsets used for access into the data will count from this
  87. * offset, effectively limiting access to a window starting at this
  88. * byte.
  89. *
  90. * @var int
  91. * @see setWindowStart
  92. */
  93. private $start = 0;
  94.  
  95. /**
  96. * The size of the current window.
  97. *
  98. * All offsets used for access into the data will be limited by this
  99. * variable. A valid offset must be strictly less than this
  100. * variable.
  101. *
  102. * @var int
  103. * @see setWindowSize
  104. */
  105. private $size = 0;
  106.  
  107.  
  108. /**
  109. * Construct a new data window with the data supplied.
  110. *
  111. * @param string the data that this window will contain. The data
  112. * will be copied into the new data window.
  113. *
  114. * @param boolean the initial byte order of the window. This must
  115. * be either {@link PelConvert::LITTLE_ENDIAN} or {@link }
  116. * PelConvert::BIG_ENDIAN}. This will be used when integers are
  117. * read from the data, and it can be changed later with {@link }
  118. * setByteOrder()}.
  119. */
  120. function __construct($d = '', $e = PelConvert::LITTLE_ENDIAN) {
  121. $this->data = $d;
  122. $this->order = $e;
  123. $this->size = strlen($d);
  124. }
  125.  
  126.  
  127. /**
  128. * Get the size of the data window.
  129. *
  130. * @return int the number of bytes covered by the window. The
  131. * allowed offsets go from 0 up to this number minus one.
  132. *
  133. * @see getBytes()
  134. */
  135. function getSize() {
  136. return $this->size;
  137. }
  138.  
  139.  
  140. /**
  141. * Change the byte order of the data.
  142. *
  143. * @param PelByteOrder the new byte order. This must be either
  144. * {@link Convert::LITTLE_ENDIAN} or {@link Convert::BIG_ENDIAN}.
  145. */
  146. function setByteOrder($o) {
  147. $this->order = $o;
  148. }
  149.  
  150.  
  151. /**
  152. * Get the currently used byte order.
  153. *
  154. * @return PelByteOrder this will be either {@link }
  155. * Convert::LITTLE_ENDIAN} or {@link Convert::BIG_ENDIAN}.
  156. */
  157. function getByteOrder() {
  158. return $this->order;
  159. }
  160.  
  161.  
  162. /* Move the start of the window forward.
  163. *
  164. * @param int the new start of the window. All new offsets will be
  165. * calculated from this new start offset, and the size of the window
  166. * will shrink to keep the end of the window in place.
  167. */
  168. function setWindowStart($start) {
  169. if ($start < 0 || $start > $this->size)
  170. throw new PelDataWindowWindowException('Window [%d, %d] does ' .
  171. 'not fit in window [0, %d]',
  172. $start, $this->size, $this->size);
  173.  
  174. $this->start += $start;
  175. $this->size -= $start;
  176. }
  177.  
  178.  
  179. /**
  180. * Adjust the size of the window.
  181. *
  182. * The size can only be made smaller.
  183. *
  184. * @param int the desired size of the window. If the argument is
  185. * negative, the window will be shrunk by the argument.
  186. */
  187. function setWindowSize($size) {
  188. if ($size < 0)
  189. $size += $this->size;
  190.  
  191. if ($size < 0 || $size > $this->size)
  192. throw new PelDataWindowWindowException('Window [0, %d] ' .
  193. 'does not fit in window [0, %d]',
  194. $size, $this->size);
  195. $this->size = $size;
  196. }
  197.  
  198. /**
  199. * Initialize a copy with data.
  200. *
  201. * This is used internally by {@link getClone} to make return a copy
  202. * with the proper initialization.
  203. *
  204. * @param string a reference to the data this copy will hold.
  205. * @param int the start of the data window.
  206. * @param int the size of the data window.
  207. * @param PelByteOrder the byte order of the data.
  208. *
  209. * @see getClone
  210. */
  211. protected function initializeClone(&$data, $start, $size, $order) {
  212. $this->data = &$data;
  213. $this->start = $start;
  214. $this->size = $size;
  215. $this->order = $order;
  216. }
  217.  
  218.  
  219. /**
  220. * Make a new data window with the same data as the this window.
  221. *
  222. * The new window will read from the same data as this window, so
  223. * calling this method is significantly faster than using the
  224. * built-in clone functionality of PHP.
  225. *
  226. * @param mixed if an integer is supplied, then it will be the start
  227. * of the window in the clone. If left unspecified, then the clone
  228. * will inherit the start from this object.
  229. *
  230. * @param mixed if an integer is supplied, then it will be the size
  231. * of the window in the clone. If left unspecified, then the clone
  232. * will inherit the size from this object.
  233. *
  234. * @return PelDataWindow a new window that operates on the same data
  235. * as this window, but (optionally) with a smaller size.
  236. */
  237. function getClone($start = false, $size = false) {
  238. $c = new PelDataWindow();
  239. $c->initializeClone($this->data, $this->start, $this->size, $this->order);
  240. if (is_int($start))
  241. $c->setWindowStart($start);
  242.  
  243. if (is_int($size))
  244. $c->setWindowSize($size);
  245.  
  246. return $c;
  247. }
  248.  
  249.  
  250. /**
  251. * Validate an offset against the current window.
  252. *
  253. * @param int the offset to be validated. If the offset is negative
  254. * or if it is greater than or equal to the current window size,
  255. * then a {@link PelDataWindowOffsetException} is thrown.
  256. *
  257. * @return void if the offset is valid nothing is returned, if it's
  258. * invalid a new {@link PelDataWindowOffsetException} is thrown.
  259. */
  260. private function validateOffset($o) {
  261. if ($o < 0 || $o >= $this->size)
  262. throw new PelDataWindowOffsetException('Offset %d not within [%d, %d]',
  263. $o, 0, $this->size-1);
  264. }
  265.  
  266.  
  267. /**
  268. * Return some or all bytes visible in the window.
  269. *
  270. * This method works just like the standard {@link substr()}
  271. * function in PHP with the exception that it works within the
  272. * window of accessible bytes and does strict range checking.
  273. *
  274. * @param int the offset to the first byte returned. If a negative
  275. * number is given, then the counting will be from the end of the
  276. * window. Invalid offsets will result in a {@link }
  277. * PelDataWindowOffsetException} being thrown.
  278. *
  279. * @param int the size of the sub-window. If a negative number is
  280. * given, then that many bytes will be omitted from the result.
  281. *
  282. * @return string a subset of the bytes in the window. This will
  283. * always return no more than {@link getSize()} bytes.
  284. */
  285. function getBytes($start = false, $size = false) {
  286. if (is_int($start)) {
  287. if ($start < 0)
  288. $start += $this->size;
  289. $this->validateOffset($start);
  290. } else {
  291. $start = 0;
  292. }
  293. if (is_int($size)) {
  294. if ($size <= 0)
  295. $size += $this->size - $start;
  296. $this->validateOffset($start+$size);
  297. } else {
  298. $size = $this->size - $start;
  299. }
  300.  
  301. return substr($this->data, $this->start + $start, $size);
  302. }
  303.  
  304.  
  305. /**
  306. * Return an unsigned byte from the data.
  307. *
  308. * @param int the offset into the data. An offset of zero will
  309. * return the first byte in the current allowed window. The last
  310. * valid offset is equal to {@link getSize()}-1. Invalid offsets
  311. * will result in a {@link PelDataWindowOffsetException} being
  312. * thrown.
  313. *
  314. * @return int the unsigned byte found at offset.
  315. */
  316. function getByte($o = 0) {
  317. /* Validate the offset --- this throws an exception if offset is
  318. * out of range. */
  319. $this->validateOffset($o);
  320.  
  321. /* Translate the offset into an offset into the data. */
  322. $o += $this->start;
  323. /* Return an unsigned byte. */
  324. return PelConvert::bytesToByte($this->data, $o);
  325. }
  326.  
  327.  
  328. /**
  329. * Return a signed byte from the data.
  330. *
  331. * @param int the offset into the data. An offset of zero will
  332. * return the first byte in the current allowed window. The last
  333. * valid offset is equal to {@link getSize()}-1. Invalid offsets
  334. * will result in a {@link PelDataWindowOffsetException} being
  335. * thrown.
  336. *
  337. * @return int the signed byte found at offset.
  338. */
  339. function getSByte($o = 0) {
  340. /* Validate the offset --- this throws an exception if offset is
  341. * out of range. */
  342. $this->validateOffset($o);
  343.  
  344. /* Translate the offset into an offset into the data. */
  345. $o += $this->start;
  346. /* Return a signed byte. */
  347. return PelConvert::bytesToSByte($this->data, $o);
  348. }
  349.  
  350.  
  351. /**
  352. * Return an unsigned short read from the data.
  353. *
  354. * @param int the offset into the data. An offset of zero will
  355. * return the first short available in the current allowed window.
  356. * The last valid offset is equal to {@link getSize()}-2. Invalid
  357. * offsets will result in a {@link PelDataWindowOffsetException}
  358. * being thrown.
  359. *
  360. * @return int the unsigned short found at offset.
  361. */
  362. function getShort($o = 0) {
  363. /* Validate the offset+1 to see if we can safely get two bytes ---
  364. * this throws an exception if offset is out of range. */
  365. $this->validateOffset($o);
  366. $this->validateOffset($o+1);
  367.  
  368. /* Translate the offset into an offset into the data. */
  369. $o += $this->start;
  370.  
  371. /* Return an unsigned short. */
  372. return PelConvert::bytesToShort($this->data, $o, $this->order);
  373. }
  374.  
  375.  
  376. /**
  377. * Return a signed short read from the data.
  378. *
  379. * @param int the offset into the data. An offset of zero will
  380. * return the first short available in the current allowed window.
  381. * The last valid offset is equal to {@link getSize()}-2. Invalid
  382. * offsets will result in a {@link PelDataWindowOffsetException}
  383. * being thrown.
  384. *
  385. * @return int the signed short found at offset.
  386. */
  387. function getSShort($o = 0) {
  388. /* Validate the offset+1 to see if we can safely get two bytes ---
  389. * this throws an exception if offset is out of range. */
  390. $this->validateOffset($o);
  391. $this->validateOffset($o+1);
  392.  
  393. /* Translate the offset into an offset into the data. */
  394. $o += $this->start;
  395.  
  396. /* Return a signed short. */
  397. return PelConvert::bytesToSShort($this->data, $o, $this->order);
  398. }
  399.  
  400.  
  401. /**
  402. * Return an unsigned long read from the data.
  403. *
  404. * @param int the offset into the data. An offset of zero will
  405. * return the first long available in the current allowed window.
  406. * The last valid offset is equal to {@link getSize()}-4. Invalid
  407. * offsets will result in a {@link PelDataWindowOffsetException}
  408. * being thrown.
  409. *
  410. * @return int the unsigned long found at offset.
  411. */
  412. function getLong($o = 0) {
  413. /* Validate the offset+3 to see if we can safely get four bytes
  414. * --- this throws an exception if offset is out of range. */
  415. $this->validateOffset($o);
  416. $this->validateOffset($o+3);
  417. /* Translate the offset into an offset into the data. */
  418. $o += $this->start;
  419.  
  420. /* Return an unsigned long. */
  421. return PelConvert::bytesToLong($this->data, $o, $this->order);
  422. }
  423.  
  424.  
  425. /**
  426. * Return a signed long read from the data.
  427. *
  428. * @param int the offset into the data. An offset of zero will
  429. * return the first long available in the current allowed window.
  430. * The last valid offset is equal to {@link getSize()}-4. Invalid
  431. * offsets will result in a {@link PelDataWindowOffsetException}
  432. * being thrown.
  433. *
  434. * @return int the signed long found at offset.
  435. */
  436. function getSLong($o = 0) {
  437. /* Validate the offset+3 to see if we can safely get four bytes
  438. * --- this throws an exception if offset is out of range. */
  439. $this->validateOffset($o);
  440. $this->validateOffset($o+3);
  441. /* Translate the offset into an offset into the data. */
  442. $o += $this->start;
  443.  
  444. /* Return a signed long. */
  445. return PelConvert::bytesToSLong($this->data, $o, $this->order);
  446. }
  447.  
  448.  
  449. /**
  450. * Return an unsigned rational read from the data.
  451. *
  452. * @param int the offset into the data. An offset of zero will
  453. * return the first rational available in the current allowed
  454. * window. The last valid offset is equal to {@link getSize()}-8.
  455. * Invalid offsets will result in a {@link }
  456. * PelDataWindowOffsetException} being thrown.
  457. *
  458. * @return array the unsigned rational found at offset. A rational
  459. * number is represented as an array of two numbers: the enumerator
  460. * and denominator. Both of these numbers will be unsigned longs.
  461. */
  462. function getRational($o = 0) {
  463. return array($this->getLong($o), $this->getLong($o+4));
  464. }
  465.  
  466.  
  467. /**
  468. * Return a signed rational read from the data.
  469. *
  470. * @param int the offset into the data. An offset of zero will
  471. * return the first rational available in the current allowed
  472. * window. The last valid offset is equal to {@link getSize()}-8.
  473. * Invalid offsets will result in a {@link }
  474. * PelDataWindowOffsetException} being thrown.
  475. *
  476. * @return array the signed rational found at offset. A rational
  477. * number is represented as an array of two numbers: the enumerator
  478. * and denominator. Both of these numbers will be signed longs.
  479. */
  480. function getSRational($o = 0) {
  481. return array($this->getSLong($o), $this->getSLong($o+4));
  482. }
  483.  
  484.  
  485. /**
  486. * String comparison on substrings.
  487. *
  488. * @param int the offset into the data. An offset of zero will make
  489. * the comparison start with the very first byte available in the
  490. * window. The last valid offset is equal to {@link getSize()}
  491. * minus the length of the string. If the string is too long, then
  492. * a {@link PelDataWindowOffsetException} will be thrown.
  493. *
  494. * @param string the string to compare with.
  495. *
  496. * @return boolean true if the string given matches the data in the
  497. * window, at the specified offset, false otherwise. The comparison
  498. * will stop as soon as a mismatch if found.
  499. */
  500. function strcmp($o, $str) {
  501. /* Validate the offset of the final character we might have to
  502. * check. */
  503. $s = strlen($str);
  504. $this->validateOffset($o);
  505. $this->validateOffset($o + $s - 1);
  506.  
  507. /* Translate the offset into an offset into the data. */
  508. $o += $this->start;
  509. /* Check each character, return as soon as the answer is known. */
  510. for ($i = 0; $i < $s; $i++) {
  511. if ($this->data{$o + $i} != $str{$i})
  512. return false;
  513. }
  514.  
  515. /* All characters matches each other, return true. */
  516. return true;
  517. }
  518.  
  519.  
  520. /**
  521. * Return a string representation of the data window.
  522. *
  523. * @return string a description of the window with information about
  524. * the number of bytes accessible, the total number of bytes, and
  525. * the window start and stop.
  526. */
  527. function __toString() {
  528. return Pel::fmt('DataWindow: %d bytes in [%d, %d] of %d bytes',
  529. $this->size,
  530. $this->start, $this->start + $this->size,
  531. strlen($this->data));
  532. }
  533.  
  534.  
  535. /**
  536. * Clear the data.
  537. *
  538. * This method is for debugging only. It removed the data held by
  539. * this data window, thereby removing access to it for all clones
  540. * too. This is useful when a data window object is to be printed
  541. * with print_r() or a similar function, and the binary output would
  542. * mess up the terminal or browser.
  543. */
  544. function clear() {
  545. $this->data = '(cleared)';
  546. }
  547.  
  548. }
  549.  
  550. ?>

SourceForge.net Logo Documentation generated on Wed, 21 Jul 2004 19:12:57 +0200 by phpDocumentor 1.3.0RC3