diff --git a/core/src/main/scala/com/eed3si9n/jarjarabrams/scalasig/ScalaSigAnnotationVisitor.scala b/core/src/main/scala/com/eed3si9n/jarjarabrams/scalasig/ScalaSigAnnotationVisitor.scala index bdc262c..ad2b511 100644 --- a/core/src/main/scala/com/eed3si9n/jarjarabrams/scalasig/ScalaSigAnnotationVisitor.scala +++ b/core/src/main/scala/com/eed3si9n/jarjarabrams/scalasig/ScalaSigAnnotationVisitor.scala @@ -24,6 +24,7 @@ class ScalaSigAnnotationVisitor( cv: ClassVisitor, renamer: String => Option[String] ) extends AnnotationVisitor(Opcodes.ASM7) { + import ScalaSigAnnotationVisitor._ private val MaxStringSizeInBytes = 65535 private val annotationBytes: ByteArrayOutputStream = new ByteArrayOutputStream() @@ -65,32 +66,15 @@ class ScalaSigAnnotationVisitor( // Encode as ScalaLongSignature containing an array of strings val av = cv.visitAnnotation("Lscala/reflect/ScalaLongSignature;", visible) - def nextChunk(from: Int): Array[Char] = { - if (from == chars.length) { - Array.empty - } else { - var size = 0 - var index = 0 - - while (size < MaxStringSizeInBytes && from + index < chars.length) { - val c = chars(from + index) - size += (if (c == 0) 2 else 1) - index += 1 - } - - chars.slice(from, from + index) - } - } - // Write the array of strings as chunks of max MaxStringSizeInBytes bytes val arrayVisitor = av.visitArray("bytes") var offset = 0 - var chunk = nextChunk(offset) + var chunk = nextChunk(chars, offset, MaxStringSizeInBytes) while (chunk.nonEmpty) { arrayVisitor.visit("bytes", new String(chunk)) offset += chunk.length - chunk = nextChunk(offset) + chunk = nextChunk(chars, offset, MaxStringSizeInBytes) } arrayVisitor.visitEnd() @@ -127,3 +111,22 @@ class ScalaSigAnnotationVisitor( ca } } + +object ScalaSigAnnotationVisitor { + def nextChunk(chars: Array[Char], from: Int, maxBytes: Int): Array[Char] = { + if (from == chars.length) { + Array.empty + } else { + var size = 0 + var index = 0 + + while (size < maxBytes && from + index < chars.length) { + val c = chars(from + index) + size += (if (c == 0) 2 else 1) + if (size <= maxBytes) index += 1 + } + + chars.slice(from, from + index) + } + } +} diff --git a/core/src/test/scala/testpkg/ScalaSigAnnotationVisitorSpec.scala b/core/src/test/scala/testpkg/ScalaSigAnnotationVisitorSpec.scala new file mode 100644 index 0000000..d9c3fae --- /dev/null +++ b/core/src/test/scala/testpkg/ScalaSigAnnotationVisitorSpec.scala @@ -0,0 +1,25 @@ +package testpkg + +import verify._ +import com.eed3si9n.jarjarabrams.scalasig.ScalaSigAnnotationVisitor + +object ScalaSigAnnotationVisitorSpec extends BasicTestSuite { + test("nextChunk") { + import ScalaSigAnnotationVisitor.nextChunk + + val chars1 = Array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h') + assert(nextChunk(chars1, chars1.length, 3).toSeq.isEmpty) + assert(nextChunk(chars1, 0, 3).toSeq == Seq('a', 'b', 'c')) + assert(nextChunk(chars1, 3, 3).toSeq == Seq('d', 'e', 'f')) + assert(nextChunk(chars1, 6, 3).toSeq == Seq('g', 'h')) + + val chars2 = Array('\u0000', 'a', 'b', 'c', 'd', 'e', '\u0000', 'g', '\u0000') + assert(nextChunk(chars2, 0, 3).toSeq == Seq('\u0000', 'a')) + assert(nextChunk(chars2, 2, 3).toSeq == Seq('b', 'c', 'd')) + assert(nextChunk(chars2, 5, 3).toSeq == Seq('e', '\u0000')) + assert(nextChunk(chars2, 5, 2).toSeq == Seq('e')) + assert(nextChunk(chars2, 7, 3).toSeq == Seq('g', '\u0000')) + assert(nextChunk(chars2, 7, 2).toSeq == Seq('g')) + assert(nextChunk(chars2, 8, 2).toSeq == Seq('\u0000')) + } +}