001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in 015 * Java(TM), hosted at https://github.com/gunterze/dcm4che. 016 * 017 * The Initial Developer of the Original Code is 018 * Agfa Healthcare. 019 * Portions created by the Initial Developer are Copyright (C) 2011 020 * the Initial Developer. All Rights Reserved. 021 * 022 * Contributor(s): 023 * See @authors listed below 024 * 025 * Alternatively, the contents of this file may be used under the terms of 026 * either the GNU General Public License Version 2 or later (the "GPL"), or 027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 028 * in which case the provisions of the GPL or the LGPL are applicable instead 029 * of those above. If you wish to allow use of your version of this file only 030 * under the terms of either the GPL or the LGPL, and not to allow others to 031 * use your version of this file under the terms of the MPL, indicate your 032 * decision by deleting the provisions above and replace them with the notice 033 * and other provisions required by the GPL or the LGPL. If you do not delete 034 * the provisions above, a recipient may use your version of this file under 035 * the terms of any one of the MPL, the GPL or the LGPL. 036 * 037 * ***** END LICENSE BLOCK ***** */ 038 039package org.dcm4che3.tool.dcmdump; 040 041import java.io.File; 042import java.io.IOException; 043import java.text.MessageFormat; 044import java.util.List; 045import java.util.ResourceBundle; 046 047import org.apache.commons.cli.CommandLine; 048import org.apache.commons.cli.OptionBuilder; 049import org.apache.commons.cli.Options; 050import org.apache.commons.cli.ParseException; 051import org.dcm4che3.data.Tag; 052import org.dcm4che3.data.Attributes; 053import org.dcm4che3.data.ElementDictionary; 054import org.dcm4che3.data.Fragments; 055import org.dcm4che3.data.Sequence; 056import org.dcm4che3.data.VR; 057import org.dcm4che3.io.DicomInputHandler; 058import org.dcm4che3.io.DicomInputStream; 059import org.dcm4che3.tool.common.CLIUtils; 060import org.dcm4che3.util.TagUtils; 061 062/** 063 * @author Gunter Zeilinger <gunterze@gmail.com> 064 */ 065public class DcmDump implements DicomInputHandler { 066 067 private static ResourceBundle rb = 068 ResourceBundle.getBundle("org.dcm4che3.tool.dcmdump.messages"); 069 070 /** default number of characters per line */ 071 private static final int DEFAULT_WIDTH = 78; 072 073 private int width = DEFAULT_WIDTH; 074 075 public final int getWidth() { 076 return width; 077 } 078 079 public final void setWidth(int width) { 080 if (width < 40) 081 throw new IllegalArgumentException(); 082 this.width = width; 083 } 084 085 public void parse(DicomInputStream dis) throws IOException { 086 dis.setDicomInputHandler(this); 087 dis.readDataset(-1, -1); 088 } 089 090 @Override 091 public void startDataset(DicomInputStream dis) throws IOException { 092 promptPreamble(dis.getPreamble()); 093 } 094 095 @Override 096 public void endDataset(DicomInputStream dis) throws IOException { 097 } 098 099 @Override 100 public void readValue(DicomInputStream dis, Attributes attrs) 101 throws IOException { 102 StringBuilder line = new StringBuilder(width + 30); 103 appendPrefix(dis, line); 104 appendHeader(dis, line); 105 VR vr = dis.vr(); 106 int vallen = dis.length(); 107 boolean undeflen = vallen == -1; 108 if (vr == VR.SQ || undeflen) { 109 appendKeyword(dis, line); 110 System.out.println(line); 111 dis.readValue(dis, attrs); 112 if (undeflen) { 113 line.setLength(0); 114 appendPrefix(dis, line); 115 appendHeader(dis, line); 116 appendKeyword(dis, line); 117 System.out.println(line); 118 } 119 return; 120 } 121 int tag = dis.tag(); 122 byte[] b = dis.readValue(); 123 line.append(" ["); 124 if (vr.prompt(b, dis.bigEndian(), 125 attrs.getSpecificCharacterSet(), 126 width - line.length() - 1, line)) { 127 line.append(']'); 128 appendKeyword(dis, line); 129 } 130 System.out.println(line); 131 if (tag == Tag.FileMetaInformationGroupLength) 132 dis.setFileMetaInformationGroupLength(b); 133 else if (tag == Tag.TransferSyntaxUID 134 || tag == Tag.SpecificCharacterSet 135 || TagUtils.isPrivateCreator(tag)) 136 attrs.setBytes(tag, vr, b); 137 } 138 139 @Override 140 public void readValue(DicomInputStream dis, Sequence seq) 141 throws IOException { 142 StringBuilder line = new StringBuilder(width); 143 appendPrefix(dis, line); 144 appendHeader(dis, line); 145 appendKeyword(dis, line); 146 appendNumber(seq.size() + 1, line); 147 System.out.println(line); 148 boolean undeflen = dis.length() == -1; 149 dis.readValue(dis, seq); 150 if (undeflen) { 151 line.setLength(0); 152 appendPrefix(dis, line); 153 appendHeader(dis, line); 154 appendKeyword(dis, line); 155 System.out.println(line); 156 } 157 } 158 159 @Override 160 public void readValue(DicomInputStream dis, Fragments frags) 161 throws IOException { 162 StringBuilder line = new StringBuilder(width + 20); 163 appendPrefix(dis, line); 164 appendHeader(dis, line); 165 appendFragment(line, dis, frags.vr()); 166 System.out.println(line); 167 } 168 169 private void appendPrefix(DicomInputStream dis, StringBuilder line) { 170 line.append(dis.getTagPosition()).append(": "); 171 int level = dis.level(); 172 while (level-- > 0) 173 line.append('>'); 174 } 175 176 private void appendHeader(DicomInputStream dis, StringBuilder line) { 177 line.append(TagUtils.toString(dis.tag())).append(' '); 178 VR vr = dis.vr(); 179 if (vr != null) 180 line.append(vr).append(' '); 181 line.append('#').append(dis.length()); 182 } 183 184 private void appendKeyword(DicomInputStream dis, StringBuilder line) { 185 if (line.length() < width) { 186 line.append(" "); 187 line.append(ElementDictionary.keywordOf(dis.tag(), null)); 188 if (line.length() > width) 189 line.setLength(width); 190 } 191 } 192 193 private void appendNumber(int number, StringBuilder line) { 194 if (line.length() < width) { 195 line.append(" #"); 196 line.append(number); 197 if (line.length() > width) 198 line.setLength(width); 199 } 200 } 201 202 private void appendFragment(StringBuilder line, DicomInputStream dis, 203 VR vr) throws IOException { 204 byte[] b = dis.readValue(); 205 line.append(" ["); 206 if (vr.prompt(b, dis.bigEndian(), null, 207 width - line.length() - 1, line)) { 208 line.append(']'); 209 appendKeyword(dis, line); 210 } 211 } 212 213 private void promptPreamble(byte[] preamble) { 214 if (preamble == null) 215 return; 216 217 StringBuilder line = new StringBuilder(width); 218 line.append("0: ["); 219 if (VR.OB.prompt(preamble, false, null, width - 5, line)) 220 line.append(']'); 221 System.out.println(line); 222 } 223 224 @SuppressWarnings("unchecked") 225 public static void main(String[] args) { 226 try { 227 CommandLine cl = parseComandLine(args); 228 DcmDump main = new DcmDump(); 229 if (cl.hasOption("w")) { 230 String s = cl.getOptionValue("w"); 231 try { 232 main.setWidth(Integer.parseInt(s)); 233 } catch (IllegalArgumentException e) { 234 throw new ParseException(MessageFormat.format( 235 rb.getString("illegal-width"), s)); 236 } 237 } 238 String fname = fname(cl.getArgList()); 239 if (fname.equals("-")) { 240 main.parse(new DicomInputStream(System.in)); 241 } else { 242 DicomInputStream dis = 243 new DicomInputStream(new File(fname)); 244 try { 245 main.parse(dis); 246 } finally { 247 dis.close(); 248 } 249 } 250 } catch (ParseException e) { 251 System.err.println("dcmdump: " + e.getMessage()); 252 System.err.println(rb.getString("try")); 253 System.exit(2); 254 } catch (IOException e) { 255 System.err.println("dcmdump: " + e.getMessage()); 256 System.exit(2); 257 } 258 } 259 260 private static String fname(List<String> argList) throws ParseException { 261 int numArgs = argList.size(); 262 if (numArgs == 0) 263 throw new ParseException(rb.getString("missing")); 264 if (numArgs > 1) 265 throw new ParseException(rb.getString("too-many")); 266 return argList.get(0); 267 } 268 269 @SuppressWarnings("static-access") 270 private static CommandLine parseComandLine(String[] args) 271 throws ParseException{ 272 Options opts = new Options(); 273 CLIUtils.addCommonOptions(opts); 274 opts.addOption(OptionBuilder 275 .withLongOpt("width") 276 .hasArg() 277 .withArgName("col") 278 .withDescription(rb.getString("width")) 279 .create("w")); 280 return CLIUtils.parseComandLine(args, opts, rb, DcmDump.class); 281 } 282 283}