1 /*
   2  * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.imageio.plugins.tiff;
  26 
  27 import java.util.Arrays;
  28 import java.util.List;
  29 import javax.imageio.metadata.IIOMetadataNode;
  30 import org.w3c.dom.Node;
  31 import javax.imageio.plugins.tiff.TIFFDirectory;
  32 import javax.imageio.plugins.tiff.TIFFField;
  33 import javax.imageio.plugins.tiff.TIFFTag;
  34 import javax.imageio.plugins.tiff.TIFFTagSet;
  35 
  36 /**
  37  * The {@code Node} representation of a {@code TIFFField}
  38  * wherein the child node is procedural rather than buffered.
  39  */
  40 public class TIFFFieldNode extends IIOMetadataNode {
  41     private static boolean isIFD(TIFFField f) {
  42         int type = f.getType();
  43         return f.hasDirectory() &&
  44             (type == TIFFTag.TIFF_LONG || type == TIFFTag.TIFF_IFD_POINTER);
  45     }
  46 
  47     private static String getNodeName(TIFFField f) {
  48         return isIFD(f) ? "TIFFIFD" : "TIFFField";
  49     }
  50  
  51     private boolean isIFD;
  52 
  53     private Boolean isInitialized = Boolean.FALSE;
  54 
  55     private TIFFField field;
  56 
  57     public TIFFFieldNode(TIFFField field) {
  58         super(getNodeName(field));
  59 
  60         isIFD = isIFD(field);
  61 
  62         this.field = field;
  63 
  64         TIFFTag tag = field.getTag();
  65         int tagNumber = tag.getNumber();
  66         String tagName = tag.getName();
  67 
  68         if(isIFD) {
  69             if(tagNumber != 0) {
  70                 setAttribute("parentTagNumber", Integer.toString(tagNumber));
  71             }
  72             if(tagName != null) {
  73                 setAttribute("parentTagName", tagName);
  74             }
  75 
  76             TIFFDirectory dir = field.hasDirectory() ?
  77                 field.getDirectory() : (TIFFDirectory)field.getData();
  78             TIFFTagSet[] tagSets = dir.getTagSets();
  79             if(tagSets != null) {
  80                 StringBuilder tagSetNames = new StringBuilder();
  81                 for(int i = 0; i < tagSets.length; i++) {
  82                     tagSetNames.append(tagSets[i].getClass().getName());
  83                     if(i != tagSets.length - 1) {
  84                         tagSetNames.append(",");
  85                     }
  86                 }
  87                 setAttribute("tagSets", tagSetNames.toString());
  88             }
  89         } else {
  90             setAttribute("number", Integer.toString(tagNumber));
  91             setAttribute("name", tagName);
  92         }
  93     }
  94 
  95     private synchronized void initialize() {
  96         if(isInitialized) return;
  97 
  98         if(isIFD) {
  99             TIFFDirectory dir = field.hasDirectory() ?
 100                 field.getDirectory() : (TIFFDirectory)field.getData();
 101             TIFFField[] fields = dir.getTIFFFields();
 102             if(fields != null) {
 103                 TIFFTagSet[] tagSets = dir.getTagSets();
 104                 List<TIFFTagSet> tagSetList = Arrays.asList(tagSets);
 105                 int numFields = fields.length;
 106                 for(int i = 0; i < numFields; i++) {
 107                     TIFFField f = fields[i];
 108                     int tagNumber = f.getTagNumber();
 109                     TIFFTag tag = TIFFIFD.getTag(tagNumber, tagSetList);
 110 
 111                     Node node = f.getAsNativeNode();
 112 
 113                     if (node != null) {
 114                         appendChild(node);
 115                     }
 116                 }
 117             }
 118         } else {
 119             IIOMetadataNode child;
 120             int count = field.getCount();
 121             if (field.getType() == TIFFTag.TIFF_UNDEFINED) {
 122                 child = new IIOMetadataNode("TIFFUndefined");
 123 
 124                 byte[] data = field.getAsBytes();
 125                 StringBuffer sb = new StringBuffer();
 126                 for (int i = 0; i < count; i++) {
 127                     sb.append(Integer.toString(data[i] & 0xff));
 128                     if (i < count - 1) {
 129                         sb.append(",");
 130                     }
 131                 }
 132                 child.setAttribute("value", sb.toString());
 133             } else {
 134                 child = new IIOMetadataNode("TIFF" +
 135                                             TIFFField.getTypeName(field.getType()) +
 136                                             "s");
 137 
 138                 TIFFTag tag = field.getTag();
 139 
 140                 for (int i = 0; i < count; i++) {
 141                     IIOMetadataNode cchild =
 142                         new IIOMetadataNode("TIFF" +
 143                                             TIFFField.getTypeName(field.getType()));
 144 
 145                     cchild.setAttribute("value", field.getValueAsString(i));
 146                     if (tag.hasValueNames() && field.isIntegral()) {
 147                         int value = field.getAsInt(i);
 148                         String name = tag.getValueName(value);
 149                         if (name != null) {
 150                             cchild.setAttribute("description", name);
 151                         }
 152                     }
 153 
 154                     child.appendChild(cchild);
 155                 }
 156             }
 157             appendChild(child);
 158         }
 159 
 160         isInitialized = Boolean.TRUE;
 161     }
 162 
 163     // Need to override this method to avoid a stack overflow exception
 164     // which will occur if super.appendChild is called from initialize().
 165     public Node appendChild(Node newChild) {
 166         if (newChild == null) {
 167             throw new NullPointerException("newChild == null!");
 168         }
 169 
 170         return super.insertBefore(newChild, null);
 171     }
 172 
 173     // Override all methods which refer to child nodes.
 174 
 175     public boolean hasChildNodes() {
 176         initialize();
 177         return super.hasChildNodes();
 178     }
 179 
 180     public int getLength() {
 181         initialize();
 182         return super.getLength();
 183     }
 184 
 185     public Node getFirstChild() {
 186         initialize();
 187         return super.getFirstChild();
 188     }
 189 
 190     public Node getLastChild() {
 191         initialize();
 192         return super.getLastChild();
 193     }
 194 
 195     public Node getPreviousSibling() {
 196         initialize();
 197         return super.getPreviousSibling();
 198     }
 199 
 200     public Node getNextSibling() {
 201         initialize();
 202         return super.getNextSibling();
 203     }
 204 
 205     public Node insertBefore(Node newChild,
 206                              Node refChild) {
 207         initialize();
 208         return super.insertBefore(newChild, refChild);
 209     }
 210 
 211     public Node replaceChild(Node newChild,
 212                              Node oldChild) {
 213         initialize();
 214         return super.replaceChild(newChild, oldChild);
 215     }
 216 
 217     public Node removeChild(Node oldChild) {
 218         initialize();
 219         return super.removeChild(oldChild);
 220     }
 221 
 222     public Node cloneNode(boolean deep) {
 223         initialize();
 224         return super.cloneNode(deep);
 225     }
 226 }