1. /*
  2. * @(#)MarkerSegment.java 1.7 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.imageio.plugins.jpeg;
  8. import javax.imageio.metadata.IIOInvalidTreeException;
  9. import javax.imageio.metadata.IIOMetadataNode;
  10. import javax.imageio.stream.ImageOutputStream;
  11. import java.io.IOException;
  12. import org.w3c.dom.Node;
  13. import org.w3c.dom.NamedNodeMap;
  14. /**
  15. * All metadata is stored in MarkerSegments. Marker segments
  16. * that we know about are stored in subclasses of this
  17. * basic class, which used for unrecognized APPn marker
  18. * segments. XXX break out UnknownMarkerSegment as a subclass
  19. * and make this abstract, avoiding unused data field.
  20. */
  21. class MarkerSegment implements Cloneable {
  22. protected static final int LENGTH_SIZE = 2; // length is 2 bytes
  23. int tag; // See JPEG.java
  24. int length; /* Sometimes needed by subclasses; doesn't include
  25. itself. Meaningful only if constructed from a stream */
  26. byte [] data = null; // Raw segment data, used for unrecognized segments
  27. boolean unknown = false; // Set to true if the tag is not recognized
  28. /**
  29. * Constructor for creating <code>MarkerSegment</code>s by reading
  30. * from an <code>ImageInputStream</code>.
  31. */
  32. MarkerSegment(JPEGBuffer buffer) throws IOException {
  33. buffer.loadBuf(3); // tag plus length
  34. tag = buffer.buf[buffer.bufPtr++] & 0xff;
  35. length = (buffer.buf[buffer.bufPtr++] & 0xff) << 8;
  36. length |= buffer.buf[buffer.bufPtr++] & 0xff;
  37. length -= 2; // JPEG length includes itself, we don't
  38. buffer.bufAvail -= 3;
  39. // Now that we know the true length, ensure that we've got it,
  40. // or at least a bufferful if length is too big.
  41. buffer.loadBuf(length);
  42. }
  43. /**
  44. * Constructor used when creating segments other than by
  45. * reading them from a stream.
  46. */
  47. MarkerSegment(int tag) {
  48. this.tag = tag;
  49. length = 0;
  50. }
  51. /**
  52. * Construct a MarkerSegment from an "unknown" DOM Node.
  53. */
  54. MarkerSegment(Node node) throws IIOInvalidTreeException {
  55. // The type of node should have been verified already.
  56. // get the attribute and assign it to the tag
  57. tag = getAttributeValue(node,
  58. null,
  59. "MarkerTag",
  60. 0, 255,
  61. true);
  62. length = 0;
  63. // get the user object and clone it to the data
  64. if (node instanceof IIOMetadataNode) {
  65. IIOMetadataNode iioNode = (IIOMetadataNode) node;
  66. try {
  67. data = (byte []) iioNode.getUserObject();
  68. } catch (Exception e) {
  69. IIOInvalidTreeException newGuy =
  70. new IIOInvalidTreeException
  71. ("Can't get User Object", node);
  72. newGuy.initCause(e);
  73. throw newGuy;
  74. }
  75. } else {
  76. throw new IIOInvalidTreeException
  77. ("Node must have User Object", node);
  78. }
  79. }
  80. /**
  81. * Deep copy of data array.
  82. */
  83. protected Object clone() {
  84. MarkerSegment newGuy = null;
  85. try {
  86. newGuy = (MarkerSegment) super.clone();
  87. } catch (CloneNotSupportedException e) {} // won't happen
  88. if (this.data != null) {
  89. newGuy.data = (byte[]) data.clone();
  90. }
  91. return newGuy;
  92. }
  93. /**
  94. * We have determined that we don't know the type, so load
  95. * the data using the length parameter.
  96. */
  97. void loadData(JPEGBuffer buffer) throws IOException {
  98. data = new byte[length];
  99. buffer.readData(data);
  100. }
  101. IIOMetadataNode getNativeNode() {
  102. IIOMetadataNode node = new IIOMetadataNode("unknown");
  103. node.setAttribute("MarkerTag", Integer.toString(tag));
  104. node.setUserObject(data);
  105. return node;
  106. }
  107. static int getAttributeValue(Node node,
  108. NamedNodeMap attrs,
  109. String name,
  110. int min,
  111. int max,
  112. boolean required)
  113. throws IIOInvalidTreeException {
  114. if (attrs == null) {
  115. attrs = node.getAttributes();
  116. }
  117. String valueString = attrs.getNamedItem(name).getNodeValue();
  118. int value = -1;
  119. if (valueString == null) {
  120. if (required) {
  121. throw new IIOInvalidTreeException
  122. (name + " attribute not found", node);
  123. }
  124. } else {
  125. value = Integer.parseInt(valueString);
  126. if ((value < min) || (value > max)) {
  127. throw new IIOInvalidTreeException
  128. (name + " attribute out of range", node);
  129. }
  130. }
  131. return value;
  132. }
  133. /**
  134. * Writes the marker, tag, and length. Note that length
  135. * should be verified by the caller as a correct JPEG
  136. * length, i.e it includes itself.
  137. */
  138. void writeTag(ImageOutputStream ios) throws IOException {
  139. ios.write(0xff);
  140. ios.write(tag);
  141. write2bytes(ios, length);
  142. }
  143. /**
  144. * Writes the data for this segment to the stream in
  145. * valid JPEG format.
  146. */
  147. void write(ImageOutputStream ios) throws IOException {
  148. length = 2 + ((data != null) ? data.length : 0);
  149. writeTag(ios);
  150. if (data != null) {
  151. ios.write(data);
  152. }
  153. }
  154. static void write2bytes(ImageOutputStream ios,
  155. int value) throws IOException {
  156. ios.write((value >> 8) & 0xff);
  157. ios.write(value & 0xff);
  158. }
  159. void printTag(String prefix) {
  160. System.out.println(prefix + " marker segment - marker = 0x"
  161. + Integer.toHexString(tag));
  162. System.out.println("length: " + length);
  163. }
  164. void print() {
  165. printTag("Unknown");
  166. if (length > 10) {
  167. System.out.print("First 5 bytes:");
  168. for (int i=0;i<5;i++) {
  169. System.out.print(" Ox"
  170. + Integer.toHexString((int)data[i]));
  171. }
  172. System.out.print("\nLast 5 bytes:");
  173. for (int i=data.length-5;i<data.length;i++) {
  174. System.out.print(" Ox"
  175. + Integer.toHexString((int)data[i]));
  176. }
  177. } else {
  178. System.out.print("Data:");
  179. for (int i=0;i<data.length;i++) {
  180. System.out.print(" Ox"
  181. + Integer.toHexString((int)data[i]));
  182. }
  183. }
  184. System.out.println();
  185. }
  186. }