Skip to content

Commit

Permalink
Document DataTypes
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingun committed Jul 13, 2023
1 parent 1ddc2c5 commit ab41640
Showing 1 changed file with 150 additions and 1 deletion.
151 changes: 150 additions & 1 deletion shared/src/main/scala/io/kaitai/struct/datatype/DataType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,93 @@ object DataType {
def apiCall(defEndian: Option[FixedEndian]): String
}

/** A generic number type. */
abstract sealed class NumericType extends DataType
/** A generic boolean type. */
abstract sealed class BooleanType extends DataType

/** A generic integer type. */
abstract sealed class IntType extends NumericType
/**
* An integer type that occupies undecided number of bytes in the stream.
*
* If it possible to determine, the more narrow `Int1Type` will be inferred
* for an expression instead of this type.
*
* Represents a type of the following constructions:
*
* - `sizeof<>` and `bitsizeof<>` built-in operators
* - `_sizeof` special property of fields and self object
* - `size` and `pos` properties of streams
* - `to_i` result when converting other types (strings, floats, enums, and booleans) to integers
* - `length` and `size` properties of arrays
* - `length` property of strings
* - `_index` context variable
*/
case object CalcIntType extends IntType
/**
* An integer type that fit into the byte and therefore can represent element
* of the byte array.
*
* Parameters have this type when it's declared with `type: u1` or `type: s1`.
*
* Represents a type of the following constructions:
*
* - `Int1Type(true)` -- a constant in the [0..127] range
* - `Int1Type(false)` -- a constant in the [128..255] range
* - element type of byte arrays
* - `first`, `last`, `min`, and `max` properties of byte arrays
* - result of the `[]` operator of byte arrays
*
* @param signed Determines if most significant bit of number contains sign
*/
case class Int1Type(signed: Boolean) extends IntType with ReadableType {
override def apiCall(defEndian: Option[FixedEndian]): String = if (signed) "s1" else "u1"
}
/**
* An integer type that occupies some predefined size in bytes in the stream.
*
* Parameters have this type when it's declared with `type: u<X>` or `type: s<X>`.
*
* @param signed Determines if most significant bit of number contains sign
* @param width Size of type in bytes
* @param endian Byte order used to represent the number
*/
case class IntMultiType(signed: Boolean, width: IntWidth, endian: Option[FixedEndian]) extends IntType with ReadableType {
override def apiCall(defEndian: Option[FixedEndian]): String = {
val ch1 = if (signed) 's' else 'u'
val finalEnd = endian.orElse(defEndian)
s"$ch1${width.width}${finalEnd.map(_.toSuffix).getOrElse("")}"
}
}
/**
* A boolean type that occupies one bit in the stream.
*
* Parameters have this type when it's declared with `type: b1`.
*/
case class BitsType1(bitEndian: BitEndianness) extends BooleanType
/**
* An integer number type that occupies some predefined size in _bits_ in the stream.
*
* Parameters have this type when it's declared with `type: bX`.
*
* @param width Size of type in bits
* @param bitEndian Bit order inside of byte used to represent the number
*/
case class BitsType(width: Int, bitEndian: BitEndianness) extends IntType

/** A generic floating-point number type. */
abstract sealed class FloatType extends NumericType
/** A floating-point number type that occupies undecided number of bytes in the stream. */
case object CalcFloatType extends FloatType
/**
* A floating-point number type that occupies some predefined size in bytes in the stream.
*
* Parameters have this type when it's declared with `type: fX`.
*
* @param width Size of type in bytes
* @param endian Byte order used to represent the number
*/
case class FloatMultiType(width: IntWidth, endian: Option[FixedEndian]) extends FloatType with ReadableType {
override def apiCall(defEndian: Option[FixedEndian]): String = {
val finalEnd = endian.orElse(defEndian)
Expand All @@ -63,7 +130,13 @@ object DataType {
def process: Option[ProcessExpr]
}

/** A generic raw bytes type. */
abstract sealed class BytesType extends DataType with Processing
/**
* A raw bytes type that occupies undecided number of bytes in the stream.
*
* Parameters have this type when it's declared with `type: bytes`.
*/
case object CalcBytesType extends BytesType {
override def process = None
}
Expand All @@ -88,10 +161,27 @@ object DataType {
override val process: Option[ProcessExpr]
) extends BytesType

/** A generic string type. */
abstract sealed class StrType extends DataType
/**
* A pure string type that occupies undecided number of bytes in the stream.
*
* Parameters have this type when it's declared with `type: str`.
*/
case object CalcStrType extends StrType
/**
* A type that have the `str` and `strz` built-in Kaitai types.
*
* @param bytes An underlying bytes of the string
* @param encoding An encoding used to convert byte array into string
*/
case class StrFromBytesType(bytes: BytesType, encoding: String) extends StrType

/**
* A boolean type that occupies undecided number of bytes in the stream.
*
* Parameters have this type when it's declared with `type: bool`.
*/
case object CalcBooleanType extends BooleanType

/**
Expand Down Expand Up @@ -149,6 +239,7 @@ object DataType {
cs.isTopLevel || cs.meta.isOpaque
}
}
/** User type which isn't restricted in size (i.e. without `size`, `terminator`, or `size-eos`). */
case class UserTypeInstream(
_name: List[String],
_forcedParent: Option[Ast.expr],
Expand All @@ -161,6 +252,7 @@ object DataType {
r
}
}
/** User type which is restricted in size either via `size`, `terminator`, or `size-eos`. */
case class UserTypeFromBytes(
_name: List[String],
_forcedParent: Option[Ast.expr],
Expand All @@ -175,6 +267,12 @@ object DataType {
r
}
}
/**
* Reference to the user type which isn't restricted in size (i.e. without
* `size`, `terminator`, or `size-eos`).
*
* Parameters have this type when it's declared with any non-built-in type.
*/
case class CalcUserType(
_name: List[String],
_forcedParent: Option[Ast.expr],
Expand All @@ -183,6 +281,10 @@ object DataType {
) extends UserType(_name, _forcedParent, _args) {
override def isOwning = false
}
/**
* Reference to the user type which restricted in size either via `size`,
* `terminator`, or `size-eos`.
*/
case class CalcUserTypeFromBytes(
_name: List[String],
_forcedParent: Option[Ast.expr],
Expand All @@ -194,30 +296,75 @@ object DataType {
override def isOwning = false
}

/**
* A generic collection type.
*
* @param elType Type of elements in the collection
*/
abstract sealed class ArrayType(val elType: DataType) extends ComplexDataType

/**
* An owned slice of array type. This type is used for holding data in attributes
* with `repeat` key. Number of elements in that type is unknown
*
* @param _elType Type of elements in the slice
*/
case class ArrayTypeInStream(_elType: DataType) extends ArrayType(_elType) {
override def isOwning: Boolean = true
override def asNonOwning(isOwningInExpr: Boolean = false): CalcArrayType = CalcArrayType(elType, isOwningInExpr)
}
/**
* A borrowed slice of an array. This type is used when array is passed as a
* parameter to the user type (parameter have type `bytes` or haven't any
* explicitly defined type). Number of elements in that type is unknown
*
* @param _elType Type of elements in the slice
*/
case class CalcArrayType(_elType: DataType, override val isOwningInExpr: Boolean = false) extends ArrayType(_elType) {
override def isOwning: Boolean = false
}

val USER_TYPE_NO_PARENT = Ast.expr.Bool(false)

/**
* A very generic type that can hold any other type. Used when type of expression
* is completely unknown to the compiler.
*
* Parameters have this type when it's declared with `type: any`.
*/
case object AnyType extends DataType

/**
* A type that can hold any Kaitai generated type. Can be used as common ancestor
* of `switch-on` types, when all alternative types is owned.
*/
case object KaitaiStructType extends StructType {
def isOwning = true
override def asNonOwning(isOwningInExpr: Boolean = false): DataType = CalcKaitaiStructType(isOwningInExpr)
}
/**
* A type that can hold any Kaitai generated type. Can be used as common ancestor
* of `switch-on` types, when at least one of the alternative types is borrowed.
*
* Parameters have this type when it's declared with `type: struct`.
*/
case class CalcKaitaiStructType(override val isOwningInExpr: Boolean = false) extends StructType {
def isOwning = false
}
/**
* A type that hold and own Kaitai stream object. This type is used when a new IO object
* is allocated (i.e. when new sub-stream is created for types with `size`, `terminator`,
* or `size-eos: true` attributes).
*/
case object OwnedKaitaiStreamType extends ComplexDataType {
def isOwning = true
override def asNonOwning(isOwningInExpr: Boolean = false): DataType = KaitaiStreamType
}
/**
* A type that hold and borrow Kaitai stream object. This type is used
* when an IO object is passed as parameter to the user type.
*
* Parameters have this type when it's declared with `type: io`.
*/
case object KaitaiStreamType extends ComplexDataType {
def isOwning = false
}
Expand Down Expand Up @@ -400,6 +547,8 @@ object DataType {
StrFromBytesType(bat, enc)
case _ =>
val typeWithArgs = Expressions.parseTypeRef(dt)
// if `size`, `terminator` and `size-eos: true` isn't defined,
// user type uses parent stream, otherwise creates an own stream
if (arg.size.isEmpty && !arg.sizeEos && arg.terminator.isEmpty) {
if (arg.process.isDefined)
throw KSYParseError(s"user type '$dt': need 'size' / 'size-eos' / 'terminator' if 'process' is used", path).toException
Expand Down

0 comments on commit ab41640

Please sign in to comment.