1. /*
  2. * @(#)ImageOutputStreamImpl.java 1.23 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.imageio.stream;
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.io.UTFDataFormatException;
  11. import java.nio.ByteOrder;
  12. /**
  13. * An abstract class implementing the <code>ImageOutputStream</code> interface.
  14. * This class is designed to reduce the number of methods that must
  15. * be implemented by subclasses.
  16. *
  17. * @version 0.5
  18. */
  19. public abstract class ImageOutputStreamImpl
  20. extends ImageInputStreamImpl
  21. implements ImageOutputStream {
  22. /**
  23. * Constructs an <code>ImageOutputStreamImpl</code>.
  24. */
  25. public ImageOutputStreamImpl() {
  26. }
  27. public abstract void write(int b) throws IOException;
  28. public void write(byte b[]) throws IOException {
  29. write(b, 0, b.length);
  30. }
  31. public abstract void write(byte b[], int off, int len) throws IOException;
  32. public void writeBoolean(boolean v) throws IOException {
  33. write(v ? 1 : 0);
  34. }
  35. public void writeByte(int v) throws IOException {
  36. write(v);
  37. }
  38. public void writeShort(int v) throws IOException {
  39. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  40. write((v >>> 8) & 0xFF);
  41. write((v >>> 0) & 0xFF);
  42. } else {
  43. write((v >>> 0) & 0xFF);
  44. write((v >>> 8) & 0xFF);
  45. }
  46. }
  47. public void writeChar(int v) throws IOException {
  48. writeShort(v);
  49. }
  50. public void writeInt(int v) throws IOException {
  51. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  52. write((v >>> 24) & 0xFF);
  53. write((v >>> 16) & 0xFF);
  54. write((v >>> 8) & 0xFF);
  55. write((v >>> 0) & 0xFF);
  56. } else {
  57. write((v >>> 0) & 0xFF);
  58. write((v >>> 8) & 0xFF);
  59. write((v >>> 16) & 0xFF);
  60. write((v >>> 24) & 0xFF);
  61. }
  62. }
  63. public void writeLong(long v) throws IOException {
  64. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  65. write((int)(v >>> 56) & 0xFF);
  66. write((int)(v >>> 48) & 0xFF);
  67. write((int)(v >>> 40) & 0xFF);
  68. write((int)(v >>> 32) & 0xFF);
  69. write((int)(v >>> 24) & 0xFF);
  70. write((int)(v >>> 16) & 0xFF);
  71. write((int)(v >>> 8) & 0xFF);
  72. write((int)(v >>> 0) & 0xFF);
  73. } else {
  74. write((int)(v >>> 0) & 0xFF);
  75. write((int)(v >>> 8) & 0xFF);
  76. write((int)(v >>> 16) & 0xFF);
  77. write((int)(v >>> 24) & 0xFF);
  78. write((int)(v >>> 32) & 0xFF);
  79. write((int)(v >>> 40) & 0xFF);
  80. write((int)(v >>> 48) & 0xFF);
  81. write((int)(v >>> 56) & 0xFF);
  82. }
  83. }
  84. public void writeFloat(float v) throws IOException {
  85. writeInt(Float.floatToIntBits(v));
  86. }
  87. public void writeDouble(double v) throws IOException {
  88. writeLong(Double.doubleToLongBits(v));
  89. }
  90. public void writeBytes(String s) throws IOException {
  91. int len = s.length();
  92. for (int i = 0 ; i < len ; i++) {
  93. write((byte)s.charAt(i));
  94. }
  95. }
  96. public void writeChars(String s) throws IOException {
  97. int len = s.length();
  98. byte[] b = new byte[len*2];
  99. int boff = 0;
  100. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  101. for (int i = 0; i < len ; i++) {
  102. int v = s.charAt(i);
  103. b[boff++] = (byte)(v >>> 8);
  104. b[boff++] = (byte)(v >>> 0);
  105. }
  106. } else {
  107. for (int i = 0; i < len ; i++) {
  108. int v = s.charAt(i);
  109. b[boff++] = (byte)(v >>> 0);
  110. b[boff++] = (byte)(v >>> 8);
  111. }
  112. }
  113. write(b, 0, len*2);
  114. }
  115. public void writeUTF(String s) throws IOException {
  116. int strlen = s.length();
  117. int utflen = 0;
  118. char[] charr = new char[strlen];
  119. int c, boff = 0;
  120. s.getChars(0, strlen, charr, 0);
  121. for (int i = 0; i < strlen; i++) {
  122. c = charr[i];
  123. if ((c >= 0x0001) && (c <= 0x007F)) {
  124. utflen++;
  125. } else if (c > 0x07FF) {
  126. utflen += 3;
  127. } else {
  128. utflen += 2;
  129. }
  130. }
  131. if (utflen > 65535) {
  132. throw new UTFDataFormatException("utflen > 65536!");
  133. }
  134. byte[] b = new byte[utflen+2];
  135. b[boff++] = (byte) ((utflen >>> 8) & 0xFF);
  136. b[boff++] = (byte) ((utflen >>> 0) & 0xFF);
  137. for (int i = 0; i < strlen; i++) {
  138. c = charr[i];
  139. if ((c >= 0x0001) && (c <= 0x007F)) {
  140. b[boff++] = (byte) c;
  141. } else if (c > 0x07FF) {
  142. b[boff++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
  143. b[boff++] = (byte) (0x80 | ((c >> 6) & 0x3F));
  144. b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
  145. } else {
  146. b[boff++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
  147. b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
  148. }
  149. }
  150. write(b, 0, utflen + 2);
  151. }
  152. public void writeShorts(short[] s, int off, int len) throws IOException {
  153. // Fix 4430357 - if off + len < 0, overflow occurred
  154. if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
  155. throw new IndexOutOfBoundsException
  156. ("off < 0 || len < 0 || off + len > s.length!");
  157. }
  158. byte[] b = new byte[len*2];
  159. int boff = 0;
  160. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  161. for (int i = 0; i < len; i++) {
  162. short v = s[off + i];
  163. b[boff++] = (byte)(v >>> 8);
  164. b[boff++] = (byte)(v >>> 0);
  165. }
  166. } else {
  167. for (int i = 0; i < len; i++) {
  168. short v = s[off + i];
  169. b[boff++] = (byte)(v >>> 0);
  170. b[boff++] = (byte)(v >>> 8);
  171. }
  172. }
  173. write(b, 0, len*2);
  174. }
  175. public void writeChars(char[] c, int off, int len) throws IOException {
  176. // Fix 4430357 - if off + len < 0, overflow occurred
  177. if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
  178. throw new IndexOutOfBoundsException
  179. ("off < 0 || len < 0 || off + len > c.length!");
  180. }
  181. byte[] b = new byte[len*2];
  182. int boff = 0;
  183. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  184. for (int i = 0; i < len; i++) {
  185. char v = c[off + i];
  186. b[boff++] = (byte)(v >>> 8);
  187. b[boff++] = (byte)(v >>> 0);
  188. }
  189. } else {
  190. for (int i = 0; i < len; i++) {
  191. char v = c[off + i];
  192. b[boff++] = (byte)(v >>> 0);
  193. b[boff++] = (byte)(v >>> 8);
  194. }
  195. }
  196. write(b, 0, len*2);
  197. }
  198. public void writeInts(int[] i, int off, int len) throws IOException {
  199. // Fix 4430357 - if off + len < 0, overflow occurred
  200. if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
  201. throw new IndexOutOfBoundsException
  202. ("off < 0 || len < 0 || off + len > i.length!");
  203. }
  204. byte[] b = new byte[len*4];
  205. int boff = 0;
  206. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  207. for (int j = 0; j < len; j++) {
  208. int v = i[off + j];
  209. b[boff++] = (byte)(v >>> 24);
  210. b[boff++] = (byte)(v >>> 16);
  211. b[boff++] = (byte)(v >>> 8);
  212. b[boff++] = (byte)(v >>> 0);
  213. }
  214. } else {
  215. for (int j = 0; j < len; j++) {
  216. int v = i[off + j];
  217. b[boff++] = (byte)(v >>> 0);
  218. b[boff++] = (byte)(v >>> 8);
  219. b[boff++] = (byte)(v >>> 16);
  220. b[boff++] = (byte)(v >>> 24);
  221. }
  222. }
  223. write(b, 0, len*4);
  224. }
  225. public void writeLongs(long[] l, int off, int len) throws IOException {
  226. // Fix 4430357 - if off + len < 0, overflow occurred
  227. if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
  228. throw new IndexOutOfBoundsException
  229. ("off < 0 || len < 0 || off + len > l.length!");
  230. }
  231. byte[] b = new byte[len*8];
  232. int boff = 0;
  233. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  234. for (int i = 0; i < len; i++) {
  235. long v = l[off + i];
  236. b[boff++] = (byte)(v >>> 56);
  237. b[boff++] = (byte)(v >>> 48);
  238. b[boff++] = (byte)(v >>> 40);
  239. b[boff++] = (byte)(v >>> 32);
  240. b[boff++] = (byte)(v >>> 24);
  241. b[boff++] = (byte)(v >>> 16);
  242. b[boff++] = (byte)(v >>> 8);
  243. b[boff++] = (byte)(v >>> 0);
  244. }
  245. } else {
  246. for (int i = 0; i < len; i++) {
  247. long v = l[off + i];
  248. b[boff++] = (byte)(v >>> 0);
  249. b[boff++] = (byte)(v >>> 8);
  250. b[boff++] = (byte)(v >>> 16);
  251. b[boff++] = (byte)(v >>> 24);
  252. b[boff++] = (byte)(v >>> 32);
  253. b[boff++] = (byte)(v >>> 40);
  254. b[boff++] = (byte)(v >>> 48);
  255. b[boff++] = (byte)(v >>> 56);
  256. }
  257. }
  258. write(b, 0, len*8);
  259. }
  260. public void writeFloats(float[] f, int off, int len) throws IOException {
  261. // Fix 4430357 - if off + len < 0, overflow occurred
  262. if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
  263. throw new IndexOutOfBoundsException
  264. ("off < 0 || len < 0 || off + len > f.length!");
  265. }
  266. byte[] b = new byte[len*4];
  267. int boff = 0;
  268. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  269. for (int i = 0; i < len; i++) {
  270. int v = Float.floatToIntBits(f[off + i]);
  271. b[boff++] = (byte)(v >>> 24);
  272. b[boff++] = (byte)(v >>> 16);
  273. b[boff++] = (byte)(v >>> 8);
  274. b[boff++] = (byte)(v >>> 0);
  275. }
  276. } else {
  277. for (int i = 0; i < len; i++) {
  278. int v = Float.floatToIntBits(f[off + i]);
  279. b[boff++] = (byte)(v >>> 0);
  280. b[boff++] = (byte)(v >>> 8);
  281. b[boff++] = (byte)(v >>> 16);
  282. b[boff++] = (byte)(v >>> 24);
  283. }
  284. }
  285. write(b, 0, len*4);
  286. }
  287. public void writeDoubles(double[] d, int off, int len) throws IOException {
  288. // Fix 4430357 - if off + len < 0, overflow occurred
  289. if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
  290. throw new IndexOutOfBoundsException
  291. ("off < 0 || len < 0 || off + len > d.length!");
  292. }
  293. byte[] b = new byte[len*8];
  294. int boff = 0;
  295. if (byteOrder == ByteOrder.BIG_ENDIAN) {
  296. for (int i = 0; i < len; i++) {
  297. long v = Double.doubleToLongBits(d[off + i]);
  298. b[boff++] = (byte)(v >>> 56);
  299. b[boff++] = (byte)(v >>> 48);
  300. b[boff++] = (byte)(v >>> 40);
  301. b[boff++] = (byte)(v >>> 32);
  302. b[boff++] = (byte)(v >>> 24);
  303. b[boff++] = (byte)(v >>> 16);
  304. b[boff++] = (byte)(v >>> 8);
  305. b[boff++] = (byte)(v >>> 0);
  306. }
  307. } else {
  308. for (int i = 0; i < len; i++) {
  309. long v = Double.doubleToLongBits(d[off + i]);
  310. b[boff++] = (byte)(v >>> 0);
  311. b[boff++] = (byte)(v >>> 8);
  312. b[boff++] = (byte)(v >>> 16);
  313. b[boff++] = (byte)(v >>> 24);
  314. b[boff++] = (byte)(v >>> 32);
  315. b[boff++] = (byte)(v >>> 40);
  316. b[boff++] = (byte)(v >>> 48);
  317. b[boff++] = (byte)(v >>> 56);
  318. }
  319. }
  320. write(b, 0, len*8);
  321. }
  322. public void writeBit(int bit) throws IOException {
  323. writeBits((1L & bit), 1);
  324. }
  325. public void writeBits(long bits, int numBits) throws IOException {
  326. checkClosed();
  327. if (numBits < 0 || numBits > 64) {
  328. throw new IllegalArgumentException("Bad value for numBits!");
  329. }
  330. if (numBits == 0) {
  331. return;
  332. }
  333. // Prologue: deal with pre-existing bits
  334. // Bug 4499158, 4507868 - if we're at the beginning of the stream
  335. // and the bit offset is 0, there can't be any pre-existing bits
  336. if ((getStreamPosition() > 0) || (bitOffset > 0)) {
  337. int offset = bitOffset; // read() will reset bitOffset
  338. int partialByte = read();
  339. if (partialByte != -1) {
  340. seek(getStreamPosition() - 1);
  341. } else {
  342. partialByte = 0;
  343. }
  344. if (numBits + offset < 8) {
  345. // Notch out the partial byte and drop in the new bits
  346. int shift = 8 - (offset+numBits);
  347. int mask = -1 >>> (32 - numBits);
  348. partialByte &= ~(mask << shift); // Clear out old bits
  349. partialByte |= ((bits & mask) << shift); // Or in new ones
  350. write(partialByte);
  351. seek(getStreamPosition() - 1);
  352. bitOffset = offset + numBits;
  353. numBits = 0; // Signal that we are done
  354. } else {
  355. // Fill out the partial byte and reduce numBits
  356. int num = 8 - offset;
  357. int mask = -1 >>> (32 - num);
  358. partialByte &= ~mask; // Clear out bits
  359. partialByte |= ((bits >> (numBits - num)) & mask);
  360. // Note that bitOffset is already 0, so there is no risk
  361. // of this advancing to the next byte
  362. write(partialByte);
  363. numBits -= num;
  364. }
  365. }
  366. // Now write any whole bytes
  367. if (numBits > 7) {
  368. int extra = numBits % 8;
  369. for (int numBytes = numBits / 8; numBytes > 0; numBytes--) {
  370. int shift = (numBytes-1)*8+extra;
  371. int value = (int) ((shift == 0)
  372. ? bits & 0xFF
  373. : (bits>>shift) & 0xFF);
  374. write(value);
  375. }
  376. numBits = extra;
  377. }
  378. // Epilogue: write out remaining partial byte, if any
  379. // Note that we may be at EOF, in which case we pad with 0,
  380. // or not, in which case we must preserve the existing bits
  381. if (numBits != 0) {
  382. // If we are not at the end of the file, read the current byte
  383. // If we are at the end of the file, initialize our byte to 0.
  384. int partialByte = 0;
  385. partialByte = read();
  386. if (partialByte != -1) {
  387. seek(getStreamPosition() - 1);
  388. }
  389. // Fix 4494976: writeBit(int) does not pad the remainder
  390. // of the current byte with 0s
  391. else { // EOF
  392. partialByte = 0;
  393. }
  394. int shift = 8 - numBits;
  395. int mask = -1 >>> (32 - numBits);
  396. partialByte &= ~(mask << shift);
  397. partialByte |= (bits & mask) << shift;
  398. // bitOffset is always already 0 when we get here.
  399. write(partialByte);
  400. seek(getStreamPosition() - 1);
  401. bitOffset = numBits;
  402. }
  403. }
  404. /**
  405. * If the bit offset is non-zero, forces the remaining bits
  406. * in the current byte to 0 and advances the stream position
  407. * by one. This method should be called by subclasses at the
  408. * beginning of the <code>write(int)</code> and
  409. * <code>write(byte[], int, int)</code> methods.
  410. *
  411. * @exception IOException if an I/O error occurs.
  412. */
  413. protected final void flushBits() throws IOException {
  414. checkClosed();
  415. if (bitOffset != 0) {
  416. int offset = bitOffset;
  417. int partialByte = read(); // Sets bitOffset to 0
  418. if (partialByte < 0) {
  419. // Fix 4465683: When bitOffset is set
  420. // to something non-zero beyond EOF,
  421. // we should set that whole byte to
  422. // zero and write it to stream.
  423. partialByte = 0;
  424. bitOffset = 0;
  425. }
  426. else {
  427. seek(getStreamPosition() - 1);
  428. partialByte &= -1 << (8 - offset);
  429. }
  430. write(partialByte);
  431. }
  432. }
  433. }