mirror of
https://github.com/aziascreations/PB-MessagePack.git
synced 2026-11-03 17:01:24 +01:00
@@ -167,6 +167,32 @@ Supported encodings: `#PB_UTF8` (default, per spec), `#PB_Ascii`, `#PB_Unicode`
|
||||
See: `MsgPackLastError`
|
||||
|
||||
|
||||
### Extensions
|
||||
`ExtType.b` is the signed ext type, `-128` to `-1` being reserved by the spec but not rejected. \
|
||||
Size errors reuse the `#MsgPack_Error_BinaryDataSize*` codes.
|
||||
|
||||
* `MsgPackWriteExtension.MsgPack_ErrorCode(*MsgPackData.MsgPackData, ExtType.b, *Buffer, BufferSize.q)` \
|
||||
Writes `BufferSize` bytes from `*Buffer` using fixext for 1/2/4/8/16 bytes, or the smallest ext format code otherwise. \
|
||||
Returns `#MsgPack_Error_Success` on success, something else otherwise.
|
||||
|
||||
* `MsgPackWriteExt8/16/32.MsgPack_ErrorCode(*MsgPackData.MsgPackData, ExtType.b, *Buffer, BufferSize.q)` \
|
||||
Same as `MsgPackWriteExtension`, but forces the given format code, even if a smaller one fits.
|
||||
|
||||
* `MsgPackWriteFixExt1/2/4/8/16.MsgPack_ErrorCode(*MsgPackData.MsgPackData, ExtType.b, *Buffer)` \
|
||||
Writes the 1/2/4/8/16 bytes at `*Buffer` as the given fixext.
|
||||
|
||||
* `MsgPackGetExtensionType.b(*MsgPackData.MsgPackData)` \
|
||||
Returns the type of the ext field at the current internal offset, without moving it. \
|
||||
Returns `0` on errors and sets the internal error code. \
|
||||
See: `MsgPackLastError`
|
||||
|
||||
* `MsgPackReadExtension.q(*MsgPackData.MsgPackData, *OutputBuffer, OutputBufferSize.q)` \
|
||||
Same as `MsgPackReadBinary`, for the data of ext fields.
|
||||
|
||||
* `MsgPackCopyExtension.i(*MsgPackData.MsgPackData)` \
|
||||
Same as `MsgPackCopyBinary`, for the data of ext fields.
|
||||
|
||||
|
||||
## Remarks
|
||||
* Never touch the `MsgPackData` structure unless you **absolutely** have to.
|
||||
|
||||
|
||||
@@ -30,4 +30,5 @@ XIncludeFile "./_Literals.pbi"
|
||||
XIncludeFile "./_Binary.pbi"
|
||||
XIncludeFile "./_Primitives.pbi"
|
||||
XIncludeFile "./_Strings.pbi"
|
||||
XIncludeFile "./_Extensions.pbi"
|
||||
XIncludeFile "./_Iterators.pbi"
|
||||
|
||||
+77
-31
@@ -21,12 +21,14 @@
|
||||
; Sizes are all unsigned 8/16/32, using Q fixes any potential issues !
|
||||
|
||||
; The "sized field" helpers below handle every `[FormatCode][Size][Data]` layout
|
||||
; shared by the str and bin families.
|
||||
; shared by the str, bin and ext families.
|
||||
; The `SizeFieldByteLength` parameter is the number of bytes used to store the size:
|
||||
; * `0` - Size is stored in the format code's lower 5 bits. (FixStr)
|
||||
; * `1` - Str8, Bin8
|
||||
; * `2` - Str16, Bin16
|
||||
; * `4` - Str32, Bin32
|
||||
; Or implied by the format code. (FixExt1/2/4/8/16)
|
||||
; * `1` - Str8, Bin8, Ext8
|
||||
; * `2` - Str16, Bin16, Ext16
|
||||
; * `4` - Str32, Bin32, Ext32
|
||||
; The ext family also has a 1 byte type between its size and its data.
|
||||
|
||||
|
||||
|
||||
@@ -51,9 +53,11 @@ XIncludeFile "./_Primitives.pbi"
|
||||
|
||||
; Validates `DataSize`, reserves space for the whole field, writes its format code
|
||||
; and size, and moves the offset right after them.
|
||||
; The caller is expected to write `DataSize` bytes of data and move the offset afterward.
|
||||
; `ExtraHeaderSize` more bytes are reserved right after the size, for the ext type.
|
||||
; The caller is expected to write the extra header bytes and `DataSize` bytes of data,
|
||||
; and move the offset afterward.
|
||||
; Sets the structure's error code and returns it.
|
||||
Procedure.MsgPack_ErrorCode _MsgPackWriteSizedFieldHeader(*MsgPackData.MsgPackData, FormatCode.MsgPack_FormatCode, SizeFieldByteLength.a, DataSize.q)
|
||||
Procedure.MsgPack_ErrorCode _MsgPackWriteSizedFieldHeader(*MsgPackData.MsgPackData, FormatCode.MsgPack_FormatCode, SizeFieldByteLength.a, DataSize.q, ExtraHeaderSize.a = 0)
|
||||
Protected MaxDataSize.q
|
||||
Protected ErrorCode.MsgPack_ErrorCode
|
||||
|
||||
@@ -89,7 +93,7 @@ Procedure.MsgPack_ErrorCode _MsgPackWriteSizedFieldHeader(*MsgPackData.MsgPackDa
|
||||
ProcedureReturn #MsgPack_Error_BinaryDataSizeIsTooBig
|
||||
EndIf
|
||||
|
||||
ErrorCode = _MsgPackReserveWrite(*MsgPackData, 1 + SizeFieldByteLength + DataSize)
|
||||
ErrorCode = _MsgPackReserveWrite(*MsgPackData, 1 + SizeFieldByteLength + ExtraHeaderSize + DataSize)
|
||||
If ErrorCode <> #MsgPack_Error_Success
|
||||
ProcedureReturn ErrorCode
|
||||
EndIf
|
||||
@@ -132,14 +136,17 @@ Procedure.MsgPack_ErrorCode _MsgPackWriteSizedField(*MsgPackData.MsgPackData, Fo
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Reads the header of a str or bin field at the current offset, without moving it.
|
||||
; `ExpectedDataType` must be `#MsgPack_DataTypes_String` or `#MsgPack_DataTypes_Binary`.
|
||||
; On success, `*HeaderSize` receives the format code + size field length, and `*DataSize`
|
||||
; the data's length, both guaranteed to be within the buffer.
|
||||
; Reads the header of a str, bin or ext field at the current offset, without moving it.
|
||||
; `ExpectedDataType` must be `#MsgPack_DataTypes_String`, `#MsgPack_DataTypes_Binary`
|
||||
; or `#MsgPack_DataTypes_Extension`.
|
||||
; On success, `*HeaderSize` receives the format code + size field (+ ext type) length,
|
||||
; and `*DataSize` the data's length, both guaranteed to be within the buffer.
|
||||
; For ext fields, the type is the header's last byte.
|
||||
; Sets the structure's error code and returns it.
|
||||
Procedure.MsgPack_ErrorCode _MsgPackReadSizedFieldHeader(*MsgPackData.MsgPackData, ExpectedDataType.MsgPack_DataType, *HeaderSize.Integer, *DataSize.Quad)
|
||||
Protected FormatCode.MsgPack_FormatCode
|
||||
Protected SizeFieldByteLength.a
|
||||
Protected ExtTypeByteLength.a = 0
|
||||
Protected DataSize.q
|
||||
|
||||
CompilerIf Not #MsgPack_DisableNullChecks
|
||||
@@ -166,17 +173,34 @@ Procedure.MsgPack_ErrorCode _MsgPackReadSizedFieldHeader(*MsgPackData.MsgPackDat
|
||||
Case #MsgPack_FormatCode_FixStr:
|
||||
SizeFieldByteLength = 0
|
||||
Case #MsgPack_FormatCode_Str8,
|
||||
#MsgPack_FormatCode_Bin8:
|
||||
#MsgPack_FormatCode_Bin8,
|
||||
#MsgPack_FormatCode_Ext8:
|
||||
SizeFieldByteLength = 1
|
||||
Case #MsgPack_FormatCode_Str16,
|
||||
#MsgPack_FormatCode_Bin16:
|
||||
#MsgPack_FormatCode_Bin16,
|
||||
#MsgPack_FormatCode_Ext16:
|
||||
SizeFieldByteLength = 2
|
||||
Case #MsgPack_FormatCode_Str32,
|
||||
#MsgPack_FormatCode_Bin32:
|
||||
#MsgPack_FormatCode_Bin32,
|
||||
#MsgPack_FormatCode_Ext32:
|
||||
SizeFieldByteLength = 4
|
||||
Case #MsgPack_FormatCode_FixExt1:
|
||||
SizeFieldByteLength = 0 : DataSize = 1
|
||||
Case #MsgPack_FormatCode_FixExt2:
|
||||
SizeFieldByteLength = 0 : DataSize = 2
|
||||
Case #MsgPack_FormatCode_FixExt4:
|
||||
SizeFieldByteLength = 0 : DataSize = 4
|
||||
Case #MsgPack_FormatCode_FixExt8:
|
||||
SizeFieldByteLength = 0 : DataSize = 8
|
||||
Case #MsgPack_FormatCode_FixExt16:
|
||||
SizeFieldByteLength = 0 : DataSize = 16
|
||||
EndSelect
|
||||
|
||||
If Not _MsgPackHasSpaceLeft(*MsgPackData, 1 + SizeFieldByteLength)
|
||||
If ExpectedDataType = #MsgPack_DataTypes_Extension
|
||||
ExtTypeByteLength = 1
|
||||
EndIf
|
||||
|
||||
If Not _MsgPackHasSpaceLeft(*MsgPackData, 1 + SizeFieldByteLength + ExtTypeByteLength)
|
||||
Debug("End of buffer reached, cannot read the field's size !")
|
||||
*MsgPackData\LastError = #MsgPack_Error_BufferTooSmall
|
||||
ProcedureReturn #MsgPack_Error_BufferTooSmall
|
||||
@@ -184,7 +208,10 @@ Procedure.MsgPack_ErrorCode _MsgPackReadSizedFieldHeader(*MsgPackData.MsgPackDat
|
||||
|
||||
Select SizeFieldByteLength
|
||||
Case 0:
|
||||
DataSize = PeekA(*MsgPackData\Buffer + *MsgPackData\BufferOffset) & %00011111
|
||||
; FixExt sizes were already set above.
|
||||
If FormatCode = #MsgPack_FormatCode_FixStr
|
||||
DataSize = PeekA(*MsgPackData\Buffer + *MsgPackData\BufferOffset) & %00011111
|
||||
EndIf
|
||||
Case 1:
|
||||
DataSize = PeekA(*MsgPackData\Buffer + *MsgPackData\BufferOffset + 1)
|
||||
Case 2:
|
||||
@@ -193,13 +220,13 @@ Procedure.MsgPack_ErrorCode _MsgPackReadSizedFieldHeader(*MsgPackData.MsgPackDat
|
||||
DataSize = EndianSwapI32(PeekL(*MsgPackData\Buffer + *MsgPackData\BufferOffset + 1)) & $FFFFFFFF
|
||||
EndSelect
|
||||
|
||||
If Not _MsgPackHasSpaceLeft(*MsgPackData, 1 + SizeFieldByteLength + DataSize)
|
||||
If Not _MsgPackHasSpaceLeft(*MsgPackData, 1 + SizeFieldByteLength + ExtTypeByteLength + DataSize)
|
||||
Debug("End of buffer reached, cannot read the field's data !")
|
||||
*MsgPackData\LastError = #MsgPack_Error_BufferTooSmall
|
||||
ProcedureReturn #MsgPack_Error_BufferTooSmall
|
||||
EndIf
|
||||
|
||||
*HeaderSize\i = 1 + SizeFieldByteLength
|
||||
*HeaderSize\i = 1 + SizeFieldByteLength + ExtTypeByteLength
|
||||
*DataSize\q = DataSize
|
||||
|
||||
*MsgPackData\LastError = #MsgPack_Error_Success
|
||||
@@ -207,18 +234,15 @@ Procedure.MsgPack_ErrorCode _MsgPackReadSizedFieldHeader(*MsgPackData.MsgPackDat
|
||||
EndProcedure
|
||||
|
||||
|
||||
|
||||
;-> Getters
|
||||
|
||||
; Copies the bin field at the current offset into `*OutputBuffer`.
|
||||
; Copies the data of the bin or ext field at the current offset into `*OutputBuffer`.
|
||||
; Returns: The number of bytes copied.
|
||||
; OnError: Returns `#MsgPack_InvalidSize` and sets the `MsgPackData\LastError` field.
|
||||
; The offset is left untouched, so a bigger buffer can be given afterward.
|
||||
Procedure.q MsgPackReadBinary(*MsgPackData.MsgPackData, *OutputBuffer, OutputBufferSize.q)
|
||||
Procedure.q _MsgPackReadSizedFieldData(*MsgPackData.MsgPackData, ExpectedDataType.MsgPack_DataType, *OutputBuffer, OutputBufferSize.q)
|
||||
Protected HeaderSize.i
|
||||
Protected DataSize.q
|
||||
|
||||
If _MsgPackReadSizedFieldHeader(*MsgPackData, #MsgPack_DataTypes_Binary, @HeaderSize, @DataSize) <> #MsgPack_Error_Success
|
||||
|
||||
If _MsgPackReadSizedFieldHeader(*MsgPackData, ExpectedDataType, @HeaderSize, @DataSize) <> #MsgPack_Error_Success
|
||||
ProcedureReturn #MsgPack_InvalidSize
|
||||
EndIf
|
||||
|
||||
@@ -246,24 +270,24 @@ Procedure.q MsgPackReadBinary(*MsgPackData.MsgPackData, *OutputBuffer, OutputBuf
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Copies the bin field at the current offset into a new buffer.
|
||||
; Copies the data of the bin or ext field at the current offset into a new buffer.
|
||||
; Returns: A buffer from `AllocateMemory()` that the caller must free with `FreeMemory()`.
|
||||
; Its size can be obtained with `MemorySize()`.
|
||||
; Empty bin fields return `#Null` with `MsgPackData\LastError` set to `#MsgPack_Error_Success`.
|
||||
; Empty fields return `#Null` with `MsgPackData\LastError` set to `#MsgPack_Error_Success`.
|
||||
; OnError: Returns `#Null` and sets the `MsgPackData\LastError` field.
|
||||
Procedure.i MsgPackCopyBinary(*MsgPackData.MsgPackData)
|
||||
Procedure.i _MsgPackCopySizedFieldData(*MsgPackData.MsgPackData, ExpectedDataType.MsgPack_DataType)
|
||||
Protected HeaderSize.i
|
||||
Protected DataSize.q
|
||||
Protected *ReturnedValue = #Null
|
||||
|
||||
If _MsgPackReadSizedFieldHeader(*MsgPackData, #MsgPack_DataTypes_Binary, @HeaderSize, @DataSize) <> #MsgPack_Error_Success
|
||||
|
||||
If _MsgPackReadSizedFieldHeader(*MsgPackData, ExpectedDataType, @HeaderSize, @DataSize) <> #MsgPack_Error_Success
|
||||
ProcedureReturn #Null
|
||||
EndIf
|
||||
|
||||
If DataSize > 0
|
||||
*ReturnedValue = AllocateMemory(DataSize, #PB_Memory_NoClear)
|
||||
If Not *ReturnedValue
|
||||
Debug("Failed to allocate memory for the copied binary !")
|
||||
Debug("Failed to allocate memory for the copied data !")
|
||||
*MsgPackData\LastError = #MsgPack_Error_FailedToAllocateBuffer
|
||||
ProcedureReturn #Null
|
||||
EndIf
|
||||
@@ -278,6 +302,28 @@ EndProcedure
|
||||
|
||||
|
||||
|
||||
;-> Getters
|
||||
|
||||
; Copies the bin field at the current offset into `*OutputBuffer`.
|
||||
; Returns: The number of bytes copied.
|
||||
; OnError: Returns `#MsgPack_InvalidSize` and sets the `MsgPackData\LastError` field.
|
||||
; The offset is left untouched, so a bigger buffer can be given afterward.
|
||||
Procedure.q MsgPackReadBinary(*MsgPackData.MsgPackData, *OutputBuffer, OutputBufferSize.q)
|
||||
ProcedureReturn _MsgPackReadSizedFieldData(*MsgPackData, #MsgPack_DataTypes_Binary, *OutputBuffer, OutputBufferSize)
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Copies the bin field at the current offset into a new buffer.
|
||||
; Returns: A buffer from `AllocateMemory()` that the caller must free with `FreeMemory()`.
|
||||
; Its size can be obtained with `MemorySize()`.
|
||||
; Empty bin fields return `#Null` with `MsgPackData\LastError` set to `#MsgPack_Error_Success`.
|
||||
; OnError: Returns `#Null` and sets the `MsgPackData\LastError` field.
|
||||
Procedure.i MsgPackCopyBinary(*MsgPackData.MsgPackData)
|
||||
ProcedureReturn _MsgPackCopySizedFieldData(*MsgPackData, #MsgPack_DataTypes_Binary)
|
||||
EndProcedure
|
||||
|
||||
|
||||
|
||||
;-> Setters
|
||||
|
||||
; Writes `BufferSize` bytes from `*Buffer` as a bin8.
|
||||
|
||||
+190
-1
@@ -9,7 +9,7 @@
|
||||
; * //PureBasic 5.73 LTS (x86/x64)
|
||||
; * //PureBasic 6.21 (x86/x64)
|
||||
; * //PureBasic 6.21 C Backend (arm64)
|
||||
;
|
||||
;
|
||||
; ==- Links & License -===========================
|
||||
; License: CC0 1.0 Universal (Public Domain)
|
||||
; GitHub: https://github.com/aziascreations/PB-MessagePack
|
||||
@@ -21,6 +21,12 @@
|
||||
; Specification:
|
||||
; * https://github.com/msgpack/msgpack/blob/master/spec.md
|
||||
|
||||
; The ext type is a signed byte, `-128` to `-1` being reserved by the spec. (`-1` = timestamp)
|
||||
; Reserved types are not rejected, so predefined types can be written with these procedures.
|
||||
; FixExt fields have no size field, their data size is implied by the format code.
|
||||
; See "_Binary.pbi" for the shared "sized field" helpers.
|
||||
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
;- Compiler directive
|
||||
@@ -30,4 +36,187 @@ CompilerIf #PB_Compiler_IsMainFile
|
||||
CompilerEndIf
|
||||
|
||||
XIncludeFile "./_Commons.pbi"
|
||||
XIncludeFile "./_Primitives.pbi"
|
||||
XIncludeFile "./_Binary.pbi"
|
||||
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
;- Procedures
|
||||
|
||||
;-> Internal helpers
|
||||
|
||||
; Writes a full ext field by copying `DataSize` bytes from `*Data`.
|
||||
; `SizeFieldByteLength` set to `0` indicates a FixExt whose implied size must match `DataSize`.
|
||||
; Sets the structure's error code and returns it.
|
||||
Procedure.MsgPack_ErrorCode _MsgPackWriteExtField(*MsgPackData.MsgPackData, FormatCode.MsgPack_FormatCode, SizeFieldByteLength.a, ExtType.b, *Data, DataSize.q)
|
||||
Protected ErrorCode.MsgPack_ErrorCode
|
||||
Protected FixExtSize.q
|
||||
|
||||
CompilerIf Not #MsgPack_DisableNullChecks
|
||||
If Not *MsgPackData
|
||||
DebuggerError("A #Null MsgPackData pointer was passed !")
|
||||
ProcedureReturn #MsgPack_Error_NullPointerGiven
|
||||
EndIf
|
||||
CompilerEndIf
|
||||
|
||||
If SizeFieldByteLength = 0
|
||||
Select FormatCode
|
||||
Case #MsgPack_FormatCode_FixExt1 : FixExtSize = 1
|
||||
Case #MsgPack_FormatCode_FixExt2 : FixExtSize = 2
|
||||
Case #MsgPack_FormatCode_FixExt4 : FixExtSize = 4
|
||||
Case #MsgPack_FormatCode_FixExt8 : FixExtSize = 8
|
||||
Case #MsgPack_FormatCode_FixExt16 : FixExtSize = 16
|
||||
Default
|
||||
FixExtSize = #MsgPack_InvalidSize
|
||||
EndSelect
|
||||
|
||||
If DataSize <> FixExtSize
|
||||
DebuggerError("Invalid FixExt size: " + Str(DataSize))
|
||||
*MsgPackData\LastError = #MsgPack_Error_InvalidValue
|
||||
ProcedureReturn #MsgPack_Error_InvalidValue
|
||||
EndIf
|
||||
|
||||
ErrorCode = _MsgPackReserveWrite(*MsgPackData, 2 + DataSize)
|
||||
If ErrorCode <> #MsgPack_Error_Success
|
||||
ProcedureReturn ErrorCode
|
||||
EndIf
|
||||
|
||||
PokeA(*MsgPackData\Buffer + *MsgPackData\BufferOffset, FormatCode)
|
||||
*MsgPackData\BufferOffset = *MsgPackData\BufferOffset + 1
|
||||
Else
|
||||
ErrorCode = _MsgPackWriteSizedFieldHeader(*MsgPackData, FormatCode, SizeFieldByteLength, DataSize, 1)
|
||||
If ErrorCode <> #MsgPack_Error_Success
|
||||
ProcedureReturn ErrorCode
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
PokeB(*MsgPackData\Buffer + *MsgPackData\BufferOffset, ExtType)
|
||||
*MsgPackData\BufferOffset = *MsgPackData\BufferOffset + 1
|
||||
|
||||
If DataSize > 0
|
||||
CopyMemory(*Data, *MsgPackData\Buffer + *MsgPackData\BufferOffset, DataSize)
|
||||
*MsgPackData\BufferOffset = *MsgPackData\BufferOffset + DataSize
|
||||
EndIf
|
||||
|
||||
ProcedureReturn #MsgPack_Error_Success
|
||||
EndProcedure
|
||||
|
||||
|
||||
|
||||
;-> Getters
|
||||
|
||||
; Reads the type of the ext field at the current offset, without moving it.
|
||||
; Returns: The ext type.
|
||||
; OnError: Returns `0` and sets the `MsgPackData\LastError` field.
|
||||
Procedure.b MsgPackGetExtensionType(*MsgPackData.MsgPackData)
|
||||
Protected HeaderSize.i
|
||||
Protected DataSize.q
|
||||
|
||||
If _MsgPackReadSizedFieldHeader(*MsgPackData, #MsgPack_DataTypes_Extension, @HeaderSize, @DataSize) <> #MsgPack_Error_Success
|
||||
ProcedureReturn 0
|
||||
EndIf
|
||||
|
||||
ProcedureReturn PeekB(*MsgPackData\Buffer + *MsgPackData\BufferOffset + HeaderSize - 1)
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Copies the data of the ext field at the current offset into `*OutputBuffer`.
|
||||
; Its type can be read beforehand with `MsgPackGetExtensionType()`.
|
||||
; Returns: The number of bytes copied.
|
||||
; OnError: Returns `#MsgPack_InvalidSize` and sets the `MsgPackData\LastError` field.
|
||||
; The offset is left untouched, so a bigger buffer can be given afterward.
|
||||
Procedure.q MsgPackReadExtension(*MsgPackData.MsgPackData, *OutputBuffer, OutputBufferSize.q)
|
||||
ProcedureReturn _MsgPackReadSizedFieldData(*MsgPackData, #MsgPack_DataTypes_Extension, *OutputBuffer, OutputBufferSize)
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Copies the data of the ext field at the current offset into a new buffer.
|
||||
; Its type can be read beforehand with `MsgPackGetExtensionType()`.
|
||||
; Returns: A buffer from `AllocateMemory()` that the caller must free with `FreeMemory()`.
|
||||
; Its size can be obtained with `MemorySize()`.
|
||||
; Empty ext fields return `#Null` with `MsgPackData\LastError` set to `#MsgPack_Error_Success`.
|
||||
; OnError: Returns `#Null` and sets the `MsgPackData\LastError` field.
|
||||
Procedure.i MsgPackCopyExtension(*MsgPackData.MsgPackData)
|
||||
ProcedureReturn _MsgPackCopySizedFieldData(*MsgPackData, #MsgPack_DataTypes_Extension)
|
||||
EndProcedure
|
||||
|
||||
|
||||
|
||||
;-> Setters
|
||||
|
||||
; Writes `BufferSize` bytes from `*Buffer` as an ext8 of type `ExtType`, even if a smaller format code fits.
|
||||
; Returns `#MsgPack_Error_Success` on success, something else otherwise.
|
||||
Procedure.MsgPack_ErrorCode MsgPackWriteExt8(*MsgPackData.MsgPackData, ExtType.b, *Buffer, BufferSize.q)
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_Ext8, 1, ExtType, *Buffer, BufferSize)
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Writes `BufferSize` bytes from `*Buffer` as an ext16 of type `ExtType`, even if a smaller format code fits.
|
||||
; Returns `#MsgPack_Error_Success` on success, something else otherwise.
|
||||
Procedure.MsgPack_ErrorCode MsgPackWriteExt16(*MsgPackData.MsgPackData, ExtType.b, *Buffer, BufferSize.q)
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_Ext16, 2, ExtType, *Buffer, BufferSize)
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Writes `BufferSize` bytes from `*Buffer` as an ext32 of type `ExtType`, even if a smaller format code fits.
|
||||
; Returns `#MsgPack_Error_Success` on success, something else otherwise.
|
||||
Procedure.MsgPack_ErrorCode MsgPackWriteExt32(*MsgPackData.MsgPackData, ExtType.b, *Buffer, BufferSize.q)
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_Ext32, 4, ExtType, *Buffer, BufferSize)
|
||||
EndProcedure
|
||||
|
||||
|
||||
; Writes `BufferSize` bytes from `*Buffer` as an ext of type `ExtType` using the smallest
|
||||
; format code that fits.
|
||||
; Returns `#MsgPack_Error_Success` on success, something else otherwise.
|
||||
Procedure.MsgPack_ErrorCode MsgPackWriteExtension(*MsgPackData.MsgPackData, ExtType.b, *Buffer, BufferSize.q)
|
||||
Select BufferSize
|
||||
Case 1
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_FixExt1, 0, ExtType, *Buffer, BufferSize)
|
||||
Case 2
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_FixExt2, 0, ExtType, *Buffer, BufferSize)
|
||||
Case 4
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_FixExt4, 0, ExtType, *Buffer, BufferSize)
|
||||
Case 8
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_FixExt8, 0, ExtType, *Buffer, BufferSize)
|
||||
Case 16
|
||||
ProcedureReturn _MsgPackWriteExtField(*MsgPackData, #MsgPack_FormatCode_FixExt16, 0, ExtType, *Buffer, BufferSize)
|
||||
EndSelect
|
||||
|
||||
If BufferSize <= 255
|
||||
ProcedureReturn MsgPackWriteExt8(*MsgPackData, ExtType, *Buffer, BufferSize)
|
||||
ElseIf BufferSize <= 65535
|
||||
ProcedureReturn MsgPackWriteExt16(*MsgPackData, ExtType, *Buffer, BufferSize)
|
||||
Else
|
||||
; Sizes above `(2^32)-1` are rejected by the helper.
|
||||
ProcedureReturn MsgPackWriteExt32(*MsgPackData, ExtType, *Buffer, BufferSize)
|
||||
EndIf
|
||||
EndProcedure
|
||||
|
||||
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
;- Macros
|
||||
|
||||
; Writes the 1/2/4/8/16 bytes at `Buffer` as a FixExt of type `ExtType`.
|
||||
; Returns `#MsgPack_Error_Success` on success, something else otherwise.
|
||||
|
||||
Macro MsgPackWriteFixExt1(MsgPackData, ExtType, Buffer)
|
||||
_MsgPackWriteExtField(MsgPackData, #MsgPack_FormatCode_FixExt1, 0, ExtType, Buffer, 1)
|
||||
EndMacro
|
||||
|
||||
Macro MsgPackWriteFixExt2(MsgPackData, ExtType, Buffer)
|
||||
_MsgPackWriteExtField(MsgPackData, #MsgPack_FormatCode_FixExt2, 0, ExtType, Buffer, 2)
|
||||
EndMacro
|
||||
|
||||
Macro MsgPackWriteFixExt4(MsgPackData, ExtType, Buffer)
|
||||
_MsgPackWriteExtField(MsgPackData, #MsgPack_FormatCode_FixExt4, 0, ExtType, Buffer, 4)
|
||||
EndMacro
|
||||
|
||||
Macro MsgPackWriteFixExt8(MsgPackData, ExtType, Buffer)
|
||||
_MsgPackWriteExtField(MsgPackData, #MsgPack_FormatCode_FixExt8, 0, ExtType, Buffer, 8)
|
||||
EndMacro
|
||||
|
||||
Macro MsgPackWriteFixExt16(MsgPackData, ExtType, Buffer)
|
||||
_MsgPackWriteExtField(MsgPackData, #MsgPack_FormatCode_FixExt16, 0, ExtType, Buffer, 16)
|
||||
EndMacro
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
EnableExplicit
|
||||
|
||||
XIncludeFile "../_UnitTesting.pbi"
|
||||
XIncludeFile "../../Includes/MessagePack.pbi"
|
||||
XIncludeFile "../_TestBuffers.pbi"
|
||||
|
||||
|
||||
; Note: Only covers errors that don't call `DebuggerError()`.
|
||||
; See "TestExtensionsFatalErrors.pb" for the others.
|
||||
|
||||
|
||||
; Setup
|
||||
Define *MsgPack.MsgPackData
|
||||
Define *Source = AllocatePattern(16)
|
||||
Define *Output = AllocateMemory(16)
|
||||
|
||||
|
||||
; Sizes past each format code's limit, checked before anything is allocated
|
||||
*MsgPack = MsgPackCreate(8)
|
||||
|
||||
AssertEquals(MsgPackWriteExt8(*MsgPack, 1, *Source, 256), #MsgPack_Error_BinaryDataSizeIsTooBig, "Ext8 rejects 256 bytes")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BinaryDataSizeIsTooBig, "Ext8 too big error is set")
|
||||
AssertEquals(MsgPackWriteExt16(*MsgPack, 1, *Source, 65536), #MsgPack_Error_BinaryDataSizeIsTooBig, "Ext16 rejects 65536 bytes")
|
||||
AssertEquals(MsgPackWriteExt32(*MsgPack, 1, *Source, 4294967296), #MsgPack_Error_BinaryDataSizeIsTooBig, "Ext32 rejects 2^32 bytes")
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 1, *Source, 4294967296), #MsgPack_Error_BinaryDataSizeIsTooBig, "Extension rejects 2^32 bytes")
|
||||
|
||||
AssertEquals(MsgPackWriteExt8(*MsgPack, 1, *Source, -1), #MsgPack_Error_BinaryDataSizeIsNegative, "Ext8 rejects negative sizes")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BinaryDataSizeIsNegative, "Negative size error is set")
|
||||
AssertEquals(MsgPackWriteExt16(*MsgPack, 1, *Source, -1), #MsgPack_Error_BinaryDataSizeIsNegative, "Ext16 rejects negative sizes")
|
||||
AssertEquals(MsgPackWriteExt32(*MsgPack, 1, *Source, -1), #MsgPack_Error_BinaryDataSizeIsNegative, "Ext32 rejects negative sizes")
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 1, *Source, -1), #MsgPack_Error_BinaryDataSizeIsNegative, "Extension rejects negative sizes")
|
||||
|
||||
AssertEquals(*MsgPack\BufferOffset, 0, "Offset is untouched by rejected writes")
|
||||
AssertEquals(*MsgPack\BufferSize, 8, "Buffer wasn't grown by rejected writes")
|
||||
|
||||
AssertEquals(MsgPackWriteExt8(*MsgPack, 1, *Source, 3), #MsgPack_Error_Success, "Wrote ext8 after rejected writes")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_Success, "Successful write cleared the error")
|
||||
|
||||
MsgPackFree(*MsgPack, #True)
|
||||
|
||||
|
||||
; Buffers that can't grow
|
||||
*MsgPack = WrapHex("0000000000")
|
||||
|
||||
AssertEquals(MsgPackWriteFixExt4(*MsgPack, 1, *Source), #MsgPack_Error_CannotGrowBufferDueToConfig, "fixext4's 6 bytes don't fit in 5")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_CannotGrowBufferDueToConfig, "Growth error is set")
|
||||
AssertEquals(MsgPackWriteExt8(*MsgPack, 1, *Source, 3), #MsgPack_Error_CannotGrowBufferDueToConfig, "ext8's 6 bytes don't fit in 5")
|
||||
AssertEquals(*MsgPack\BufferOffset, 0, "Offset is untouched by the failed writes")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer), $00, "Nothing was written by the failed writes")
|
||||
|
||||
AssertEquals(MsgPackWriteExt8(*MsgPack, 1, *Source, 2), #MsgPack_Error_Success, "ext8's 5 bytes fit exactly")
|
||||
AssertEquals(*MsgPack\BufferOffset, 5, "Offset is at the end")
|
||||
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("00000000")
|
||||
AssertEquals(MsgPackWriteFixExt2(*MsgPack, 1, *Source), #MsgPack_Error_Success, "fixext2's 4 bytes fit exactly")
|
||||
AssertEquals(*MsgPack\BufferOffset, 4, "Offset is at the end")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Reading at the end
|
||||
*MsgPack = WrapHex("D40100")
|
||||
*MsgPack\BufferOffset = 3
|
||||
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Read at the end fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_AtOrPastTheEndOfBuffer, "Read at the end error is set")
|
||||
AssertEquals(MsgPackCopyExtension(*MsgPack), #Null, "Copy at the end fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_AtOrPastTheEndOfBuffer, "Copy at the end error is set")
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 0, "Type at the end fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_AtOrPastTheEndOfBuffer, "Type at the end error is set")
|
||||
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Wrong format codes, in both directions
|
||||
*MsgPack = WrapHex("C4020102")
|
||||
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Reading a bin as an ext fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_InvalidFormatCode, "Bin as ext read error is set")
|
||||
AssertEquals(MsgPackCopyExtension(*MsgPack), #Null, "Copying a bin as an ext fails")
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 0, "Getting the type of a bin fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_InvalidFormatCode, "Bin type error is set")
|
||||
AssertEquals(*MsgPack\BufferOffset, 0, "Offset is untouched by the wrong format code")
|
||||
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("C702050102")
|
||||
AssertEqualsQ(MsgPackReadBinary(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Reading an ext8 as a bin fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_InvalidFormatCode, "Ext8 as bin error is set")
|
||||
Assert(Bool(MsgPackReadString(*MsgPack) = ""), "Reading an ext8 as a str fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_InvalidFormatCode, "Ext8 as str error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("D40501")
|
||||
AssertEqualsQ(MsgPackReadBinary(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Reading a fixext1 as a bin fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_InvalidFormatCode, "Fixext1 as bin error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("A3616263")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Reading a str as an ext fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_InvalidFormatCode, "Str as ext error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Truncated size and type fields
|
||||
*MsgPack = WrapHex("C7")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Ext8 without its size fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Ext8 without its size error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("C700")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Empty ext8 without its type fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Empty ext8 without its type error is set")
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 0, "Getting a missing type fails")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("C80000")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Empty ext16 without its type fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Empty ext16 without its type error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("C9000000")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Ext32 with 3/4 of its size fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Ext32 with 3/4 of its size error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("D4")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Fixext1 without its type fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Fixext1 without its type error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Truncated data
|
||||
*MsgPack = WrapHex("D6FF0000")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Fixext4 missing data fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Fixext4 missing data error is set")
|
||||
AssertEquals(MsgPackCopyExtension(*MsgPack), #Null, "Copying a fixext4 missing data fails")
|
||||
AssertEquals(*MsgPack\BufferOffset, 0, "Offset is untouched by the truncated data")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
*MsgPack = WrapHex("C705016162")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Ext8 missing data fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Ext8 missing data error is set")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
; The type byte must not be counted as data.
|
||||
*MsgPack = WrapHex("C70201AA")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Ext8 with its type as the last data byte fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Type isn't counted as data")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
; The ext32 size is unsigned, `0xFFFFFFFF` must not be read as `-1`.
|
||||
*MsgPack = WrapHex("C9FFFFFFFF0100")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), #MsgPack_InvalidSize, "Ext32 with a 0xFFFFFFFF size fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_BufferTooSmall, "Ext32 size is treated as unsigned")
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Output buffer too small, then retried
|
||||
*MsgPack = WrapHex("C70307010203")
|
||||
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 2), #MsgPack_InvalidSize, "3 bytes don't fit in 2")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_OutputBufferTooSmall, "Output too small error is set")
|
||||
AssertEquals(*MsgPack\BufferOffset, 0, "Offset is untouched so the read can be retried")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 7, "Type is still readable")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 3), 3, "Retried with an exactly sized buffer")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_Success, "Retry cleared the error")
|
||||
AssertEqualsA(PeekA(*Output), $01, "Retried data byte 1")
|
||||
AssertEqualsA(PeekA(*Output + 1), $02, "Retried data byte 2")
|
||||
AssertEqualsA(PeekA(*Output + 2), $03, "Retried data byte 3")
|
||||
AssertEquals(*MsgPack\BufferOffset, 6, "Offset is at the end")
|
||||
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Ending
|
||||
FreeMemory(*Source)
|
||||
FreeMemory(*Output)
|
||||
|
||||
If FailedUnitTests
|
||||
End 1
|
||||
EndIf
|
||||
|
||||
Debug "Done !"
|
||||
|
||||
End 0
|
||||
@@ -0,0 +1,51 @@
|
||||
EnableExplicit
|
||||
|
||||
XIncludeFile "../_UnitTesting.pbi"
|
||||
XIncludeFile "../../Includes/MessagePack.pbi"
|
||||
XIncludeFile "../_TestBuffers.pbi"
|
||||
|
||||
|
||||
; /!\ Every case here calls `DebuggerError()`, which halts the program under the debugger.
|
||||
; Run it without the debugger and check the exit code.
|
||||
|
||||
|
||||
; Setup
|
||||
Define *MsgPack.MsgPackData
|
||||
Define *Source = AllocatePattern(16)
|
||||
Define *Output = AllocateMemory(16)
|
||||
|
||||
|
||||
; Null MsgPack pointers
|
||||
AssertEquals(MsgPackWriteExt8(#Null, 1, *Source, 1), #MsgPack_Error_NullPointerGiven, "MsgPackWriteExt8 is given #Null")
|
||||
AssertEquals(MsgPackWriteExt16(#Null, 1, *Source, 1), #MsgPack_Error_NullPointerGiven, "MsgPackWriteExt16 is given #Null")
|
||||
AssertEquals(MsgPackWriteExt32(#Null, 1, *Source, 1), #MsgPack_Error_NullPointerGiven, "MsgPackWriteExt32 is given #Null")
|
||||
AssertEquals(MsgPackWriteExtension(#Null, 1, *Source, 1), #MsgPack_Error_NullPointerGiven, "MsgPackWriteExtension is given #Null for a fixext")
|
||||
AssertEquals(MsgPackWriteExtension(#Null, 1, *Source, 3), #MsgPack_Error_NullPointerGiven, "MsgPackWriteExtension is given #Null for an ext8")
|
||||
AssertEquals(MsgPackWriteFixExt1(#Null, 1, *Source), #MsgPack_Error_NullPointerGiven, "MsgPackWriteFixExt1 is given #Null")
|
||||
AssertEquals(MsgPackWriteFixExt16(#Null, 1, *Source), #MsgPack_Error_NullPointerGiven, "MsgPackWriteFixExt16 is given #Null")
|
||||
AssertEqualsQ(MsgPackReadExtension(#Null, *Output, 16), #MsgPack_InvalidSize, "MsgPackReadExtension is given #Null")
|
||||
AssertEquals(MsgPackCopyExtension(#Null), #Null, "MsgPackCopyExtension is given #Null")
|
||||
AssertEqualsB(MsgPackGetExtensionType(#Null), 0, "MsgPackGetExtensionType is given #Null")
|
||||
|
||||
|
||||
; Null output buffer with data to copy
|
||||
*MsgPack = WrapHex("D5010102")
|
||||
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, #Null, 2), #MsgPack_InvalidSize, "Reading into a #Null buffer fails")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_NullPointerGiven, "Null output buffer error is set")
|
||||
AssertEquals(*MsgPack\BufferOffset, 0, "Offset is untouched by the failed read")
|
||||
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Ending
|
||||
FreeMemory(*Source)
|
||||
FreeMemory(*Output)
|
||||
|
||||
If FailedUnitTests
|
||||
End 1
|
||||
EndIf
|
||||
|
||||
Debug "Done !"
|
||||
|
||||
End 0
|
||||
@@ -0,0 +1,255 @@
|
||||
EnableExplicit
|
||||
|
||||
XIncludeFile "../_UnitTesting.pbi"
|
||||
XIncludeFile "../../Includes/MessagePack.pbi"
|
||||
XIncludeFile "../_TestBuffers.pbi"
|
||||
|
||||
|
||||
; Setup
|
||||
; Starting with 1 byte so every write has to grow the buffer.
|
||||
Define *MsgPack.MsgPackData = MsgPackCreate(1)
|
||||
Define *Source = AllocatePattern(65536)
|
||||
Define *Output = AllocateMemory(65536)
|
||||
Define *Copy
|
||||
|
||||
Define OffsetEmpty.i, OffsetFix1.i, OffsetFix2.i, OffsetFix4.i, OffsetFix8.i, OffsetFix16.i
|
||||
Define Offset3.i, Offset255.i, Offset256.i, Offset65535.i, Offset65536.i
|
||||
Define OffsetExt8Fix.i, OffsetExt16Small.i, OffsetExt32Empty.i, OffsetFixExt4.i, OffsetFixExt16.i
|
||||
Define OffsetEnd.i
|
||||
|
||||
|
||||
; Automatic format code selection, on each boundary
|
||||
OffsetEmpty = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 5, #Null, 0), #MsgPack_Error_Success, "Wrote 0 bytes from a #Null buffer")
|
||||
OffsetFix1 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 1, *Source, 1), #MsgPack_Error_Success, "Wrote 1 byte")
|
||||
OffsetFix2 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, -1, *Source, 2), #MsgPack_Error_Success, "Wrote 2 bytes")
|
||||
OffsetFix4 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 127, *Source, 4), #MsgPack_Error_Success, "Wrote 4 bytes")
|
||||
OffsetFix8 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, -128, *Source, 8), #MsgPack_Error_Success, "Wrote 8 bytes")
|
||||
OffsetFix16 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 42, *Source, 16), #MsgPack_Error_Success, "Wrote 16 bytes")
|
||||
Offset3 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 3, *Source, 3), #MsgPack_Error_Success, "Wrote 3 bytes")
|
||||
Offset255 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 6, *Source, 255), #MsgPack_Error_Success, "Wrote 255 bytes")
|
||||
Offset256 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 7, *Source, 256), #MsgPack_Error_Success, "Wrote 256 bytes")
|
||||
Offset65535 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 8, *Source, 65535), #MsgPack_Error_Success, "Wrote 65535 bytes")
|
||||
Offset65536 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExtension(*MsgPack, 9, *Source, 65536), #MsgPack_Error_Success, "Wrote 65536 bytes")
|
||||
|
||||
|
||||
; Forced format codes, even when a smaller one fits
|
||||
OffsetExt8Fix = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExt8(*MsgPack, 10, *Source, 4), #MsgPack_Error_Success, "Wrote 4 bytes as ext8")
|
||||
OffsetExt16Small = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExt16(*MsgPack, 11, *Source, 1), #MsgPack_Error_Success, "Wrote 1 byte as ext16")
|
||||
OffsetExt32Empty = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteExt32(*MsgPack, 12, #Null, 0), #MsgPack_Error_Success, "Wrote 0 bytes as ext32")
|
||||
OffsetFixExt4 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteFixExt4(*MsgPack, 13, *Source), #MsgPack_Error_Success, "Wrote fixext4")
|
||||
OffsetFixExt16 = *MsgPack\BufferOffset
|
||||
AssertEquals(MsgPackWriteFixExt16(*MsgPack, 14, *Source), #MsgPack_Error_Success, "Wrote fixext16")
|
||||
|
||||
|
||||
; Something right after, to catch offset drifts
|
||||
AssertEquals(MsgPackWriteUInt8(*MsgPack, 42), #MsgPack_Error_Success, "Wrote trailing UInt8")
|
||||
OffsetEnd = *MsgPack\BufferOffset
|
||||
|
||||
|
||||
; Offsets
|
||||
AssertEquals(OffsetFix1, OffsetEmpty + 3, "Empty ext8 takes 3 bytes")
|
||||
AssertEquals(OffsetFix2, OffsetFix1 + 2 + 1, "fixext1 takes 3 bytes")
|
||||
AssertEquals(OffsetFix4, OffsetFix2 + 2 + 2, "fixext2 takes 4 bytes")
|
||||
AssertEquals(OffsetFix8, OffsetFix4 + 2 + 4, "fixext4 takes 6 bytes")
|
||||
AssertEquals(OffsetFix16, OffsetFix8 + 2 + 8, "fixext8 takes 10 bytes")
|
||||
AssertEquals(Offset3, OffsetFix16 + 2 + 16, "fixext16 takes 18 bytes")
|
||||
AssertEquals(Offset255, Offset3 + 3 + 3, "3 bytes ext8 takes 6 bytes")
|
||||
AssertEquals(Offset256, Offset255 + 3 + 255, "255 bytes ext8 takes 258 bytes")
|
||||
AssertEquals(Offset65535, Offset256 + 4 + 256, "256 bytes ext16 takes 260 bytes")
|
||||
AssertEquals(Offset65536, Offset65535 + 4 + 65535, "65535 bytes ext16 takes 65539 bytes")
|
||||
AssertEquals(OffsetExt8Fix, Offset65536 + 6 + 65536, "65536 bytes ext32 takes 65542 bytes")
|
||||
AssertEquals(OffsetExt16Small, OffsetExt8Fix + 3 + 4, "4 bytes ext8 takes 7 bytes")
|
||||
AssertEquals(OffsetExt32Empty, OffsetExt16Small + 4 + 1, "1 byte ext16 takes 5 bytes")
|
||||
AssertEquals(OffsetFixExt4, OffsetExt32Empty + 6, "Empty ext32 takes 6 bytes")
|
||||
AssertEquals(OffsetFixExt16, OffsetFixExt4 + 2 + 4, "Forced fixext4 takes 6 bytes")
|
||||
AssertEquals(OffsetEnd, OffsetFixExt16 + 2 + 16 + 2, "Forced fixext16 and UInt8 take 20 bytes")
|
||||
AssertEquals(*MsgPack\BufferSize, OffsetEnd, "Buffer grew to exactly what was written")
|
||||
|
||||
|
||||
; Big-endian layouts
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetEmpty), #MsgPack_FormatCode_Ext8, "Empty uses ext8")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetEmpty + 1), $00, "Empty ext8 size")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + OffsetEmpty + 2), 5, "Empty ext8 type")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix1), #MsgPack_FormatCode_FixExt1, "1 byte uses fixext1")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + OffsetFix1 + 1), 1, "fixext1 type")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix1 + 2), PeekA(*Source), "fixext1 data")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix2), #MsgPack_FormatCode_FixExt2, "2 bytes uses fixext2")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix2 + 1), $FF, "fixext2 negative type")
|
||||
Assert(CompareMemory(*MsgPack\Buffer + OffsetFix2 + 2, *Source, 2), "fixext2 data")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix4), #MsgPack_FormatCode_FixExt4, "4 bytes uses fixext4")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix4 + 1), $7F, "fixext4 type")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix8), #MsgPack_FormatCode_FixExt8, "8 bytes uses fixext8")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix8 + 1), $80, "fixext8 type")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFix16), #MsgPack_FormatCode_FixExt16, "16 bytes uses fixext16")
|
||||
Assert(CompareMemory(*MsgPack\Buffer + OffsetFix16 + 2, *Source, 16), "fixext16 data")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset3), #MsgPack_FormatCode_Ext8, "3 bytes uses ext8")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset3 + 1), $03, "3 bytes ext8 size")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + Offset3 + 2), 3, "3 bytes ext8 type")
|
||||
Assert(CompareMemory(*MsgPack\Buffer + Offset3 + 3, *Source, 3), "3 bytes ext8 data")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset255), #MsgPack_FormatCode_Ext8, "255 bytes uses ext8")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset255 + 1), $FF, "255 bytes ext8 size")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset256), #MsgPack_FormatCode_Ext16, "256 bytes uses ext16")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset256 + 1), $01, "256 bytes ext16 size high byte")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset256 + 2), $00, "256 bytes ext16 size low byte")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + Offset256 + 3), 7, "256 bytes ext16 type")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65535), #MsgPack_FormatCode_Ext16, "65535 bytes uses ext16")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65535 + 1), $FF, "65535 bytes ext16 size high byte")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65535 + 2), $FF, "65535 bytes ext16 size low byte")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65536), #MsgPack_FormatCode_Ext32, "65536 bytes uses ext32")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65536 + 1), $00, "65536 bytes ext32 size byte 1")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65536 + 2), $01, "65536 bytes ext32 size byte 2")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65536 + 3), $00, "65536 bytes ext32 size byte 3")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + Offset65536 + 4), $00, "65536 bytes ext32 size byte 4")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + Offset65536 + 5), 9, "65536 bytes ext32 type")
|
||||
Assert(CompareMemory(*MsgPack\Buffer + Offset65536 + 6, *Source, 65536), "65536 bytes ext32 data")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetExt8Fix), #MsgPack_FormatCode_Ext8, "Forced 4 bytes ext8")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetExt8Fix + 1), $04, "Forced 4 bytes ext8 size")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + OffsetExt8Fix + 2), 10, "Forced 4 bytes ext8 type")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetExt32Empty), #MsgPack_FormatCode_Ext32, "Forced empty ext32")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetExt32Empty + 4), $00, "Forced empty ext32 size byte 4")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + OffsetExt32Empty + 5), 12, "Forced empty ext32 type")
|
||||
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFixExt4), #MsgPack_FormatCode_FixExt4, "Forced fixext4")
|
||||
AssertEqualsA(PeekA(*MsgPack\Buffer + OffsetFixExt16), #MsgPack_FormatCode_FixExt16, "Forced fixext16")
|
||||
AssertEqualsB(PeekB(*MsgPack\Buffer + OffsetFixExt16 + 1), 14, "Forced fixext16 type")
|
||||
|
||||
|
||||
; Reading them back
|
||||
*MsgPack\BufferOffset = 0
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 5, "Empty ext8 type is read")
|
||||
AssertEquals(*MsgPack\BufferOffset, 0, "Reading the type didn't move the offset")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, #Null, 0), 0, "Read empty ext8 into a #Null buffer")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_Success, "Empty read is a success")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 1, "fixext1 type is read")
|
||||
FillMemory(*Output, 65536, $AA)
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 1), 1, "Read fixext1 into an exactly sized buffer")
|
||||
AssertEqualsA(PeekA(*Output), PeekA(*Source), "fixext1 data matches")
|
||||
AssertEqualsA(PeekA(*Output + 1), $AA, "Nothing written past the data")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), -1, "fixext2 negative type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 2, "Read fixext2")
|
||||
Assert(CompareMemory(*Output, *Source, 2), "fixext2 data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 127, "fixext4 type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 4, "Read fixext4")
|
||||
Assert(CompareMemory(*Output, *Source, 4), "fixext4 data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), -128, "fixext8 type is read")
|
||||
*Copy = MsgPackCopyExtension(*MsgPack)
|
||||
Assert(Bool(*Copy <> #Null), "Copied fixext8")
|
||||
If *Copy
|
||||
AssertEquals(MemorySize(*Copy), 8, "Copy is exactly 8 bytes")
|
||||
Assert(CompareMemory(*Copy, *Source, 8), "fixext8 data matches")
|
||||
FreeMemory(*Copy)
|
||||
EndIf
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 42, "fixext16 type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 16), 16, "Read fixext16")
|
||||
Assert(CompareMemory(*Output, *Source, 16), "fixext16 data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 3, "3 bytes ext8 type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 3, "Read 3 bytes ext8")
|
||||
Assert(CompareMemory(*Output, *Source, 3), "3 bytes ext8 data matches")
|
||||
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 255), 255, "Read 255 bytes ext8")
|
||||
Assert(CompareMemory(*Output, *Source, 255), "255 bytes data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 7, "256 bytes ext16 type is read")
|
||||
*Copy = MsgPackCopyExtension(*MsgPack)
|
||||
Assert(Bool(*Copy <> #Null), "Copied 256 bytes")
|
||||
If *Copy
|
||||
AssertEquals(MemorySize(*Copy), 256, "Copy is exactly 256 bytes")
|
||||
Assert(CompareMemory(*Copy, *Source, 256), "256 bytes data matches")
|
||||
FreeMemory(*Copy)
|
||||
EndIf
|
||||
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 65535, "Read 65535 bytes ext16")
|
||||
Assert(CompareMemory(*Output, *Source, 65535), "65535 bytes data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 9, "65536 bytes ext32 type is read")
|
||||
*Copy = MsgPackCopyExtension(*MsgPack)
|
||||
Assert(Bool(*Copy <> #Null), "Copied 65536 bytes")
|
||||
If *Copy
|
||||
AssertEquals(MemorySize(*Copy), 65536, "Copy is exactly 65536 bytes")
|
||||
Assert(CompareMemory(*Copy, *Source, 65536), "65536 bytes data matches")
|
||||
FreeMemory(*Copy)
|
||||
EndIf
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 10, "Forced ext8 type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 4, "Read forced 4 bytes ext8")
|
||||
Assert(CompareMemory(*Output, *Source, 4), "Forced 4 bytes ext8 data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 11, "Forced ext16 type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 1, "Read forced 1 byte ext16")
|
||||
AssertEqualsA(PeekA(*Output), PeekA(*Source), "Forced 1 byte ext16 data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 12, "Forced ext32 type is read")
|
||||
AssertEquals(MsgPackCopyExtension(*MsgPack), #Null, "Copying an empty ext32 returns #Null")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_Success, "Empty copy is a success")
|
||||
AssertEquals(*MsgPack\BufferOffset, OffsetFixExt4, "Empty copy still moved the offset")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 13, "Forced fixext4 type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 4, "Read forced fixext4")
|
||||
Assert(CompareMemory(*Output, *Source, 4), "Forced fixext4 data matches")
|
||||
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), 14, "Forced fixext16 type is read")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 65536), 16, "Read forced fixext16")
|
||||
Assert(CompareMemory(*Output, *Source, 16), "Forced fixext16 data matches")
|
||||
|
||||
AssertEqualsA(MsgPackReadUInt8(*MsgPack), 42, "Read trailing UInt8")
|
||||
AssertEquals(*MsgPack\BufferOffset, OffsetEnd, "Offset is at the end")
|
||||
AssertEquals(MsgPackLastError(*MsgPack), #MsgPack_Error_Success, "No error after reading")
|
||||
|
||||
MsgPackFree(*MsgPack, #True)
|
||||
|
||||
|
||||
; Known vector: timestamp 32 for 1970-01-01T00:00:01Z
|
||||
*MsgPack = WrapHex("D6FF00000001")
|
||||
|
||||
AssertEquals(MsgPackFormatCodeToDataType(MsgPackGetFormatCode(*MsgPack)), #MsgPack_DataTypes_Extension, "Timestamp is detected as an extension")
|
||||
AssertEqualsB(MsgPackGetExtensionType(*MsgPack), -1, "Timestamp type is -1")
|
||||
AssertEqualsQ(MsgPackReadExtension(*MsgPack, *Output, 4), 4, "Read the timestamp's 4 bytes")
|
||||
AssertEquals(EndianSwapI32(PeekL(*Output)), 1, "Timestamp seconds are big-endian")
|
||||
AssertEquals(*MsgPack\BufferOffset, 6, "Offset is at the end")
|
||||
|
||||
FreeWrappedHex(*MsgPack)
|
||||
|
||||
|
||||
; Ending
|
||||
FreeMemory(*Source)
|
||||
FreeMemory(*Output)
|
||||
|
||||
If FailedUnitTests
|
||||
End 1
|
||||
EndIf
|
||||
|
||||
Debug "Done !"
|
||||
|
||||
End 0
|
||||
Reference in New Issue
Block a user