474c48a61273c69e3701cbe1f8536e2f0cc9c3a5
[yaffs-website] / lsolesen / pel / src / PelConvert.php
1 <?php
2
3 /**
4  * PEL: PHP Exif Library.
5  * A library with support for reading and
6  * writing all Exif headers in JPEG and TIFF images using PHP.
7  *
8  * Copyright (C) 2004, 2005 Martin Geisler.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program in the file COPYING; if not, write to the
22  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23  * Boston, MA 02110-1301 USA
24  */
25 namespace lsolesen\pel;
26
27 /**
28  * Routines for converting back and forth between bytes and integers.
29  *
30  * @author Martin Geisler <mgeisler@users.sourceforge.net>
31  * @license http://www.gnu.org/licenses/gpl.html GNU General Public
32  *          License (GPL)
33  * @package PEL
34  */
35
36 /**
37  * Conversion functions to and from bytes and integers.
38  *
39  * The functions found in this class are used to convert bytes into
40  * integers of several sizes ({@link bytesToShort}, {@link
41  * bytesToLong}, and {@link bytesToRational}) and convert integers of
42  * several sizes into bytes ({@link shortToBytes} and {@link
43  * longToBytes}).
44  *
45  * All the methods are static and they all rely on an argument that
46  * specifies the byte order to be used, this must be one of the class
47  * constants {@link LITTLE_ENDIAN} or {@link BIG_ENDIAN}. These
48  * constants will be referred to as the pseudo type PelByteOrder
49  * throughout the documentation.
50  *
51  * @author Martin Geisler <mgeisler@users.sourceforge.net>
52  * @package PEL
53  */
54 class PelConvert
55 {
56
57     /**
58      * Little-endian (Intel) byte order.
59      *
60      * Data stored in little-endian byte order store the least
61      * significant byte first, so the number 0x12345678 becomes 0x78
62      * 0x56 0x34 0x12 when stored with little-endian byte order.
63      */
64     const LITTLE_ENDIAN = true;
65
66     /**
67      * Big-endian (Motorola) byte order.
68      *
69      * Data stored in big-endian byte order store the most significant
70      * byte first, so the number 0x12345678 becomes 0x12 0x34 0x56 0x78
71      * when stored with big-endian byte order.
72      */
73     const BIG_ENDIAN = false;
74
75     /**
76      * Convert an unsigned short into two bytes.
77      *
78      * @param integer $value
79      *            the unsigned short that will be converted. The lower
80      *            two bytes will be extracted regardless of the actual size passed.
81      *
82      * @param integer $endian
83      *            one of {@link LITTLE_ENDIAN} and {@link
84      *            BIG_ENDIAN}.
85      *
86      * @return string the bytes representing the unsigned short.
87      */
88     public static function shortToBytes($value, $endian)
89     {
90         if ($endian == self::LITTLE_ENDIAN) {
91             return chr($value) . chr($value >> 8);
92         } else {
93             return chr($value >> 8) . chr($value);
94         }
95     }
96
97     /**
98      * Convert a signed short into two bytes.
99      *
100      * @param integer $value
101      *            the signed short that will be converted. The lower
102      *            two bytes will be extracted regardless of the actual size passed.
103      *
104      * @param integer $endian
105      *            one of {@link LITTLE_ENDIAN} and {@link
106      *            BIG_ENDIAN}.
107      *
108      * @return string the bytes representing the signed short.
109      */
110     public static function sShortToBytes($value, $endian)
111     {
112         /*
113          * We can just use shortToBytes, since signed shorts fits well
114          * within the 32 bit signed integers used in PHP.
115          */
116         return self::shortToBytes($value, $endian);
117     }
118
119     /**
120      * Convert an unsigned long into four bytes.
121      *
122      * Because PHP limits the size of integers to 32 bit signed, one
123      * cannot really have an unsigned integer in PHP. But integers
124      * larger than 2^31-1 will be promoted to 64 bit signed floating
125      * point numbers, and so such large numbers can be handled too.
126      *
127      * @param integer $value
128      *            the unsigned long that will be converted. The
129      *            argument will be treated as an unsigned 32 bit integer and the
130      *            lower four bytes will be extracted. Treating the argument as an
131      *            unsigned integer means that the absolute value will be used. Use
132      *            {@link sLongToBytes} to convert signed integers.
133      *
134      * @param integer $endian
135      *            one of {@link LITTLE_ENDIAN} and {@link
136      *            BIG_ENDIAN}.
137      *
138      * @return string the bytes representing the unsigned long.
139      */
140     public static function longToBytes($value, $endian)
141     {
142         /*
143          * We cannot convert the number to bytes in the normal way (using
144          * shifts and modulo calculations) because the PHP operator >> and
145          * function chr() clip their arguments to 2^31-1, which is the
146          * largest signed integer known to PHP. But luckily base_convert
147          * handles such big numbers.
148          */
149         $hex = str_pad(base_convert($value, 10, 16), 8, '0', STR_PAD_LEFT);
150         if ($endian == self::LITTLE_ENDIAN) {
151             return (chr(hexdec($hex{6} . $hex{7})) . chr(hexdec($hex{4} . $hex{5})) . chr(hexdec($hex{2} . $hex{3})) .
152                  chr(hexdec($hex{0} . $hex{1})));
153         } else {
154             return (chr(hexdec($hex{0} . $hex{1})) . chr(hexdec($hex{2} . $hex{3})) . chr(hexdec($hex{4} . $hex{5})) .
155                  chr(hexdec($hex{6} . $hex{7})));
156         }
157     }
158
159     /**
160      * Convert a signed long into four bytes.
161      *
162      * @param integer $value
163      *            the signed long that will be converted. The argument
164      *            will be treated as a signed 32 bit integer, from which the lower
165      *            four bytes will be extracted.
166      *
167      * @param integer $endian
168      *            one of {@link LITTLE_ENDIAN} and {@link
169      *            BIG_ENDIAN}.
170      *
171      * @return string the bytes representing the signed long.
172      */
173     public static function sLongToBytes($value, $endian)
174     {
175         /*
176          * We can convert the number into bytes in the normal way using
177          * shifts and modulo calculations here (in contrast with
178          * longToBytes) because PHP automatically handles 32 bit signed
179          * integers for us.
180          */
181         if ($endian == self::LITTLE_ENDIAN) {
182             return (chr($value) . chr($value >> 8) . chr($value >> 16) . chr($value >> 24));
183         } else {
184             return (chr($value >> 24) . chr($value >> 16) . chr($value >> 8) . chr($value));
185         }
186     }
187
188     /**
189      * Extract an unsigned byte from a string of bytes.
190      *
191      * @param string $bytes
192      *            the bytes.
193      *
194      * @param integer $offset
195      *            The byte found at the offset will be
196      *            returned as an integer. The must be at least one byte available
197      *            at offset.
198      *
199      * @return integer $offset the unsigned byte found at offset, e.g., an integer
200      *         in the range 0 to 255.
201      */
202     public static function bytesToByte($bytes, $offset)
203     {
204         return ord($bytes{$offset});
205     }
206
207     /**
208      * Extract a signed byte from bytes.
209      *
210      * @param string $bytes
211      *            the bytes.
212      *
213      * @param integer $offset
214      *            the offset. The byte found at the offset will be
215      *            returned as an integer. The must be at least one byte available
216      *            at offset.
217      *
218      * @return integer the signed byte found at offset, e.g., an integer in
219      *         the range -128 to 127.
220      */
221     public static function bytesToSByte($bytes, $offset)
222     {
223         $n = self::bytesToByte($bytes, $offset);
224         if ($n > 127) {
225             return $n - 256;
226         } else {
227             return $n;
228         }
229     }
230
231     /**
232      * Extract an unsigned short from bytes.
233      *
234      * @param string $bytes
235      *            the bytes.
236      *
237      * @param integer $offset
238      *            the offset. The short found at the offset will be
239      *            returned as an integer. There must be at least two bytes
240      *            available beginning at the offset given.
241      * @param integer $endian
242      *            one of {@link LITTLE_ENDIAN} and {@link
243      *            BIG_ENDIAN}.
244      * @return integer the unsigned short found at offset, e.g., an integer
245      *         in the range 0 to 65535.
246      *
247      */
248     public static function bytesToShort($bytes, $offset, $endian)
249     {
250         if ($endian == self::LITTLE_ENDIAN) {
251             return (ord($bytes{$offset + 1}) * 256 + ord($bytes{$offset}));
252         } else {
253             return (ord($bytes{$offset}) * 256 + ord($bytes{$offset + 1}));
254         }
255     }
256
257     /**
258      * Extract a signed short from bytes.
259      *
260      * @param string $bytes
261      *
262      * @param integer $offset
263      *            The short found at offset will be returned
264      *            as an integer. There must be at least two bytes available
265      *            beginning at the offset given.
266      * @param integer $endian
267      *            one of {@link LITTLE_ENDIAN} and {@link
268      *            BIG_ENDIAN}.
269      * @return integer the signed byte found at offset, e.g., an integer in
270      *         the range -32768 to 32767.
271      *
272      */
273     public static function bytesToSShort($bytes, $offset, $endian)
274     {
275         $n = self::bytesToShort($bytes, $offset, $endian);
276         if ($n > 32767) {
277             return $n - 65536;
278         } else {
279             return $n;
280         }
281     }
282
283     /**
284      * Extract an unsigned long from bytes.
285      *
286      * @param string $bytes
287      *
288      * @param integer $offset
289      *            The long found at offset will be returned
290      *            as an integer. There must be at least four bytes available
291      *            beginning at the offset given.
292      * @param integer $endian
293      *            one of {@link LITTLE_ENDIAN} and {@link
294      *            BIG_ENDIAN}.
295      * @return integer the unsigned long found at offset, e.g., an integer
296      *         in the range 0 to 4294967295.
297      *
298      */
299     public static function bytesToLong($bytes, $offset, $endian)
300     {
301         if ($endian == self::LITTLE_ENDIAN) {
302             return (ord($bytes{$offset + 3}) * 16777216 + ord($bytes{$offset + 2}) * 65536 +
303                  ord($bytes{$offset + 1}) * 256 + ord($bytes{$offset}));
304         } else {
305             return (ord($bytes{$offset}) * 16777216 + ord($bytes{$offset + 1}) * 65536 + ord($bytes{$offset + 2}) * 256 +
306                  ord($bytes{$offset + 3}));
307         }
308     }
309
310     /**
311      * Extract a signed long from bytes.
312      *
313      * @param string $bytes
314      *
315      * @param integer $offset
316      *            The long found at offset will be returned
317      *            as an integer. There must be at least four bytes available
318      *            beginning at the offset given.
319      * @param integer $endian
320      *            one of {@link LITTLE_ENDIAN} and {@link
321      *            BIG_ENDIAN}. *
322      * @return integer the signed long found at offset, e.g., an integer in
323      *         the range -2147483648 to 2147483647.
324      *
325      */
326     public static function bytesToSLong($bytes, $offset, $endian)
327     {
328         $n = self::bytesToLong($bytes, $offset, $endian);
329         if ($n > 2147483647) {
330             return $n - 4294967296;
331         } else {
332             return $n;
333         }
334     }
335
336     /**
337      * Extract an unsigned rational from bytes.
338      *
339      * @param string $bytes
340      *
341      * @param integer $offset
342      *            The rational found at offset will be
343      *            returned as an array. There must be at least eight bytes
344      *            available beginning at the offset given.
345      * @param integer $endian
346      *            one of {@link LITTLE_ENDIAN} and {@link
347      *            BIG_ENDIAN}. *
348      * @return array the unsigned rational found at offset, e.g., an
349      *         array with two integers in the range 0 to 4294967295.
350      *
351      */
352     public static function bytesToRational($bytes, $offset, $endian)
353     {
354         return array(
355             self::bytesToLong($bytes, $offset, $endian),
356             self::bytesToLong($bytes, $offset + 4, $endian)
357         );
358     }
359
360     /**
361      * Extract a signed rational from bytes.
362      *
363      * @param string $bytes
364      *
365      * @param integer $offset
366      *            The rational found at offset will be
367      *            returned as an array. There must be at least eight bytes
368      *            available beginning at the offset given.
369      * @param integer $endian
370      *            one of {@link LITTLE_ENDIAN} and {@link
371      *            BIG_ENDIAN}.
372      * @return array the signed rational found at offset, e.g., an array
373      *         with two integers in the range -2147483648 to 2147483647.
374      *
375      */
376     public static function bytesToSRational($bytes, $offset, $endian)
377     {
378         return array(
379             self::bytesToSLong($bytes, $offset, $endian),
380             self::bytesToSLong($bytes, $offset + 4, $endian)
381         );
382     }
383
384     /**
385      * Format bytes for dumping.
386      *
387      * This method is for debug output, it will format a string as a
388      * hexadecimal dump suitable for display on a terminal. The output
389      * is printed directly to standard out.
390      *
391      * @param string $bytes
392      *            the bytes that will be dumped.
393      *
394      * @param integer $max
395      *            the maximum number of bytes to dump. If this is left
396      *            out (or left to the default of 0), then the entire string will be
397      *            dumped.
398      * @return void
399      */
400     public static function bytesToDump($bytes, $max = 0)
401     {
402         $s = strlen($bytes);
403
404         if ($max > 0) {
405             $s = min($max, $s);
406         }
407         $line = 24;
408
409         for ($i = 0; $i < $s; $i ++) {
410             printf('%02X ', ord($bytes{$i}));
411
412             if (($i + 1) % $line == 0) {
413                 print("\n");
414             }
415         }
416         print("\n");
417     }
418 }