Kevin Archie avatar Kevin Archie committed 0f221f6

allow tag patterns (in addition to tag literals) as lvalues

Comments (0)

Files changed (19)

   <groupId>org.nrg</groupId>
   <artifactId>DicomEdit</artifactId>
   <packaging>jar</packaging>
-  <version>2.2.2</version>
+  <version>3.0.0</version>
   <name>DicomEdit</name>
   <description>Language for modifying DICOM metadata</description>
   <url>http://nrg.wustl.edu</url>

src/main/antlr3/org/nrg/dcm/edit/EditDCMLexer.g

 
 TAG	:	LPAREN HEXWORD COMMA HEXWORD RPAREN;
 
+TAGPATTERN
+	:	LPAREN HEXPATWORD COMMA HEXPATWORD RPAREN;
+
 fragment LPAREN	:	'(';
 
 fragment RPAREN	:	')';
 fragment HEXWORD
 	:	HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT;
 
-fragment
-HEXDIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
+fragment HEXDIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
+
+fragment HEXPATWORD
+	:	HEXPATTERN HEXPATTERN HEXPATTERN HEXPATTERN;
+	
+fragment HEXPATTERN 
+	:	'X' | '@' | '#' | HEXDIGIT;
+
 
 fragment
 ESC_SEQ

src/main/antlr3/org/nrg/dcm/edit/EditDCMParser.g

 constraint
 	:	(condition CONSTRAINS!)+
 	;
+	
+lvalue	:	TAG | TAGPATTERN;
 		
 assignment
-	:	TAG ASSIGN value -> ^(ASSIGN TAG value)
+	:	lvalue ASSIGN value -> ^(ASSIGN lvalue value)
 	|	TAG ASSIGN NEW ID -> ^(NEW TAG ID)
 	|	TAG ASSIGN NEW ID LEFT termlist RIGHT -> ^(NEW TAG ID termlist)
 	;
 	|	ECHO
 	;
 
-deletion:	DELETE TAG -> ^(DELETE TAG)
+deletion:	DELETE lvalue -> ^(DELETE lvalue)
 	;
 
 initialization

src/main/antlr3/org/nrg/dcm/edit/EditDCMTreeParser.g

     return sb.toString();
   }
 	
-	private static int decodeTag(final CommonTree token) {
-		final StringBuffer hex = new StringBuffer("0x");
-		final String text = token.getText();
-		hex.append(text.substring(1, 5));
-		hex.append(text.substring(6, 10));
-		return Integer.decode(hex.toString()).intValue();
-	}
+  private static TagPattern tagPattern(final CommonTree token) throws RecognitionException {
+    try {
+      return new TagPattern(token.getText().substring(1,10));
+    } catch (ScriptEvaluationException e) {
+      throw new RuntimeException("invalid tag pattern " + token.getText(), e);
+    }
+  }
+	
+  private static int tagLiteral(final CommonTree token) {
+    final StringBuffer hex = new StringBuffer("0x");
+    final String text = token.getText();
+    hex.append(text.substring(1, 5));
+    hex.append(text.substring(6, 10));
+    return Integer.decode(hex.toString()).intValue();
+  }
+        
+
 	
 	private Variable getVariable(final CommonTree token) {
 		return getVariable(token.getText());
 	;
 
 assignment returns [Operation operation]
-	:	^(ASSIGN TAG value) {
-			$operation = new Assignment(decodeTag($TAG), $value.v);
+	:	^(ASSIGN lvalue value) {
+			$operation = new Assignment($lvalue.tp, $value.v);
 		}
 	|	^(NEW TAG ID termlist) {
-			final int tag = decodeTag($TAG);
-			$operation = new Assignment(tag,
-				new GeneratedValue(scope, tag, $ID.getText(), $termlist.tl));
+			$operation = new Assignment(tagPattern($TAG),
+				new GeneratedValue(scope, tagLiteral($TAG), $ID.getText(), $termlist.tl));
 		}
 	;
 	
 	;
 
 deletion returns [Deletion deletion]
-	:	^(DELETE TAG) {
-			$deletion = new Deletion(decodeTag($TAG));
+	:	^(DELETE lvalue) {
+			$deletion = new Deletion($lvalue.tp);
 		}
 	;
 
 term returns [Value v]
 	:	STRING	{ $v = new ConstantValue(extractString($STRING)); }
 	|	NUMBER	{ $v = new IntegerValue($NUMBER.getText()); }
-	|	TAG		{ $v = new SingleTagValue(decodeTag($TAG)); }
+	|	TAG		{ $v = new SingleTagValue(tagLiteral($TAG)); }
 	|	ID		{ $v = new VariableValue(getVariable($ID)); }
 	|	^(FUNCTION ID termlist)	{
 	   		try {
 	:	(t=term { tl.add(t); })*
 	;
 	
+lvalue returns [TagPattern tp] :
+		t=TAG { $tp = tagPattern($TAG); }
+	|	t=TAGPATTERN { $tp = tagPattern($TAGPATTERN); }
+	;
+	
 value returns [Value v]
  	:	t=term { $v = t; }
 	|	^(FORMAT STRING termlist) {

src/main/java/org/nrg/dcm/edit/Action.java

  */
 package org.nrg.dcm.edit;
 
-import java.util.SortedSet;
 
 /**
  * Represents an action to be performed on specific DICOM attributes
  */
 public interface Action {
     /**
-     * @return the tags of the affected attributes
-     */
-    SortedSet<Integer> getTags();
-
-    /**
      * Performs the associated action.
      */
     void apply() throws ScriptEvaluationException;

src/main/java/org/nrg/dcm/edit/Assignment.java

 import org.dcm4che2.util.TagUtils;
 
 import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Sets;
 
 
 /**
  * @author Kevin A. Archie <karchie@wustl.edu>
  */
 public class Assignment extends AbstractOperation {
-    private final int tag;
+    private final TagPattern pattern;
     private final Value value;
 
+    public Assignment(final TagPattern tagpat, final Value value) {
+	super("Assign");
+	this.pattern = tagpat;
+	this.value = value;
+    }
+    
     public Assignment(final int tag, final Value value) {
-        super("Assign");
-        this.tag = tag;
-        this.value = value;
+	this(new TagPattern(tag), value);
     }
 
     public Assignment(final Integer tag, final Value value) {
         this(tag, new ConstantValue(svalue));
     }
 
-    public SortedSet<Integer> getAffectedTags() {
-        return ImmutableSortedSet.of(tag);
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#affects(int)
+     */
+    public boolean affects(final int tag) {
+	return pattern.apply(tag);
     }
-
-    public SortedSet<Integer> getRequiredTags() {
-        return value.getTags();
+    
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#getTopTag()
+     */
+    public int getTopTag() {
+	final SortedSet<Integer> tags = Sets.newTreeSet(value.getTags());
+	tags.add(pattern.getTopTag());
+	return tags.last();
     }
-
+    
     /*
      * (non-Javadoc)
      * @see java.lang.Object#equals(java.lang.Object)
     public boolean equals(Object o) {
         if (o instanceof Assignment) {
             final Assignment oa = (Assignment)o;
-            return tag == oa.tag && value.equals(oa.value);
+            return pattern.equals(oa.pattern) && value.equals(oa.value);
         } else {
             return false;
         }
      * @see java.lang.Object#hashCode()
      */
     public int hashCode() {
-        return Objects.hashCode(Integer.valueOf(tag), value);
+        return Objects.hashCode(pattern, value);
     }
 
     /*
      * (non-Javadoc)
      * @see org.nrg.dcm.edit.Operation#makeAction(org.dcm4che2.data.DicomObject)
      */
-    public Action makeAction(final DicomObject o) throws AttributeException {
-        return new Action() {
-            public void apply() throws ScriptEvaluationException {
-                try {
-                    o.putString(new int[]{tag}, o.vrOf(tag), value.on(o));
-                } catch (UnsupportedOperationException e) {
-                    throw new ScriptEvaluationException("Unable to set attribute "
-                            + TagUtils.toString(tag) + " to \"" + value.on(o) + "\"", e);
-                }
-            }
+    public Action makeAction(final DicomObject o) throws ScriptEvaluationException {
+	final String v = value.on(o);
+	return new Action() {
+	    public void apply() throws ScriptEvaluationException {
+		for (final int tag : pattern.apply(o)) {
+		    try {
+			o.putString(new int[]{tag}, o.vrOf(tag), v);
 
-            public SortedSet<Integer> getTags() {
-                return ImmutableSortedSet.of(tag);
-            }
+		    } catch (UnsupportedOperationException e) {
+			throw new ScriptEvaluationException("Unable to set attribute "
+				+ TagUtils.toString(tag) + " to \"" + v + "\"", e);
+		    }
+		}
 
+	    }
             public String toString() {
                 return MessageFormat.format("{0}: {1} := {2}",
-                        new Object[]{getName(), TagUtils.toString(tag), value});
+                        new Object[]{getName(), pattern, v});
             }
         };
     }
     public String toString() {
         final StringBuffer sb = new StringBuffer(getName());
         sb.append(" ");
-        sb.append(TagUtils.toString(tag));
+        sb.append(pattern);
         String v;
         try {
             v = value.on(new HashMap<Integer,String>());

src/main/java/org/nrg/dcm/edit/Deletion.java

 package org.nrg.dcm.edit;
 
 import java.util.Map;
-import java.util.SortedSet;
 
 import org.dcm4che2.data.DicomObject;
-import org.dcm4che2.util.TagUtils;
-
-import com.google.common.collect.ImmutableSortedSet;
 
 /**
  * @author Kevin A. Archie <karchie@wustl.edu>
  *
  */
 public class Deletion extends AbstractOperation {
-    private final int tag;
+    private final TagPattern pattern;
 
+    public Deletion(final TagPattern pattern) {
+	super("Delete");
+	this.pattern = pattern;
+    }
+    
     public Deletion(final int tag) {
-        super("Delete");
-        this.tag = tag;
+        this(new TagPattern(tag));
     }
 
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#affects(int)
+     */
+    public boolean affects(final int tag) {
+	return pattern.apply(tag);
+    }
+    
     public Action makeAction(final DicomObject o) throws AttributeException {
         return new Action() {
-            public void apply() { o.remove(tag); }
-
-            public SortedSet<Integer> getTags() {
-                return ImmutableSortedSet.of(tag);
+            public void apply() {
+        	for (final int tag : pattern.apply(o)) {
+        	    o.remove(tag);
+        	}
             }
 
-            public String toString() {
-                return getName() + " " + TagUtils.toString(tag);
+             public String toString() {
+                return getName() + " " + pattern;
             }
         };
     }
 
     public String apply(Map<Integer,String> vals) { return null; }
 
-    public SortedSet<Integer> getAffectedTags() {
-        return ImmutableSortedSet.of(tag);
-    }
-
-    public SortedSet<Integer> getRequiredTags() {
-        return ImmutableSortedSet.of();
-    }
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#getTopTag()
+     */
+    public int getTopTag() { return pattern.getTopTag(); }
+    
     /*
      * (non-Javadoc)
      * @see java.lang.Object#toString()
      */
     public String toString() {
-        return "Delete " + TagUtils.toString(tag);
+        return "Delete " + pattern;
     }
 }

src/main/java/org/nrg/dcm/edit/Echo.java

 
 import org.dcm4che2.data.DicomObject;
 
-import com.google.common.collect.ImmutableSortedSet;
-
 
 /**
  * @author Kevin A. Archie <karchie@wustl.edu>
  */
 public final class Echo implements Operation {
-    private static final SortedSet<Integer> EMPTY = ImmutableSortedSet.of();
-
     private final Value v;
 
     public Echo(final String message) {
         this.v = v;
     }
 
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#affects(int)
+     */
+    public boolean affects(final int _) { return false; }
+    
     /* (non-Javadoc)
      * @see org.nrg.dcm.edit.Operation#makeAction(org.dcm4che2.data.DicomObject)
      */
         return new Action() {
             public void apply() { System.out.print(message); }
             public String toString() { return getName() + ": " + message; }
-            public SortedSet<Integer> getTags() { return EMPTY; }
         };
     }
 
     /*
      * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#getTopTag()
+     */
+    public int getTopTag() {
+        final SortedSet<Integer> tags = v.getTags();
+        return tags.isEmpty() ? 0 : tags.last();
+    }
+    
+    /*
+     * (non-Javadoc)
      * @see org.nrg.dcm.edit.Operation#apply(java.util.Map)
      */
     public String apply(final Map<Integer,String> vals) { return null; }
 
-    public SortedSet<Integer> getAffectedTags() { return EMPTY; }
-
-    public SortedSet<Integer> getRequiredTags() { 
-        return v.getTags();
-    }
-
     /*
      * (non-Javadoc)
      * @see java.lang.Object#toString()

src/main/java/org/nrg/dcm/edit/NoOp.java

 package org.nrg.dcm.edit;
 
 import java.util.Map;
-import java.util.SortedSet;
 
 import org.dcm4che2.data.DicomObject;
 
-import com.google.common.collect.ImmutableSortedSet;
-
 /**
  * Null operation
  * @author Kevin A. Archie <karchie@wustl.edu>
  */
 public class NoOp extends AbstractOperation {
-    private static final SortedSet<Integer> EMPTY = ImmutableSortedSet.of();
     private static final String id = "NoOp";
 
     public NoOp() { super(id); }
         return new Action() {
             public void apply() {}
             public String toString() { return id; }
-            public SortedSet<Integer> getTags() { return EMPTY; }
         };
     }
 
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#affects(int)
+     */
+    public boolean affects(final int _) { return false; }
+    
     public String apply(Map<Integer,String> vals) {
         return null;
     }
      */
     public boolean equals(Object o) { return o instanceof NoOp; }
 
-    public SortedSet<Integer> getAffectedTags() { return EMPTY; }
-    public SortedSet<Integer> getRequiredTags() { return EMPTY; }
+    /*
+     * (non-Javadoc)
+     * @see org.nrg.dcm.edit.Operation#getTopTag()
+     */
+    public int getTopTag() { return 0; }
 
     /*
      * (non-Javadoc)

src/main/java/org/nrg/dcm/edit/Operation.java

 package org.nrg.dcm.edit;
 
 import java.util.Map;
-import java.util.SortedSet;
 
 import org.dcm4che2.data.DicomObject;
 
      * @return
      * @throws AttributeException
      */
-    Action makeAction(DicomObject o) throws AttributeException;
+    Action makeAction(DicomObject o) throws AttributeException,ScriptEvaluationException;
 
     /**
      * Compute the value that results from applying this Operation to
      */
     String apply(Map<Integer,String> vals) throws ScriptEvaluationException;
 
+    boolean affects(int tag);
+    
     /**
-     * Retrieves all tags that might be modified by this operation
+     * Maximum tag value potentially required for or modified by this operation.
      * @return
      */
-    SortedSet<Integer> getAffectedTags();
-
-    /**
-     * Retrieves all tags used in constructing a value for this operation.
-     * @return
-     */
-    SortedSet<Integer> getRequiredTags();
+    int getTopTag();
 
     /**
      * Returns the name of this operation

src/main/java/org/nrg/dcm/edit/ScriptApplicator.java

         astParser = null;
     }
 
-    public SortedSet<Integer> getTags() {
+    public int getTopTag() {
         final SortedSet<Integer> tags = Sets.newTreeSet();
-        for (final Variable v : astParser.getVariables().values()) {
-            final Value iv = v.getInitialValue();
-            if (null != iv) {
-                tags.addAll(v.getInitialValue().getTags());
-            }
+        for (final Statement s : statements) {
+            tags.add(s.getTopTag());
         }
-        for (final Statement s : statements) {
-            tags.addAll(s.getAffectedTags());
-            tags.addAll(s.getRequiredTags());
-        }
-        return tags;
+        return tags.last();
     }
-
+    
     public Variable getVariable(final String label) {
         return astParser.getVariable(label);
     }

src/main/java/org/nrg/dcm/edit/Statement.java

 import java.util.List;
 import java.util.SortedSet;
 
+import org.dcm4che2.data.DicomObject;
 import org.nrg.dcm.DicomUtils;
 
-import org.dcm4che2.data.DicomObject;
-
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
         this.c = c;
     }
 
+    public int getTopTag() {
+       final SortedSet<Integer> tags = Sets.newTreeSet();
+       if (null != c) {
+           tags.addAll(c.getTags());
+       }
+       tags.add(op.getTopTag());
+       return tags.last();
+    }
+    
     public boolean isConstrained() { return null != c; }
 
     public boolean matchesConstraint(final File f, final DicomObject o)
         }
         return actions;     
     }
-
-    public SortedSet<Integer> getAffectedTags() {
-        return op.getAffectedTags();
-    }
-
-    public SortedSet<Integer> getRequiredTags() {
-        final SortedSet<Integer> tags = Sets.newTreeSet(op.getRequiredTags());
-        if (null != c) {
-            tags.addAll(c.getTags());
-        }
-        return tags;
-    }
 }

src/main/java/org/nrg/dcm/edit/TagPattern.java

+/**
+ * Copyright (c) 2012 Radiologics, Inc.
+ */
+package org.nrg.dcm.edit;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.dcm4che2.data.DicomElement;
+import org.dcm4che2.data.DicomObject;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+/**
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class TagPattern implements Predicate<Integer>,Function<DicomObject,Iterable<Integer>> {
+    public static final Character ANY_DIGIT = Character.valueOf('X');
+    public static final Character EVEN_DIGIT = Character.valueOf('@');
+    public static final Character ODD_DIGIT = Character.valueOf('#');
+    public static final ImmutableSet<Character> HEX_DIGITS = ImmutableSet.of('0','1','2','3','4','5','6','7','8','9','a','A','b','B','c','C','d','D','e','E','f','F');
+
+    private static final long MASK_ALL = 0xffffffffL, MAX_EVEN = 0xeeeeeeee, MAX_ODD = 0xffffffff;
+    
+    private static boolean matchesMod2(long v, long mask, final int mod2) {
+	while (mask != 0) {
+	    if (0 != (mask & 0xf)) {
+		if ((v & 0xf) % 2 != mod2) {
+		    return false;
+		}
+	    }
+	    v >>= 4;
+	    mask >>= 4;
+	}
+	return true;
+    }
+    
+    private final String pattern;
+    private final long exactMask, anyMask, evenMask, oddMask, exactPart;
+
+    /**
+     * Trivial tag matcher for exact tag value
+     * @param exact tag
+     */
+    public TagPattern(final int exact) {
+	exactMask = MASK_ALL;
+	anyMask = evenMask = oddMask = 0L;
+	exactPart = exact;
+	this.pattern = String.format("0x%08x", exact);
+    }
+    
+    /**
+     * Builds a tag matcher from a tag specification of the form gggg,eeee
+     * For each of the four digits, a hex digit 0-9a-fA-F requires a value match
+     * X indicates any digit is acceptable
+     * @ indicates any even digit is acceptable [02468ace]
+     * # indicates any odd digit is acceptable [13579bdf]
+     * @param spec tag specification
+     */
+    public TagPattern(final String spec) throws ScriptEvaluationException {
+	this.pattern = spec;
+	if (9 != spec.length() || ',' != spec.charAt(4)) {
+	    throw new ScriptEvaluationException("tag must be of form gggg,eeee");
+	}
+	long exact = 0L, any = 0L, even = 0L, odd = 0L, exactPart = 0L;
+	for (int i = 0; i < 9; i++) {
+	    final Character c = spec.charAt(i);
+	    if (c.equals(',')) {
+		if (i != 4) {
+		    throw new ScriptEvaluationException("tag comma at unexpected position " + i);
+		}
+		continue;
+	    }
+	    exact <<= 4;
+	    any <<= 4;
+	    even <<= 4;
+	    odd <<= 4;
+	    exactPart <<= 4;
+	    if (HEX_DIGITS.contains(c)) {
+		exact |= 0xf;
+		exactPart |= Integer.parseInt(String.valueOf(c), 16);
+	    } else if (ANY_DIGIT.equals(c)) {
+		any |= 0xf;
+	    } else if (ODD_DIGIT.equals(c)) {
+		odd |= 0xf;
+	    } else if (EVEN_DIGIT.equals(c)) {
+		even |= 0xf;
+	    } else {
+		throw new ScriptEvaluationException("unrecognized tag digit '" + c + "'");
+	    }
+	}
+	assert (exact | any | even | odd) == MASK_ALL;
+	assert (exact & any) == 0;
+	assert (exact & even) == 0;
+	assert (exact & odd) == 0;
+	assert (any & even) == 0;
+	assert (any & odd) == 0;
+	assert (even & odd) == 0;
+	
+	exactMask = exact;
+	anyMask = any;
+	evenMask = even;
+	oddMask = odd;
+	this.exactPart = exactPart;
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see com.google.common.base.Function#apply(java.lang.Object)
+     */
+    public Iterable<Integer> apply(final DicomObject o) {
+	final List<Integer> tags = Lists.newArrayList();
+	for (final Iterator<DicomElement> ei = o.datasetIterator(); ei.hasNext(); ) {
+	    final Integer tag = ei.next().tag();
+	    if (apply(tag)) {
+		tags.add(tag);
+	    }
+	}
+	if (exactMask == MASK_ALL && !tags.contains((int)exactPart)) {
+	    tags.add((int)exactPart);
+	}
+	return tags;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see com.google.common.base.Predicate#apply(java.lang.Object)
+     */
+    public boolean apply(@Nullable Integer tag) {
+	if (null == tag) {
+	    return false;
+	}
+	final long t = tag & 0xffffffffL;
+	return (t & exactMask) == exactPart
+		&& matchesMod2(t, evenMask, 0)
+		&& matchesMod2(t, oddMask, 1);
+    }
+    
+    /**
+     * Determine the largest tag value this pattern might represent.
+     * @return
+     */
+    public int getTopTag() {
+	return (int)(exactPart | (evenMask & MAX_EVEN) | ((oddMask | anyMask) & MAX_ODD));
+    }
+    
+    /* TODO: hashCode equals */
+    
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+	return "TagPattern " + pattern;
+    }
+}

src/main/java/org/nrg/dcm/io/BatchExporter.java

 
 import java.io.File;
 import java.net.URI;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
             final Iterable<Statement> statements, final Iterator<?> toExport) {
         this.objectExporter = objectExporter;
         this.statements = Lists.newArrayList(statements);
+        Collections.reverse(this.statements);
         this.toExport = toExport;
     }
 

src/test/java/org/nrg/dcm/edit/NoOpTest.java

     public void testMakeAction() throws AttributeException,ScriptEvaluationException {
         final Operation noop = new NoOp();
         final Action noa = noop.makeAction(new BasicDicomObject());
-        assertTrue(noa.getTags().isEmpty());
         noa.apply();    // TODO: make this a mock and verify zero interactions
     }
 
         final Operation noop = new NoOp();
         assertEquals(null, noop.apply(Collections.singletonMap(Tag.StudyInstanceUID, "1.2.3.4")));
     }
-
-    /**
-     * Test method for {@link org.nrg.dcm.edit.NoOp#getAffectedTags()}.
-     */
-    public void testGetAffectedTags() {
-        final Operation noop = new NoOp();
-        assertTrue(noop.getAffectedTags().isEmpty());
-    }
-
-    /**
-     * Test method for {@link org.nrg.dcm.edit.NoOp#getRequiredTags()}.
-     */
-    public void testGetRequiredTags() {
-        final Operation noop = new NoOp();
-        assertTrue(noop.getRequiredTags().isEmpty());
-    }
 }

src/test/java/org/nrg/dcm/edit/ScriptApplicatorTest.java

 import java.io.File;
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Set;
 
 import junit.framework.TestCase;
     private static final String NEW_INSTITUTION = "My Test Institution";
 
     private static final String S_ASSIGN = "(0008,0080) := \"" + NEW_INSTITUTION + "\"\n";
-    private static final Set<Integer> S_ASSIGN_TAGS = Collections.singleton(Integer.valueOf(0x00080080));
     private static final String S_DELETE = "- (0010,0020)\n";
-    private static final Set<Integer> S_DELETE_TAGS = Collections.singleton(Integer.valueOf(0x00100020));
 
     private static final String S_COND_EQ = "(0020,0011) = \"5\" : (0008,103E) := \"Series Five\"\n"
         + "lowercase[(0020,0011)] = \"6\" : (0008,103E) := \"Series Six\"\n"
         final DicomObject do6 = loader.apply(f6);
 
         final ScriptApplicator s_assign = new ScriptApplicator(bytes(S_ASSIGN));
-        assertEquals(S_ASSIGN_TAGS, s_assign.getTags());
         final DicomObject do6_assign = s_assign.apply(f6);
 
         assertEquals(ORIG_INSITUTION, do6.getString(Tag.InstitutionName));
         assertEquals(NEW_INSTITUTION, do6_assign.getString(Tag.InstitutionName));
 
         final ScriptApplicator s_delete = new ScriptApplicator(bytes(S_DELETE));
-        assertEquals(S_DELETE_TAGS, s_delete.getTags());
         final DicomObject do1_delete = s_delete.apply(f6);
 
         assertTrue(do6.contains(0x00100020));
         assertFalse(do1_delete.contains(0x00100020));
 
         final ScriptApplicator s_cond_eq = new ScriptApplicator(bytes(S_COND_EQ));
-        assertEquals(S_COND_EQ_TAGS, s_cond_eq.getTags());
         final DicomObject do4_cond_eq = s_cond_eq.apply(f4);
         final DicomObject do5_cond_eq = s_cond_eq.apply(f5);
         final DicomObject do6_cond_eq = s_cond_eq.apply(f6);

src/test/java/org/nrg/dcm/edit/TagPatternTest.java

+/**
+ * Copyright (c) 2012 Washington University
+ */
+package org.nrg.dcm.edit;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.dcm4che2.data.DicomObject;
+import org.nrg.dcm.DicomUtils;
+
+import com.google.common.collect.Lists;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Kevin A. Archie <karchie@wustl.edu>
+ *
+ */
+public class TagPatternTest extends TestCase {
+    private static final File sampleDir = new File(System.getProperty("sample.data.dir"));
+    private static final File f4 = new File(sampleDir, "1.MR.head_DHead.4.1.20061214.091206.156000.1632817982.dcm.gz");
+
+    public void testExact() {
+	final TagPattern tp = new TagPattern(0x00100020);
+	assertTrue(tp.apply(0x00100020));
+	assertFalse(tp.apply(0x00100000));
+	assertFalse(tp.apply(0x00000020));
+    }
+    
+    public void testApplyInt() throws ScriptEvaluationException {
+	final TagPattern tp1 = new TagPattern("XXX#,XXXX");
+	assertTrue(tp1.apply(0x00010000));
+	assertTrue(tp1.apply(0x00010001));
+	assertFalse(tp1.apply(0x00000000));
+	assertFalse(tp1.apply(0x00000001));
+	
+	final TagPattern tp2 = new TagPattern("001@,XXXX");
+	assertTrue(tp2.apply(0x00101234));
+	assertTrue(tp2.apply(0x00120000));
+	assertTrue(tp2.apply(0x0014ffff));
+	assertTrue(tp2.apply(0x0016fffe));
+	assertTrue(tp2.apply(0x001e0101));
+	assertFalse(tp2.apply(0x00110000));
+	assertFalse(tp2.apply(0x10101234));
+	assertFalse(tp2.apply(0x00200000));
+	
+	final TagPattern tp3 = new TagPattern("FFFC,FFFC");
+	assertTrue(tp3.apply(0xfffcfffc));
+    }
+    
+    public void testApplyToNullInt() throws ScriptEvaluationException {
+	final TagPattern tp = new TagPattern("1234,5678");
+	assertFalse(tp.apply((Integer)null));
+    }
+    
+    public void testApplyDicomObject() throws ScriptEvaluationException,IOException {
+	final DicomObject o = DicomUtils.read(f4);
+	final TagPattern tp1 = new TagPattern("0010,0020");	// extant tag
+	assertEquals(Lists.newArrayList(Integer.valueOf(0x00100020)), tp1.apply(o));
+	
+	final TagPattern tp2 = new TagPattern("0010,0028");	// nonexistent tag
+	assertEquals(Lists.newArrayList(Integer.valueOf(0x00100028)), tp2.apply(o));
+	
+	final TagPattern tp3 = new TagPattern("0010,00@0");	// a few even tags
+	assertEquals(Lists.newArrayList(Integer.valueOf(0x00100020), Integer.valueOf(0x00100040)),
+		tp3.apply(o));
+	
+	final TagPattern tp4 = new TagPattern("0010,00#0");	// a few odd tags
+	assertEquals(Lists.newArrayList(Integer.valueOf(0x00100010), Integer.valueOf(0x00100030)),
+		tp4.apply(o));
+
+    }
+    
+    public void testGetTopTag() throws ScriptEvaluationException {
+	final TagPattern tp1 = new TagPattern("0010,0020");	// exact tag
+	assertEquals(0x00100020, tp1.getTopTag());
+	final TagPattern tp2 = new TagPattern("0010,00@0");	// even tag
+	assertEquals(0x001000e0, tp2.getTopTag());
+	final TagPattern tp3 = new TagPattern("0010,00#0");	// odd tag
+	assertEquals(0x001000f0, tp3.getTopTag());	
+	final TagPattern tp4 = new TagPattern("00X0,00#0");	// any+even tag
+	assertEquals(0x00f000f0, tp4.getTopTag());
+    }
+}

src/test/java/org/nrg/dcm/io/BatchExporterTest.java

     public void testBatchExporterDicomObjectExporterStatementListIterator() {
         final DicomObjectExporter exporter = (DicomObjectExporter) exporterControl.getMock();
         final List<Statement> statements = Lists.newArrayList();
-        final Iterator<File> exports = (Iterator) exportsIteratorControl.getMock();
+        @SuppressWarnings("unchecked")
+	final Iterator<File> exports = (Iterator<File>) exportsIteratorControl.getMock();
         final BatchExporter be = new BatchExporter(exporter, statements, exports);
         assertNotNull(be);
     }
     public void testBatchExporterDicomObjectExporterStatementListCollection() {
         final DicomObjectExporter exporter = (DicomObjectExporter) exporterControl.getMock();
         final List<Statement> statements = Lists.newArrayList();
-        final Iterator<File> exports = (Iterator) exportsIteratorControl.getMock();
+        @SuppressWarnings("unchecked")
+	final Iterator<File> exports = (Iterator<File>) exportsIteratorControl.getMock();
         final BatchExporter be = new BatchExporter(exporter, statements, exports);
         assertNotNull(be);
     }
     public void testSetProgressMonitor() {
         final DicomObjectExporter exporter = (DicomObjectExporter) exporterControl.getMock();
         final List<Statement> statements = Lists.newArrayList();
-        final Iterator<File> exports = (Iterator) exportsIteratorControl.getMock();
+        @SuppressWarnings("unchecked")
+	final Iterator<File> exports = (Iterator<File>) exportsIteratorControl.getMock();
         final BatchExporter be = new BatchExporter(exporter, statements, exports);
         final EditProgressMonitor pm = (EditProgressMonitor) progressMonitorControl.getMock();
         be.setProgressMonitor(pm, 0);
     public void testIsPending() {
         final DicomObjectExporter exporter = (DicomObjectExporter) exporterControl.getMock();
         final List<Statement> statements = Lists.newArrayList();
-        final Iterator<File> exports = (Iterator) exportsIteratorControl.getMock();
+        @SuppressWarnings("unchecked")
+	final Iterator<File> exports = (Iterator<File>) exportsIteratorControl.getMock();
         final BatchExporter be = new BatchExporter(exporter, statements, exports);
         assertTrue(be.isPending());
         be.run();
     public void testGetFailures() {
         final DicomObjectExporter exporter = (DicomObjectExporter) exporterControl.getMock();
         final List<Statement> statements = Lists.newArrayList();
-        final Iterator<File> exports = (Iterator) exportsIteratorControl.getMock();
+        @SuppressWarnings("unchecked")
+	final Iterator<File> exports = (Iterator<File>) exportsIteratorControl.getMock();
         final BatchExporter be = new BatchExporter(exporter, statements, exports);
         try {
             be.getFailures();
     public void testGetProgress() {
         final DicomObjectExporter exporter = (DicomObjectExporter) exporterControl.getMock();
         final List<Statement> statements = Lists.newArrayList();
-        final Iterator<File> exports = (Iterator) exportsIteratorControl.getMock();
+        @SuppressWarnings("unchecked")
+	final Iterator<File> exports = (Iterator<File>) exportsIteratorControl.getMock();
         final BatchExporter be = new BatchExporter(exporter, statements, exports);
         final EditProgressMonitor pm = (EditProgressMonitor) progressMonitorControl.getMock();
         be.setProgressMonitor(pm, 0);

src/test/java/org/nrg/util/GraphUtilsTest.java

  * @author Kevin A. Archie <karchie@npg.wustl.edu>
  *
  */
+@SuppressWarnings({ "rawtypes", "unchecked" })
 public class GraphUtilsTest extends TestCase {
     private final List asMutableList(final Object[] a) {
 	return new ArrayList(Arrays.asList(a));
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.