0

I would create a model for the KMIP protocols that works with TTLV encoding (Tag, Type, Length, Value)

The ttlv function is "high level" and accepts the tag, the type and the codec of the value.

 def ttlv[A<:HList](tag:ByteVector, itype:ByteVector, value: Codec[A]) =
   constant(tag) :: constant(itype) :: 
   (uint32 >>:~ {
     case length => limitedSizeBytes(length, value)
   })

The result is a Codec[Unit :: Unit :: Long :: A]. However, I would have a Codec[Unit :: Unit :: Unit :: A] (or Codec[A]) to cast the codec to a case class with only the value A. How to ignore the uint32 after used by limitedSizeBytes ? Otherwise I am interested for comments for better approaches.


Here are case class examples:

case class RequestHeader(protocol:Int)
case class RequestPayload(payload:CompromiseDate, name:CertificateName)
case class RequestMessage(header:RequestHeader, payload: RequestPayload)
case class CompromiseDate(value:Int)
case class CertificateName(value:String)

More high level functions like ttlvStructure

def ttlvStructure[A<:HList](tag:ByteVector, struct:Codec[A]) =
  ttlv(tag, hex"01", struct)
def ttlvTextString(tag:ByteVector) =
  ttlv(tag, hex"07", utf8.hlist)
def ttlvInt(tag:ByteVector) =
  ttlv(tag, hex"02", int32.hlist)

And the final codec:

implicit val certificateNameCodec =
  ttlvTextString(hex"420020").as[CertificateName]

implicit val compromiseDateCodec =
  ttlvInt(hex"420021").as[CompromiseDate]

implicit val requestPayloadCodec =
  ttlvStructure(hex"420003", Codec[CompromiseDate] :: Codec[CertificateName]).as[RequestPayload]

implicit val requestHeaderCodec =
  ttlvInt(hex"420002").as[RequestHeader]

implicit val requestMessageCodec =
  ttlvStructure(hex"420001", Codec[RequestHeader] :: Codec[RequestPayload]).as[RequestMessage]

Example of object to encode:

val m = RequestMessage(
      RequestHeader(14),
      RequestPayload(
        CompromiseDate(8),
        CertificateName("certificate name")
      )
    )

Solution:

variableSizeBytesLong is here to do what I want:

def ttlv[A<:HList](tag:ByteVector, itype:ByteVector, value: Codec[A]): Codec[A] =
    (constant(tag) :~>: constant(itype) :~>: variableSizeBytesLong(uint32, value))
Xamrix
  • 452
  • 3
  • 12

1 Answers1

1

Try

val defaultLength: Long = ???

def ttlv[A<:HList](tag:ByteVector, itype:ByteVector, value: Codec[A]): Codec[A] =
  constant(tag) :~>: constant(itype) :~>:
    (uint32 >>:~ (length => limitedSizeBytes(length, value))).xmap[A](_.tail, defaultLength :: _)
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • 1
    But the default length is a variable length. I read through the scodec code and I found the perfect `variableSizeBytesLong` results to a codec `(constant(tag) :~>: constant(itype) :~>: variableSizeBytesLong(uint32, value))`. Thank you ! – Xamrix Oct 10 '18 at 09:51