All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.kaitai.struct.languages.components.GoReads.scala Maven / Gradle / Ivy

package io.kaitai.struct.languages.components

import io.kaitai.struct.datatype.DataType._
import io.kaitai.struct.datatype.{DataType, FixedEndian}
import io.kaitai.struct.exprlang.Ast
import io.kaitai.struct.format._
import io.kaitai.struct.translators.{GoTranslator, ResultLocalVar, ResultString, TranslatorResult}

trait GoReads extends CommonReads with ObjectOrientedLanguage with GoSwitchOps {
  val translator: GoTranslator

  def attrBytesTypeParse(
    id: Identifier,
    dataType: BytesType,
    io: String,
    rep: RepeatSpec,
    isRaw: Boolean
  ): Unit = {
    val rawId = dataType.process match {
      case None => id
      case Some(_) => RawIdentifier(id)
    }
    val expr = parseExprBytes(translator.outVarCheckRes(parseExpr(dataType, io, None)), dataType)
    handleAssignment(rawId, expr, rep, isRaw)
    dataType.process.foreach((proc) => attrProcess(proc, rawId, id, rep))
  }

  def attrSwitchTypeParse(
    id: Identifier,
    on: Ast.expr,
    cases: Map[Ast.expr, DataType],
    io: String,
    rep: RepeatSpec,
    defEndian: Option[FixedEndian],
    isNullable: Boolean,
    assignType: DataType
  ): Unit = {
    switchCases[DataType](id, on, cases,
      (dataType) => {
        attrParse2(id, dataType, io, rep, false, defEndian, Some(assignType))
      },
      {
        case dataType@(t: BytesType) =>
          attrParse2(RawIdentifier(id), dataType, io, rep, false, defEndian, Some(assignType))
        case dataType =>
          attrParse2(id, dataType, io, rep, false, defEndian, Some(assignType))
      }
    )
  }

  override def attrParse2(
    id: Identifier,
    dataType: DataType,
    io: String,
    rep: RepeatSpec,
    isRaw: Boolean,
    defEndian: Option[FixedEndian],
    assignType: Option[DataType] = None
  ): Unit = {
    dataType match {
      case t: UserType =>
        attrUserTypeParse(id, t, io, rep, defEndian)
      case t: BytesType =>
        attrBytesTypeParse(id, t, io, rep, isRaw)
      case st: SwitchType =>
        attrSwitchTypeParse(id, st.on, st.cases, io, rep, defEndian, st.isNullableSwitchRaw, st.combinedType)
      case t: StrFromBytesType =>
        val r1 = parseExprBytes(translator.outVarCheckRes(parseExpr(t.bytes, io, defEndian)), t.bytes)
        val expr = translator.bytesToStr(translator.resToStr(r1), Ast.expr.Str(t.encoding))
        handleAssignment(id, expr, rep, isRaw)
      case t: EnumType =>
        val r1 = translator.outVarCheckRes(parseExpr(t.basedOn, io, defEndian))
        val enumSpec = t.enumSpec.get
        val expr = translator.trEnumById(enumSpec.name, translator.resToStr(r1))
        handleAssignment(id, expr, rep, isRaw)
      case _: BitsType1 =>
        val expr = parseExpr(dataType, io, defEndian)
        val r1 = translator.outVarCheckRes(expr)
        val r2 = ResultString(s"${translator.resToStr(r1)} != 0")
        handleAssignment(id, r2, rep, isRaw)
      case _ =>
        val expr = parseExpr(dataType, io, defEndian)
        val r = translator.outVarCheckRes(expr)
        handleAssignment(id, r, rep, isRaw)
    }
  }

  def bytesPadTermExpr(id: ResultLocalVar, padRight: Option[Int], terminator: Option[Int], include: Boolean): String = {
    val expr0 = translator.resToStr(id)
    val expr1 = padRight match {
      case Some(padByte) => s"kaitai.BytesStripRight($expr0, $padByte)"
      case None => expr0
    }
    val expr2 = terminator match {
      case Some(term) => s"kaitai.BytesTerminate($expr1, $term, $include)"
      case None => expr1
    }
    expr2
  }

  def parseExprBytes(id: ResultLocalVar, dataType: BytesType): ResultLocalVar = {
    dataType match {
      case BytesEosType(terminator, include, padRight, _) =>
        translator.outTransform(id, bytesPadTermExpr(id, padRight, terminator, include))
      case BytesLimitType(_, terminator, include, padRight, _) =>
        translator.outTransform(id, bytesPadTermExpr(id, padRight, terminator, include))
      case _ =>
        id
    }
  }

  def attrUserTypeParse(id: Identifier, dataType: UserType, io: String, rep: RepeatSpec, defEndian: Option[FixedEndian]): Unit = {
    val newIO = dataType match {
      case knownSizeType: UserTypeFromBytes =>
        // we have a fixed buffer, thus we shall create separate IO for it
        val rawId = RawIdentifier(id)
        val byteType = knownSizeType.bytes

        attrParse2(rawId, byteType, io, rep, true, defEndian)

        val extraType = rep match {
          case NoRepeat => byteType
          case _ => ArrayTypeInStream(byteType)
        }

        this match {
          case thisStore: AllocateAndStoreIO =>
            thisStore.allocateIO(rawId, rep)
          case thisLocal: AllocateIOLocalVar =>
            thisLocal.allocateIO(rawId, rep)
        }
      case _: UserTypeInstream =>
        // no fixed buffer, just use regular IO
        io
    }

    val expr = translator.userType(dataType, newIO)
    handleAssignment(id, expr, rep, false)
  }

  def handleAssignment(id: Identifier, expr: TranslatorResult, rep: RepeatSpec, isRaw: Boolean): Unit = {
    rep match {
      case RepeatEos => handleAssignmentRepeatEos(id, expr)
      case RepeatExpr(_) => handleAssignmentRepeatExpr(id, expr)
      case RepeatUntil(_) => handleAssignmentRepeatUntil(id, expr, isRaw)
      case NoRepeat => handleAssignmentSimple(id, expr)
    }
  }

  def handleAssignmentRepeatEos(id: Identifier, expr: TranslatorResult): Unit
  def handleAssignmentRepeatExpr(id: Identifier, expr: TranslatorResult): Unit
  def handleAssignmentRepeatUntil(id: Identifier, expr: TranslatorResult, isRaw: Boolean): Unit
  def handleAssignmentSimple(id: Identifier, expr: TranslatorResult): Unit

  def parseExpr(dataType: DataType, io: String, defEndian: Option[FixedEndian]): String
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy