Skip to content

Commit

Permalink
Merge 2bcec5c into 526f03f
Browse files Browse the repository at this point in the history
  • Loading branch information
karl-exini committed Oct 12, 2020
2 parents 526f03f + 2bcec5c commit d926f89
Show file tree
Hide file tree
Showing 15 changed files with 502 additions and 219 deletions.
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ resolvers ++= Seq(
// deps

libraryDependencies ++= {
val akkaVersion = "2.6.6"
val akkaVersion = "2.6.9"
Seq(
"org.scala-lang.modules" %% "scala-xml" % "1.3.0",
"com.typesafe.akka" %% "akka-stream" % akkaVersion,
"com.typesafe.akka" %% "akka-slf4j" % akkaVersion,
"org.slf4j" % "slf4j-simple" % "1.7.30",
"com.beachape" %% "enumeratum" % "1.6.1",
"org.scalatest" %% "scalatest" % "3.2.0" % "test",
"org.scalatest" %% "scalatest" % "3.2.2" % "test",
"com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % "test"
)
}
Expand Down
4 changes: 2 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ resolvers += Resolver.typesafeRepo("releases")

resolvers += Classpaths.typesafeReleases

addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.0")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0")
addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.6.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7")
Expand Down
6 changes: 4 additions & 2 deletions src/main/scala/com/exini/dicom/data/Elements.scala
Original file line number Diff line number Diff line change
Expand Up @@ -802,15 +802,17 @@ case class Elements(characterSets: CharacterSets, zoneOffset: ZoneOffset, data:
val s = strings.mkString(multiValueDelimiter)
val vm = strings.length.toString
s"$indent${tagToString(e.tag)} ${e.vr} [$s] ${space1(s)} # ${space2(e.length)} ${e.length}, $vm ${Lookup
.keywordOf(e.tag)}" :: Nil
.keywordOf(e.tag)
.getOrElse("")}" :: Nil

case s: Sequence =>
val heading = {
val description =
if (s.length == indeterminateLength) "Sequence with indeterminate length"
else s"Sequence with explicit length ${s.length}"
s"$indent${tagToString(s.tag)} SQ ($description) ${space1(description)} # ${space2(s.length)} ${s.length}, 1 ${Lookup
.keywordOf(s.tag)}"
.keywordOf(s.tag)
.getOrElse("")}"
}
val items = s.items.flatMap { i =>
val heading = {
Expand Down
27 changes: 19 additions & 8 deletions src/main/scala/com/exini/dicom/data/ElementsBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,17 @@ class ElementsBuilder() {
def +=(element: Element): ElementsBuilder =
element match {

case PreambleElement if builderStack.length == 1 && builderStack.head.isEmpty =>
this

case e: ValueElement =>
subtractLength(e.length + e.vr.headerLength)
subtractLength(e.length + (if (e.explicitVR) e.vr.headerLength else 8))
val builder = builderStack.head
builder += e
maybeDelimit()

case e: FragmentsElement =>
subtractLength(e.vr.headerLength)
subtractLength(if (e.explicitVR) e.vr.headerLength else 8)
updateFragments(Some(Fragments.empty(e.tag, e.vr, e.bigEndian, e.explicitVR)))
maybeDelimit()

Expand All @@ -67,7 +70,7 @@ class ElementsBuilder() {
maybeDelimit()

case e: SequenceElement =>
subtractLength(12)
subtractLength(if (e.explicitVR) 12 else 8)
if (!e.indeterminate)
pushLength(e, e.length)
pushSequence(Sequence.empty(e.tag, if (e.indeterminate) e.length else 0, e.bigEndian, e.explicitVR))
Expand All @@ -85,11 +88,15 @@ class ElementsBuilder() {

case _: ItemDelimitationElement if hasSequence =>
subtractLength(8)
if (!itemIsIndeterminate && lengthStack.nonEmpty)
lengthStack = lengthStack.tail // determinate length item with delimitation - handle gracefully
endItem()
maybeDelimit()

case _: SequenceDelimitationElement if hasSequence =>
subtractLength(8)
if (!sequenceIsIndeterminate && lengthStack.nonEmpty)
lengthStack = lengthStack.tail // determinate length sequence with delimitation - handle gracefully
endSequence()
maybeDelimit()

Expand Down Expand Up @@ -127,10 +134,12 @@ class ElementsBuilder() {
private def pushSequence(sequence: Sequence): Unit = sequenceStack = sequence :: sequenceStack
private def pushLength(element: Element, length: Long): Unit =
lengthStack = ElementAndLength(element, length) :: lengthStack
private def popBuilder(): Unit = builderStack = builderStack.tail
private def popSequence(): Unit = sequenceStack = sequenceStack.tail
private def hasSequence: Boolean = sequenceStack.nonEmpty
private def hasFragments: Boolean = fragments.isDefined
private def popBuilder(): Unit = builderStack = builderStack.tail
private def popSequence(): Unit = sequenceStack = sequenceStack.tail
private def hasSequence: Boolean = sequenceStack.nonEmpty
private def hasFragments: Boolean = fragments.isDefined
private def sequenceIsIndeterminate: Boolean = sequenceStack.headOption.exists(_.indeterminate)
private def itemIsIndeterminate: Boolean = sequenceStack.headOption.exists(_.items.lastOption.exists(_.indeterminate))
private def endItem(): Unit = {
val builder = builderStack.head
val sequence = sequenceStack.head
Expand All @@ -144,7 +153,7 @@ class ElementsBuilder() {
}
private def endSequence(): Unit = {
val seq = sequenceStack.head
val seqLength = if (seq.indeterminate) seq.length else seq.toBytes.length - 12
val seqLength = if (seq.indeterminate) seq.length else seq.toBytes.length - (if (seq.explicitVR) 12 else 8)
val updatedSeq = new Sequence(seq.tag, seqLength, seq.items, seq.bigEndian, seq.explicitVR)
val builder = builderStack.head
builder += updatedSeq
Expand Down Expand Up @@ -180,4 +189,6 @@ class DatasetBuilder(var characterSets: CharacterSets, var zoneOffset: ZoneOffse
}

def build(): Elements = new Elements(characterSets, zoneOffset, data.toVector)

def isEmpty: Boolean = data.isEmpty
}
4 changes: 0 additions & 4 deletions src/main/scala/com/exini/dicom/streams/CollectFlow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,9 @@ object CollectFlow {
case item: ItemPart =>
maybeAdd(ItemElement(item.index, item.length, item.bigEndian))
Nil
case _: ItemDelimitationPartMarker =>
Nil
case itemDelimitation: ItemDelimitationPart =>
maybeAdd(ItemDelimitationElement(itemDelimitation.index, itemDelimitation.bigEndian))
Nil
case SequenceDelimitationPartMarker =>
Nil
case sequenceDelimitation: SequenceDelimitationPart =>
maybeAdd(SequenceDelimitationElement(sequenceDelimitation.bigEndian))
Nil
Expand Down
57 changes: 29 additions & 28 deletions src/main/scala/com/exini/dicom/streams/DicomFlow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -202,17 +202,18 @@ trait InFragments[Out] extends DicomFlow[Out] {
trait InSequence[Out] extends DicomFlow[Out] with GuaranteedDelimitationEvents[Out] {

trait InSequenceLogic extends DicomLogic with GuaranteedDelimitationEventsLogic {
protected var sequenceDepth = 0
protected var sequenceStack: List[SequencePart] = Nil

def inSequence: Boolean = sequenceDepth > 0
def inSequence: Boolean = sequenceStack.nonEmpty
def sequenceDepth: Int = sequenceStack.size

abstract override def onSequence(part: SequencePart): List[Out] = {
sequenceDepth += 1
sequenceStack = part :: sequenceStack
super.onSequence(part)
}

abstract override def onSequenceDelimitation(part: SequenceDelimitationPart): List[Out] = {
sequenceDepth -= 1
sequenceStack = sequenceStack.tail
super.onSequenceDelimitation(part)
}
}
Expand Down Expand Up @@ -260,50 +261,50 @@ trait GuaranteedDelimitationEvents[Out] extends DicomFlow[Out] with InFragments[
protected var partStack: List[(LengthPart, Long)] = Nil

def subtractLength(part: DicomPart): List[(LengthPart, Long)] =
partStack.map { case (p, bytesLeft) => (p, bytesLeft - part.bytes.length) }
partStack
.map { case (p, bytesLeft) => if (p.indeterminate) (p, bytesLeft) else (p, bytesLeft - part.bytes.length) }

def maybeDelimit(): List[Out] = {
val delimits: List[DicomPart] = partStack
.filter(_._2 <= 0) // find items and sequences that have ended
.map { // create delimiters for those
case (item: ItemPart, _) => new ItemDelimitationPartMarker(item.index)
case (_, _) => SequenceDelimitationPartMarker
}
partStack = partStack.filter(_._2 > 0) // only keep items and sequences with bytes left to subtract
delimits.flatMap { // call events, any items will be inserted in stream
case d: SequenceDelimitationPart => onSequenceDelimitation(d)
case d: ItemDelimitationPart => onItemDelimitation(d)
val (inactive, active) = partStack.span { case (p, b) => !p.indeterminate && b <= 0 }
partStack = active // only keep items and sequences with bytes left to subtract
inactive.flatMap { // call events, any items will be inserted in stream
case (item: ItemPart, _) => onItemDelimitation(new ItemDelimitationPartMarker(item.index))
case _ => onSequenceDelimitation(SequenceDelimitationPartMarker)
}
}

def subtractAndEmit[A <: DicomPart](part: A, handle: A => List[Out]): List[Out] = {
def subtractAndEmit[A <: DicomPart](part: A, handle: A => List[Out], isDelimit: Boolean = false): List[Out] = {
partStack = subtractLength(part)
handle(part) ::: maybeDelimit()
}

abstract override def onSequence(part: SequencePart): List[Out] =
if (!part.indeterminate) {
partStack = (part, part.length) +: subtractLength(part)
super.onSequence(part) ::: maybeDelimit()
} else subtractAndEmit(part, super.onSequence)
abstract override def onSequence(part: SequencePart): List[Out] = {
partStack = (part, part.length) :: subtractLength(part)
super.onSequence(part) ::: maybeDelimit()
}

abstract override def onItem(part: ItemPart): List[Out] =
if (!inFragments && !part.indeterminate) {
partStack = (part, part.length) +: subtractLength(part)
super.onItem(part) ::: maybeDelimit()
} else subtractAndEmit(part, super.onItem)
abstract override def onItem(part: ItemPart): List[Out] = {
partStack = if (!inFragments) (part, part.length) :: subtractLength(part) else subtractLength(part)
super.onItem(part) ::: maybeDelimit()
}

abstract override def onSequenceDelimitation(part: SequenceDelimitationPart): List[Out] =
abstract override def onSequenceDelimitation(part: SequenceDelimitationPart): List[Out] = {
if (partStack.nonEmpty && part != SequenceDelimitationPartMarker && !inFragments)
partStack = partStack.tail
subtractAndEmit(
part,
(p: SequenceDelimitationPart) => super.onSequenceDelimitation(p).filterNot(_ == SequenceDelimitationPartMarker)
)
}

abstract override def onItemDelimitation(part: ItemDelimitationPart): List[Out] =
abstract override def onItemDelimitation(part: ItemDelimitationPart): List[Out] = {
if (partStack.nonEmpty && !part.isInstanceOf[ItemDelimitationPartMarker])
partStack = partStack.tail
subtractAndEmit(
part,
(p: ItemDelimitationPart) => super.onItemDelimitation(p).filterNot(_.isInstanceOf[ItemDelimitationPartMarker])
)
}

abstract override def onHeader(part: HeaderPart): List[Out] = subtractAndEmit(part, super.onHeader)
abstract override def onValueChunk(part: ValueChunk): List[Out] = subtractAndEmit(part, super.onValueChunk)
Expand Down

0 comments on commit d926f89

Please sign in to comment.