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

io.kaitai.struct.translators.CommonArraysAndCast.scala Maven / Gradle / Ivy

package io.kaitai.struct.translators

import io.kaitai.struct.datatype.DataType
import io.kaitai.struct.datatype.DataType._
import io.kaitai.struct.exprlang.Ast
import io.kaitai.struct.precompile.TypeMismatchError

/**
  * Common implementation of arrays translations:
  *
  * * type guessing
  * * type enforcing with a cast
  * * rendering of byte arrays and true arrays
  * * call to actual casting implementation
  *
  * @tparam T translation result type
  */
trait CommonArraysAndCast[T] extends TypeDetector {
  /**
    * Processes elements inside a given [[exprlang.Ast.expr.List]] element to render them
    * as either byte array literal or true array.
    * @param values elements from a list
    * @return translation result
    */
  def doGuessArrayLiteral(values: Seq[Ast.expr]): T = {
    val elementType = detectArrayType(values)
    elementType match {
      case Int1Type(_) =>
        val literalBytes: Seq[Byte] = values.map {
          case Ast.expr.IntNum(x) =>
            if (x < 0 || x > 0xff) {
              throw new TypeMismatchError(s"got a weird byte value in byte array: $x")
            } else {
              x.toByte
            }
          case n =>
            throw new TypeMismatchError(s"got $n in byte array, unable to put it literally")
        }
        doByteArrayLiteral(literalBytes)
      case _ =>
        doArrayLiteral(elementType, values)
    }
  }

  /**
    * Processes an [[exprlang.Ast.expr.CastToType]] element, by checking if
    * this is an literal array type enforcement cast first, and
    * rendering it accordingly as proper literal, or invoking
    * the normal [[doCast]] otherwise.
    * @param v CastToType element
    * @return translation result
    */
  def doCastOrArray(v: Ast.expr.CastToType): T = {
    val castToType = detectCastType(v.typeName)

    v.value match {
      case array: Ast.expr.List =>
        // Special handling for literal arrays: if cast is present,
        // then we don't need to guess the data type
        castToType match {
          case _: BytesType =>
            doByteArray(array.elts)
          case ArrayTypeInStream(elType) =>
            doArrayLiteral(elType, array.elts)
          case _ =>
            // No luck, this is some kind of weird cast, not a type enforcement;
            // Just do it and let real type casting deal with it.
            doCast(v.value, castToType)
        }
      case _ =>
        doCast(v.value, castToType)
    }
  }

  def doCast(value: Ast.expr, typeName: DataType): T
  def doArrayLiteral(t: DataType, value: Seq[Ast.expr]): T
  def doByteArrayLiteral(arr: Seq[Byte]): T
  def doByteArrayNonLiteral(elts: Seq[Ast.expr]): T

  private def doByteArray(elts: Seq[Ast.expr]): T = {
    valuesAsByteArrayLiteral(elts) match {
      case Some(arr) =>
        doByteArrayLiteral(arr)
      case None =>
        doByteArrayNonLiteral(elts)
    }
  }

  private def valuesAsByteArrayLiteral(elts: Seq[Ast.expr]): Option[Seq[Byte]] = {
    Some(elts.map {
      case Ast.expr.IntNum(x) =>
        if (x < 0 || x > 0xff) {
          return None
        } else {
          x.toByte
        }
      case _ =>
        return None
    })
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy