in csv/src/main/scala/org/apache/pekko/stream/connectors/csv/impl/CsvParser.scala [220:407]
private[this] def churn(): Unit = {
while (state != LineEnd && pos < buffer.length) {
if (lineLength >= maximumLineLength)
throw new MalformedCsvException(
currentLineNo,
lineLength,
s"no line end encountered within $maximumLineLength bytes on line $currentLineNo")
val byte = current.head
state match {
case LineStart =>
byte match {
case `quoteChar` =>
state = QuoteStarted
advance()
fieldStart = pos
case `escapeChar` =>
fieldBuilder.init()
state = WithinFieldEscaped
advance()
fieldStart = pos
case `delimiter` =>
columns += ByteString.empty
state = AfterDelimiter
advance()
fieldStart = pos
case LF =>
columns += ByteString.empty
state = LineEnd
advance()
fieldStart = pos
case CR =>
columns += ByteString.empty
state = AfterCr
advance()
fieldStart = pos
case b =>
fieldBuilder.add(b)
state = WithinField
advance()
}
case AfterDelimiter =>
byte match {
case `quoteChar` =>
state = QuoteStarted
advance()
fieldStart = pos
case `escapeChar` =>
fieldBuilder.init()
state = WithinFieldEscaped
advance()
fieldStart = pos
case `delimiter` =>
columns += ByteString.empty
state = AfterDelimiter
advance()
fieldStart = pos
case LF =>
columns += ByteString.empty
state = LineEnd
advance()
fieldStart = pos
case CR =>
columns += ByteString.empty
state = AfterCr
advance()
fieldStart = pos
case b =>
fieldBuilder.add(b)
state = WithinField
advance()
}
case WithinField =>
byte match {
case `escapeChar` =>
fieldBuilder.init()
state = WithinFieldEscaped
advance()
case `delimiter` =>
columns += fieldBuilder.result(pos)
state = AfterDelimiter
advance()
dropReadBuffer()
case LF =>
columns += fieldBuilder.result(pos)
state = LineEnd
advance()
dropReadBuffer()
case CR =>
columns += fieldBuilder.result(pos)
state = AfterCr
advance()
dropReadBuffer()
case b =>
fieldBuilder.add(b)
state = WithinField
advance()
}
case WithinFieldEscaped =>
byte match {
case `escapeChar` | `delimiter` =>
fieldBuilder.add(byte)
state = WithinField
advance()
case `quoteChar` =>
throw new MalformedCsvException(
currentLineNo,
lineLength,
s"wrong escaping at $currentLineNo:$lineLength, quote is escaped as ${quoteChar.toChar}${quoteChar.toChar}")
case b =>
fieldBuilder.add(escapeChar)
state = WithinField
}
case QuoteStarted =>
byte match {
case `escapeChar` if escapeChar != quoteChar =>
fieldBuilder.init()
state = WithinQuotedFieldEscaped
advance()
case `quoteChar` =>
fieldBuilder.init()
state = WithinQuotedFieldQuote
advance()
case b =>
fieldBuilder.add(b)
state = WithinQuotedField
advance()
}
case WithinQuotedField =>
byte match {
case `escapeChar` if escapeChar != quoteChar =>
fieldBuilder.init()
state = WithinQuotedFieldEscaped
advance()
case `quoteChar` =>
fieldBuilder.init()
state = WithinQuotedFieldQuote
advance()
case b =>
fieldBuilder.add(b)
state = WithinQuotedField
advance()
}
case WithinQuotedFieldEscaped =>
byte match {
case `escapeChar` | `quoteChar` =>
fieldBuilder.add(byte)
state = WithinQuotedField
advance()
case b =>
fieldBuilder.add(escapeChar)
state = WithinQuotedField
}
case WithinQuotedFieldQuote =>
byte match {
case `quoteChar` =>
fieldBuilder.add(byte)
state = WithinQuotedField
advance()
case b =>
state = WithinField
}
case AfterCr =>
byte match {
case CR =>
state = AfterCr
advance()
case LF =>
state = LineEnd
advance()
case _ =>
state = LineEnd
}
}
}
}