/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is part of dcm4che, an implementation of DICOM(TM) in * Java(TM), hosted at https://github.com/gunterze/dcm4che. * * The Initial Developer of the Original Code is * Agfa Healthcare. * Portions created by the Initial Developer are Copyright (C) 2012 * the Initial Developer. All Rights Reserved. * * Contributor(s): * See @authors listed below * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ package org.dcm4che3.data; import java.util.ArrayList; import java.util.List; import org.dcm4che3.data.IOD.DataElement; import org.dcm4che3.util.ByteUtils; import org.dcm4che3.util.StringUtils; import org.dcm4che3.util.TagUtils; /** * @author Gunter Zeilinger <gunterze@gmail.com> * */ public class ValidationResult { public enum Invalid { VR, VM, Value, Item, MultipleItems, Code } public class InvalidAttributeValue { public final IOD.DataElement dataElement; public final Invalid reason; public final ValidationResult[] itemValidationResults; public final IOD[] missingItems; public InvalidAttributeValue(DataElement dataElement, Invalid reason, ValidationResult[] itemValidationResults, IOD[] missingItems) { this.dataElement = dataElement; this.reason = reason; this.itemValidationResults = itemValidationResults; this.missingItems = missingItems; } } private ArrayList<IOD.DataElement> missingAttributes; private ArrayList<IOD.DataElement> missingAttributeValues; private ArrayList<IOD.DataElement> notAllowedAttributes; private ArrayList<InvalidAttributeValue> invalidAttributeValues; public boolean hasMissingAttributes() { return missingAttributes != null; } public boolean hasMissingAttributeValues() { return missingAttributeValues != null; } public boolean hasInvalidAttributeValues() { return invalidAttributeValues != null; } public boolean hasNotAllowedAttributes() { return notAllowedAttributes != null; } public boolean isValid() { return !hasMissingAttributes() && !hasMissingAttributeValues() && !hasInvalidAttributeValues() && !hasNotAllowedAttributes(); } public void addMissingAttribute(IOD.DataElement dataElement) { if (missingAttributes == null) missingAttributes = new ArrayList<IOD.DataElement>(); missingAttributes.add(dataElement); } public void addMissingAttributeValue(IOD.DataElement dataElement) { if (missingAttributeValues == null) missingAttributeValues = new ArrayList<IOD.DataElement>(); missingAttributeValues.add(dataElement); } public void addInvalidAttributeValue(IOD.DataElement dataElement, Invalid reason) { addInvalidAttributeValue(dataElement, reason, null, null); } public void addInvalidAttributeValue(IOD.DataElement dataElement, Invalid reason, ValidationResult[] itemValidationResult, IOD[] missingItems) { if (invalidAttributeValues == null) invalidAttributeValues = new ArrayList<InvalidAttributeValue>(); invalidAttributeValues.add( new InvalidAttributeValue(dataElement, reason, itemValidationResult, missingItems)); } public void addNotAllowedAttribute(DataElement el) { if (notAllowedAttributes == null) notAllowedAttributes = new ArrayList<IOD.DataElement>(); notAllowedAttributes.add(el); } public int[] tagsOfNotAllowedAttributes() { return tagsOf(notAllowedAttributes); } public int[] tagsOfMissingAttributeValues() { return tagsOf(missingAttributeValues); } public int[] tagsOfMissingAttributes() { return tagsOf(missingAttributes); } public int[] tagsOfInvalidAttributeValues() { ArrayList<InvalidAttributeValue> list = invalidAttributeValues; if (list == null) return ByteUtils.EMPTY_INTS; int[] tags = new int[list.size()]; for (int i = 0; i < tags.length; i++) tags[i] = list.get(i).dataElement.tag; return tags; } public int[] getOffendingElements() { return cat(tagsOfMissingAttributes(), tagsOfMissingAttributeValues(), tagsOfInvalidAttributeValues(), tagsOfNotAllowedAttributes()); } private int[] cat(int[]... iss) { int length = 0; for (int[] is : iss) length += is.length; int[] tags = new int[length]; int off = 0; for (int[] is : iss) { System.arraycopy(is, 0, tags, off, is.length); off += is.length; } return tags; } private int[] tagsOf(List<DataElement> list) { if (list == null) return ByteUtils.EMPTY_INTS; int[] tags = new int[list.size()]; for (int i = 0; i < tags.length; i++) tags[i] = list.get(i).tag; return tags; } public String getErrorComment() { StringBuilder sb = new StringBuilder(); if (notAllowedAttributes != null) return errorComment(sb, "Not allowed Attribute", tagsOfNotAllowedAttributes()).toString(); if (missingAttributes != null) return errorComment(sb, "Missing Attribute", tagsOfMissingAttributes()).toString(); if (missingAttributeValues != null) return errorComment(sb, "Missing Value of Attribute", tagsOfMissingAttributeValues()).toString(); if (invalidAttributeValues != null) return errorComment(sb, "Invalid Attribute", tagsOfInvalidAttributeValues()).toString(); return null; } private static StringBuilder errorComment(StringBuilder sb, String prompt, int[] tags) { sb.append(prompt); String prefix = tags.length > 1 ? "s: " : ": "; for (int tag : tags) { sb.append(prefix).append(TagUtils.toString(tag)); prefix = ", "; } return sb; } @Override public String toString() { if (isValid()) return "VALID"; StringBuilder sb = new StringBuilder(); if (notAllowedAttributes != null) errorComment(sb, "Not allowed Attribute", tagsOfNotAllowedAttributes()).append(StringUtils.LINE_SEPARATOR); if (missingAttributes != null) errorComment(sb, "Missing Attribute", tagsOfMissingAttributes()).append(StringUtils.LINE_SEPARATOR); if (missingAttributeValues != null) errorComment(sb, "Missing Value of Attribute", tagsOfMissingAttributeValues()).append(StringUtils.LINE_SEPARATOR); if (invalidAttributeValues != null) errorComment(sb, "Invalid Attribute", tagsOfInvalidAttributeValues()).append(StringUtils.LINE_SEPARATOR); return sb.substring(0, sb.length()-1); } public String asText(Attributes attrs) { if (isValid()) return "VALID"; StringBuilder sb = new StringBuilder(); appendTextTo(0, attrs, sb); return sb.substring(0, sb.length()-1); } private void appendTextTo(int level, Attributes attrs, StringBuilder sb) { if (notAllowedAttributes != null) appendTextTo(level, attrs, "Not allowed Attributes:", notAllowedAttributes, sb); if (missingAttributes != null) appendTextTo(level, attrs, "Missing Attributes:", missingAttributes, sb); if (missingAttributeValues != null) appendTextTo(level, attrs, "Missing Attribute Values:", missingAttributeValues, sb); if (invalidAttributeValues != null) appendInvalidAttributeValues(level, attrs, "Invalid Attribute Values:", sb); } private void appendTextTo(int level, Attributes attrs, String title, List<DataElement> list, StringBuilder sb) { appendPrefixTo(level, sb); sb.append(title).append(StringUtils.LINE_SEPARATOR); for (DataElement el : list) { appendAttribute(level, el.tag, sb); appendIODRef(el.getLineNumber(), sb); sb.append(StringUtils.LINE_SEPARATOR); } } private void appendIODRef(int lineNumber, StringBuilder sb) { if (lineNumber > 0) sb.append(" // IOD line #").append(lineNumber); } private void appendInvalidAttributeValues(int level, Attributes attrs, String title, StringBuilder sb) { appendPrefixTo(level, sb); sb.append(title); sb.append(StringUtils.LINE_SEPARATOR); for (InvalidAttributeValue iav : invalidAttributeValues) { int tag = iav.dataElement.tag; appendAttribute(level, tag, sb); VR.Holder vr = new VR.Holder(); Object value = attrs.getValue(tag, vr); sb.append(' ').append(vr.vr); sb.append(" ["); vr.vr.prompt(value, attrs.bigEndian(), attrs.getSpecificCharacterSet(vr.vr), 200, sb); sb.append(']'); if (iav.reason != Invalid.Item) { sb.append(" Invalid ").append(iav.reason); appendIODRef(iav.dataElement.getLineNumber(), sb); } sb.append(StringUtils.LINE_SEPARATOR); if (iav.missingItems != null) { for (IOD iod : iav.missingItems) { appendPrefixTo(level+1, sb); sb.append("Missing Item"); appendIODRef(iod.getLineNumber(), sb); sb.append(StringUtils.LINE_SEPARATOR); } } if (iav.itemValidationResults != null) { Sequence seq = (Sequence) value; for (int i = 0; i < iav.itemValidationResults.length; i++) { ValidationResult itemResult = iav.itemValidationResults[i]; if (!itemResult.isValid()) { appendPrefixTo(level+1, sb); sb.append("Invalid Item ").append(i+1).append(':') .append(StringUtils.LINE_SEPARATOR); itemResult.appendTextTo(level+1, seq.get(i), sb); } } } } } private void appendAttribute(int level, int tag, StringBuilder sb) { appendPrefixTo(level, sb); sb.append(TagUtils.toString(tag)) .append(' ') .append(ElementDictionary.keywordOf(tag, null)); } private void appendPrefixTo(int level, StringBuilder sb) { while (level-- > 0) sb.append('>'); } }