1. /*
  2. * Copyright 2001-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. package org.apache.commons.io;
  17. import java.io.EOFException;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.OutputStream;
  21. /**
  22. * Utility code for dealing with different endian systems.
  23. * <br>
  24. * Origin of code: Apache Avalon (Excalibur)
  25. *
  26. * @author <a href="mailto:peter@apache.org">Peter Donald</a>
  27. * @version CVS $Revision: 1.13 $ $Date: 2004/02/23 04:35:59 $
  28. */
  29. public final class EndianUtils
  30. {
  31. /**
  32. * Instances should NOT be constructed in standard programming.
  33. */
  34. public EndianUtils() { }
  35. // ========================================== Swapping routines
  36. /**
  37. * Converts a "short" value between endian systems.
  38. * @param value value to convert
  39. * @return the converted value
  40. */
  41. public static short swapShort( short value )
  42. {
  43. return (short)( ( ( ( value >> 0 ) & 0xff ) << 8 ) +
  44. ( ( ( value >> 8 ) & 0xff ) << 0 ) );
  45. }
  46. /**
  47. * Converts a "int" value between endian systems.
  48. * @param value value to convert
  49. * @return the converted value
  50. */
  51. public static int swapInteger( int value )
  52. {
  53. return
  54. ( ( ( value >> 0 ) & 0xff ) << 24 ) +
  55. ( ( ( value >> 8 ) & 0xff ) << 16 ) +
  56. ( ( ( value >> 16 ) & 0xff ) << 8 ) +
  57. ( ( ( value >> 24 ) & 0xff ) << 0 );
  58. }
  59. /**
  60. * Converts a "long" value between endian systems.
  61. * @param value value to convert
  62. * @return the converted value
  63. */
  64. public static long swapLong( long value )
  65. {
  66. return
  67. ( ( ( value >> 0 ) & 0xff ) << 56 ) +
  68. ( ( ( value >> 8 ) & 0xff ) << 48 ) +
  69. ( ( ( value >> 16 ) & 0xff ) << 40 ) +
  70. ( ( ( value >> 24 ) & 0xff ) << 32 ) +
  71. ( ( ( value >> 32 ) & 0xff ) << 24 ) +
  72. ( ( ( value >> 40 ) & 0xff ) << 16 ) +
  73. ( ( ( value >> 48 ) & 0xff ) << 8 ) +
  74. ( ( ( value >> 56 ) & 0xff ) << 0 );
  75. }
  76. /**
  77. * Converts a "float" value between endian systems.
  78. * @param value value to convert
  79. * @return the converted value
  80. */
  81. public static float swapFloat( float value )
  82. {
  83. return Float.intBitsToFloat( swapInteger( Float.floatToIntBits( value ) ) );
  84. }
  85. /**
  86. * Converts a "double" value between endian systems.
  87. * @param value value to convert
  88. * @return the converted value
  89. */
  90. public static double swapDouble( double value )
  91. {
  92. return Double.longBitsToDouble( swapLong( Double.doubleToLongBits( value ) ) );
  93. }
  94. // ========================================== Swapping read/write routines
  95. /**
  96. * Writes a "short" value to a byte array at a given offset. The value is
  97. * converted to the opposed endian system while writing.
  98. * @param data target byte array
  99. * @param offset starting offset in the byte array
  100. * @param value value to write
  101. */
  102. public static void writeSwappedShort( byte[] data, int offset, short value )
  103. {
  104. data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
  105. data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
  106. }
  107. /**
  108. * Reads a "short" value from a byte array at a given offset. The value is
  109. * converted to the opposed endian system while reading.
  110. * @param data source byte array
  111. * @param offset starting offset in the byte array
  112. * @return the value read
  113. */
  114. public static short readSwappedShort( byte[] data, int offset )
  115. {
  116. return (short)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
  117. ( ( data[ offset + 1 ] & 0xff ) << 8 ) );
  118. }
  119. /**
  120. * Reads an unsigned short (16-bit) value from a byte array at a given
  121. * offset. The value is converted to the opposed endian system while
  122. * reading.
  123. * @param data source byte array
  124. * @param offset starting offset in the byte array
  125. * @return the value read
  126. */
  127. public static int readSwappedUnsignedShort( byte[] data, int offset )
  128. {
  129. return (int)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
  130. ( ( data[ offset + 1 ] & 0xff ) << 8 ) );
  131. }
  132. /**
  133. * Writes a "int" value to a byte array at a given offset. The value is
  134. * converted to the opposed endian system while writing.
  135. * @param data target byte array
  136. * @param offset starting offset in the byte array
  137. * @param value value to write
  138. */
  139. public static void writeSwappedInteger( byte[] data, int offset, int value )
  140. {
  141. data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
  142. data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
  143. data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff );
  144. data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff );
  145. }
  146. /**
  147. * Reads a "int" value from a byte array at a given offset. The value is
  148. * converted to the opposed endian system while reading.
  149. * @param data source byte array
  150. * @param offset starting offset in the byte array
  151. * @return the value read
  152. */
  153. public static int readSwappedInteger( byte[] data, int offset )
  154. {
  155. return (int)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
  156. ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
  157. ( ( data[ offset + 2 ] & 0xff ) << 16 ) +
  158. ( ( data[ offset + 3 ] & 0xff ) << 24 ) );
  159. }
  160. /**
  161. * Reads an unsigned integer (32-bit) value from a byte array at a given
  162. * offset. The value is converted to the opposed endian system while
  163. * reading.
  164. * @param data source byte array
  165. * @param offset starting offset in the byte array
  166. * @return the value read
  167. */
  168. public static long readSwappedUnsignedInteger( byte[] data, int offset )
  169. {
  170. return (long)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
  171. ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
  172. ( ( data[ offset + 2 ] & 0xff ) << 16 ) +
  173. ( ( data[ offset + 3 ] & 0xff ) << 24 ) );
  174. }
  175. /**
  176. * Writes a "long" value to a byte array at a given offset. The value is
  177. * converted to the opposed endian system while writing.
  178. * @param data target byte array
  179. * @param offset starting offset in the byte array
  180. * @param value value to write
  181. */
  182. public static void writeSwappedLong( byte[] data, int offset, long value )
  183. {
  184. data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
  185. data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
  186. data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff );
  187. data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff );
  188. data[ offset + 4 ] = (byte)( ( value >> 32 ) & 0xff );
  189. data[ offset + 5 ] = (byte)( ( value >> 40 ) & 0xff );
  190. data[ offset + 6 ] = (byte)( ( value >> 48 ) & 0xff );
  191. data[ offset + 7 ] = (byte)( ( value >> 56 ) & 0xff );
  192. }
  193. /**
  194. * Reads a "long" value from a byte array at a given offset. The value is
  195. * converted to the opposed endian system while reading.
  196. * @param data source byte array
  197. * @param offset starting offset in the byte array
  198. * @return the value read
  199. */
  200. public static long readSwappedLong( byte[] data, int offset )
  201. {
  202. long low = (long)(
  203. ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
  204. ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
  205. ( ( data[ offset + 2 ] & 0xff ) << 16 ) +
  206. ( ( data[ offset + 3 ] & 0xff ) << 24 ) );
  207. long high = (long)(
  208. ( ( data[ offset + 4 ] & 0xff ) << 0 ) +
  209. ( ( data[ offset + 5 ] & 0xff ) << 8 ) +
  210. ( ( data[ offset + 6 ] & 0xff ) << 16 ) +
  211. ( ( data[ offset + 7 ] & 0xff ) << 24 ) );
  212. return low + (high << 32);
  213. }
  214. /**
  215. * Writes a "float" value to a byte array at a given offset. The value is
  216. * converted to the opposed endian system while writing.
  217. * @param data target byte array
  218. * @param offset starting offset in the byte array
  219. * @param value value to write
  220. */
  221. public static void writeSwappedFloat( byte[] data, int offset, float value )
  222. {
  223. writeSwappedInteger( data, offset, Float.floatToIntBits( value ) );
  224. }
  225. /**
  226. * Reads a "float" value from a byte array at a given offset. The value is
  227. * converted to the opposed endian system while reading.
  228. * @param data source byte array
  229. * @param offset starting offset in the byte array
  230. * @return the value read
  231. */
  232. public static float readSwappedFloat( byte[] data, int offset )
  233. {
  234. return Float.intBitsToFloat( readSwappedInteger( data, offset ) );
  235. }
  236. /**
  237. * Writes a "double" value to a byte array at a given offset. The value is
  238. * converted to the opposed endian system while writing.
  239. * @param data target byte array
  240. * @param offset starting offset in the byte array
  241. * @param value value to write
  242. */
  243. public static void writeSwappedDouble( byte[] data, int offset, double value )
  244. {
  245. writeSwappedLong( data, offset, Double.doubleToLongBits( value ) );
  246. }
  247. /**
  248. * Reads a "double" value from a byte array at a given offset. The value is
  249. * converted to the opposed endian system while reading.
  250. * @param data source byte array
  251. * @param offset starting offset in the byte array
  252. * @return the value read
  253. */
  254. public static double readSwappedDouble( byte[] data, int offset )
  255. {
  256. return Double.longBitsToDouble( readSwappedLong( data, offset ) );
  257. }
  258. /**
  259. * Writes a "short" value to an OutputStream. The value is
  260. * converted to the opposed endian system while writing.
  261. * @param output target OutputStream
  262. * @param value value to write
  263. * @throws IOException in case of an I/O problem
  264. */
  265. public static void writeSwappedShort( OutputStream output, short value )
  266. throws IOException
  267. {
  268. output.write( (byte)( ( value >> 0 ) & 0xff ) );
  269. output.write( (byte)( ( value >> 8 ) & 0xff ) );
  270. }
  271. /**
  272. * Reads a "short" value from an InputStream. The value is
  273. * converted to the opposed endian system while reading.
  274. * @param input source InputStream
  275. * @return the value just read
  276. * @throws IOException in case of an I/O problem
  277. */
  278. public static short readSwappedShort( InputStream input )
  279. throws IOException
  280. {
  281. return (short)( ( ( read( input ) & 0xff ) << 0 ) +
  282. ( ( read( input ) & 0xff ) << 8 ) );
  283. }
  284. /**
  285. * Reads a unsigned short (16-bit) from an InputStream. The value is
  286. * converted to the opposed endian system while reading.
  287. * @param input source InputStream
  288. * @return the value just read
  289. * @throws IOException in case of an I/O problem
  290. */
  291. public static int readSwappedUnsignedShort( InputStream input )
  292. throws IOException
  293. {
  294. int value1 = read( input );
  295. int value2 = read( input );
  296. return (int)( ( ( value1 & 0xff ) << 0 ) +
  297. ( ( value2 & 0xff ) << 8 ) );
  298. }
  299. /**
  300. * Writes a "int" value to an OutputStream. The value is
  301. * converted to the opposed endian system while writing.
  302. * @param output target OutputStream
  303. * @param value value to write
  304. * @throws IOException in case of an I/O problem
  305. */
  306. public static void writeSwappedInteger( OutputStream output, int value )
  307. throws IOException
  308. {
  309. output.write( (byte)( ( value >> 0 ) & 0xff ) );
  310. output.write( (byte)( ( value >> 8 ) & 0xff ) );
  311. output.write( (byte)( ( value >> 16 ) & 0xff ) );
  312. output.write( (byte)( ( value >> 24 ) & 0xff ) );
  313. }
  314. /**
  315. * Reads a "int" value from an InputStream. The value is
  316. * converted to the opposed endian system while reading.
  317. * @param input source InputStream
  318. * @return the value just read
  319. * @throws IOException in case of an I/O problem
  320. */
  321. public static int readSwappedInteger( InputStream input )
  322. throws IOException
  323. {
  324. int value1 = read( input );
  325. int value2 = read( input );
  326. int value3 = read( input );
  327. int value4 = read( input );
  328. return (int)( ( ( value1 & 0xff ) << 0 ) +
  329. ( ( value2 & 0xff ) << 8 ) +
  330. ( ( value3 & 0xff ) << 16 ) +
  331. ( ( value4 & 0xff ) << 24 ) );
  332. }
  333. /**
  334. * Reads a unsigned integer (32-bit) from an InputStream. The value is
  335. * converted to the opposed endian system while reading.
  336. * @param input source InputStream
  337. * @return the value just read
  338. * @throws IOException in case of an I/O problem
  339. */
  340. public static long readSwappedUnsignedInteger( InputStream input )
  341. throws IOException
  342. {
  343. int value1 = read( input );
  344. int value2 = read( input );
  345. int value3 = read( input );
  346. int value4 = read( input );
  347. return (long)( ( ( value1 & 0xff ) << 0 ) +
  348. ( ( value2 & 0xff ) << 8 ) +
  349. ( ( value3 & 0xff ) << 16 ) +
  350. ( ( value4 & 0xff ) << 24 ) );
  351. }
  352. /**
  353. * Writes a "long" value to an OutputStream. The value is
  354. * converted to the opposed endian system while writing.
  355. * @param output target OutputStream
  356. * @param value value to write
  357. * @throws IOException in case of an I/O problem
  358. */
  359. public static void writeSwappedLong( OutputStream output, long value )
  360. throws IOException
  361. {
  362. output.write( (byte)( ( value >> 0 ) & 0xff ) );
  363. output.write( (byte)( ( value >> 8 ) & 0xff ) );
  364. output.write( (byte)( ( value >> 16 ) & 0xff ) );
  365. output.write( (byte)( ( value >> 24 ) & 0xff ) );
  366. output.write( (byte)( ( value >> 32 ) & 0xff ) );
  367. output.write( (byte)( ( value >> 40 ) & 0xff ) );
  368. output.write( (byte)( ( value >> 48 ) & 0xff ) );
  369. output.write( (byte)( ( value >> 56 ) & 0xff ) );
  370. }
  371. /**
  372. * Reads a "long" value from an InputStream. The value is
  373. * converted to the opposed endian system while reading.
  374. * @param input source InputStream
  375. * @return the value just read
  376. * @throws IOException in case of an I/O problem
  377. */
  378. public static long readSwappedLong( InputStream input )
  379. throws IOException
  380. {
  381. byte[] bytes = new byte[8];
  382. input.read( bytes );
  383. return readSwappedLong( bytes, 0 );
  384. }
  385. /**
  386. * Writes a "float" value to an OutputStream. The value is
  387. * converted to the opposed endian system while writing.
  388. * @param output target OutputStream
  389. * @param value value to write
  390. * @throws IOException in case of an I/O problem
  391. */
  392. public static void writeSwappedFloat( OutputStream output, float value )
  393. throws IOException
  394. {
  395. writeSwappedInteger( output, Float.floatToIntBits( value ) );
  396. }
  397. /**
  398. * Reads a "float" value from an InputStream. The value is
  399. * converted to the opposed endian system while reading.
  400. * @param input source InputStream
  401. * @return the value just read
  402. * @throws IOException in case of an I/O problem
  403. */
  404. public static float readSwappedFloat( InputStream input )
  405. throws IOException
  406. {
  407. return Float.intBitsToFloat( readSwappedInteger( input ) );
  408. }
  409. /**
  410. * Writes a "double" value to an OutputStream. The value is
  411. * converted to the opposed endian system while writing.
  412. * @param output target OutputStream
  413. * @param value value to write
  414. * @throws IOException in case of an I/O problem
  415. */
  416. public static void writeSwappedDouble( OutputStream output, double value )
  417. throws IOException
  418. {
  419. writeSwappedLong( output, Double.doubleToLongBits( value ) );
  420. }
  421. /**
  422. * Reads a "double" value from an InputStream. The value is
  423. * converted to the opposed endian system while reading.
  424. * @param input source InputStream
  425. * @return the value just read
  426. * @throws IOException in case of an I/O problem
  427. */
  428. public static double readSwappedDouble( InputStream input )
  429. throws IOException
  430. {
  431. return Double.longBitsToDouble( readSwappedLong( input ) );
  432. }
  433. private static int read( InputStream input )
  434. throws IOException
  435. {
  436. int value = input.read();
  437. if( -1 == value )
  438. {
  439. throw new EOFException( "Unexpected EOF reached" );
  440. }
  441. return value;
  442. }
  443. }