I ported the C example to PB:
Code: Select all
;
; https://github.com/maelh/hxd-plugin-framework
;
; ported to PureBasic by infratec
;
; https://www.purebasic.fr/english/viewtopic.php?p=565301#p565301
;
; 2021-02-04 first public release
;
EnableExplicit
CompilerIf #PB_Compiler_ExecutableFormat <> #PB_Compiler_DLL And Not #PB_Compiler_Debugger
CompilerError "Set the excutable format to 'Shared DLL'"
CompilerEndIf
#Debugging = #False
#MaxConverterCount = 10
;-Macros
Macro TByteOrders
Ascii
EndMacro
Macro TConverterClassID
i
EndMacro
Macro PConverterClassID
Integer
EndMacro
Macro TDataTypeWidth
Integer
EndMacro
;-Enumerations
Enumeration TByteOrder
#boLittleEndian
#boBigEndian
EndEnumeration
Enumeration TDataTypeWidth
#dtwVariable
#dtwFixed
EndEnumeration
Enumeration TIntegerDisplayOption
#idoDecimal
#idoHexadecimalUpperCase
#idoHexadecimalLowerCase
EndEnumeration
Enumeration TBytesToStrError
#btseNone
#btseInvalidBytes
#btseBytesTooShort
EndEnumeration
Enumeration TStrToBytesError
#stbeNone
#stbeInvalidString
#stbeUnderflow
#stbeOverflow
#stbeOutOfRange ;If unclear whether underflow Or overflow
EndEnumeration
Structure TInt32ConverterInstance
; NOTE: For simpliciy the Array sizes were chosen statically For the
; int32_t type, but you may need To dynamically allocate memory For other
; converter types To Not waste memory; in this case, make sure to allocate
; And initialize in CreateConverter, And deallocate in DestroyConverter.
; What matters is that each converter instance has its own memory, that
; holds converted Data returned by BytesToStr And StrToBytes (see the
; comment at file start).
ConvertedStr.s{128} ; // smaller should be fine, but depends on maximal length of formatted string
ConvertedBytes.a[SizeOf(Long)]
EndStructure
Structure TConverterClassIDStructure
i.i[#MaxConverterCount]
EndStructure
Prototype TClassIDOrFactoryFunc()
;-Declarations (needed public procedures)
DeclareDLL AttachProcess(Instance.i)
DeclareDLL.i GetDataTypeConverters(*ClassIDsOrFactoryFuncs.PConverterClassID, *Count.Integer)
DeclareDLL.i CreateConverter(ClassIDOrFactoryFunc.TConverterClassID, *TypeName.Integer, *FriendlyTypeName.Integer, *Width.TDataTypeWidth, *MaxTypeSize.Integer, *SupportedByteOrders.TByteOrders)
DeclareDLL DestroyConverter(*ThisPtr)
DeclareDLL AssignConverter(*ThisPtr.TInt32ConverterInstance, *Source.TInt32ConverterInstance)
DeclareDLL ChangeByteOrder(*ThisPtr, *Bytes, ByteCount.i, TargetByteOrder.i)
DeclareDLL.i BytesToStr(*ThisPtr, *Bytes, ByteCount.i, IntegerDisplayOption.i, *ConvertedByteCount.Integer, *ConvertedStr.Integer)
DeclareDLL.i StrToBytes(*ThisPtr, Str$, IntegerDisplayOption.i, *ConvertedBytes.Integer, *ConvertedByteCount.Integer)
;-Globals
Global InternalClassIDsOrFactoryFuncs.TConverterClassIDStructure
Global ConverterCount.i
Global Int32ConverterClassID.i
;-Debug tool
Macro DebugLogging(Text)
CompilerIf Defined(Debugging, #PB_Constant)
CompilerIf #Debugging
Logging(Text)
CompilerEndIf
CompilerEndIf
EndMacro
CompilerIf Defined(Debugging, #PB_Constant)
CompilerIf #Debugging
Procedure Logging(Text$)
Protected File.i
;File = OpenFile(#PB_Any, GetPathPart(ProgramFilename()) + GetFilePart(ProgramFilename(), #PB_FileSystem_NoExtension) + ".log", #PB_File_Append)
File = OpenFile(#PB_Any, GetFilePart(ProgramFilename(), #PB_FileSystem_NoExtension) + ".log", #PB_File_Append)
If File
;WriteStringN(File, FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date()) + " " + Text$)
WriteStringN(File, Text$)
CloseFile(File)
EndIf
EndProcedure
CompilerEndIf
CompilerEndIf
;-Main procedures
Procedure RegisterDataTypeConverter(ClassIDOrFactoryFunc.TClassIDOrFactoryFunc)
DebugLogging("RegisterDataTypeConverter")
If ConverterCount < #MaxConverterCount
DebugLogging("RegisterDataTypeConverter inside if ClassIDOrFactoryFunc: [" + Str(ConverterCount) + "] " + Hex(ClassIDOrFactoryFunc))
InternalClassIDsOrFactoryFuncs\i[ConverterCount] = ClassIDOrFactoryFunc
ConverterCount + 1
EndIf
;DebugLogging("RegisterDataTypeConverter End")
EndProcedure
ProcedureDLL.i GetDataTypeConverterClassIDs(*ClassIDsOrFactoryFuncs.PConverterClassID, *Count.Long)
DebugLogging("GetDataTypeConverterClassIDs")
If ConverterCount > 0
*ClassIDsOrFactoryFuncs\i = @InternalClassIDsOrFactoryFuncs\i[0]
Else
*ClassIDsOrFactoryFuncs\i = #Null
EndIf
*Count\l = ConverterCount
;DebugLogging("GetDataTypeConverterClassIDs end")
ProcedureReturn #True
EndProcedure
ProcedureDLL AttachProcess(Instance.i)
;DebugLogging("AttachProcess")
Int32ConverterClassID = 66
RegisterDataTypeConverter(@Int32ConverterClassID)
EndProcedure
ProcedureDLL AttachThread(Instance.i)
;DebugLogging("AttachThread")
EndProcedure
ProcedureDLL DetachThread(Instance.i)
;DebugLogging("DetachThread")
EndProcedure
ProcedureDLL DetachProcess(Instance.i)
;DebugLogging("DetachProcess")
EndProcedure
Procedure.l ByteSwap(UI32.l)
ProcedureReturn ((UI32 & $000000FF) << 24) | ((UI32 & $0000FF00) << 8) | ((UI32 & $00FF0000) >> 8) | ((UI32 & $FF000000) >> 24)
EndProcedure
ProcedureDLL.i CreateConverter(ClassIDOrFactoryFunc.TConverterClassID, *TypeName.Integer, *FriendlyTypeName.Integer, *Width.TDataTypeWidth, *MaxTypeSize.Integer, *SupportedByteOrders.TByteOrders)
Protected *Converter.TInt32ConverterInstance
DebugLogging("CreateConverter")
; ClassIDOrFactoryFunc can be used To delegate creation To constructor
; functions As needed. See the C++ plugin For an example.
; Here we just support one converter type, so it suffices To check we were
; called To construct the right converter.
If ClassIDOrFactoryFunc = @Int32ConverterClassID
*TypeName\i = @"PB - Int32"
*FriendlyTypeName\i = *TypeName\i
*Width\i = #dtwFixed
*MaxTypeSize\i = SizeOf(Long)
*SupportedByteOrders\a = 1 << #boLittleEndian | 1 << #boBigEndian
*Converter = AllocateMemory(SizeOf(TInt32ConverterInstance))
EndIf
DebugLogging("CreateConverter End")
ProcedureReturn *Converter
EndProcedure
ProcedureDLL DestroyConverter(*ThisPtr)
DebugLogging("DestroyConverter")
FreeMemory(*ThisPtr)
DebugLogging("DestroyConverter End")
EndProcedure
ProcedureDLL AssignConverter(*ThisPtr.TInt32ConverterInstance, *Source.TInt32ConverterInstance)
DebugLogging("AssignConverter")
CopyMemory(@*Source\ConvertedBytes[0], @*ThisPtr\ConvertedBytes[0], SizeOf(*Source\ConvertedBytes))
CopyMemory(@*Source\ConvertedStr, @*ThisPtr\ConvertedStr, SizeOf(*Source\ConvertedStr))
DebugLogging("AssignConverter End")
EndProcedure
ProcedureDLL ChangeByteOrder(*ThisPtr, *Bytes, ByteCount.i, TargetByteOrder.i)
DebugLogging("ChangeByteOrder")
If TargetByteOrder = #boBigEndian And ByteCount >= SizeOf(long)
PokeL(*Bytes, ByteSwap(PeekL(*Bytes)))
EndIf
DebugLogging("ChangeByteOrder End")
EndProcedure
ProcedureDLL.i BytesToStr(*ThisPtr, *Bytes, ByteCount.i, IntegerDisplayOption.i, *ConvertedByteCount.Integer, *ConvertedStr.Integer)
Protected Result.l
Protected *Converter.TInt32ConverterInstance
DebugLogging("BytesToStr")
*Converter = *ThisPtr
If ByteCount >= SizeOf(long)
Select IntegerDisplayOption
Case #idoDecimal
DebugLogging("idoDecimal")
*Converter\ConvertedStr = Str(PeekL(*Bytes))
Case #idoHexaDecimalUpperCase
DebugLogging("idoHexaDecimalUpperCase")
;*Converter\ConvertedStr = UCase(RSet(Hex(PeekL(*Bytes) & $FFFFFFFF), 8, "0"))
*Converter\ConvertedStr = UCase(Hex(PeekL(*Bytes) & $FFFFFFFF))
Case #idoHexaDecimalLowerCase
DebugLogging("idoHexaDecimalLowerCase")
;*Converter\ConvertedStr = LCase(RSet(Hex(PeekL(*Bytes) & $FFFFFFFF), 8, "0"))
*Converter\ConvertedStr = LCase(Hex(PeekL(*Bytes) & $FFFFFFFF))
EndSelect
*ConvertedStr\i = @*Converter\ConvertedStr
*ConvertedByteCount\i = SizeOf(long)
Result = #btseNone
Else
*Converter\ConvertedStr = ""
*ConvertedStr\i = @*Converter\ConvertedStr
*ConvertedByteCount\i = 0
Result = #btseBytesTooShort
EndIf
DebugLogging("BytesToStr End")
ProcedureReturn Result
EndProcedure
ProcedureDLL.i StrToBytes(*ThisPtr, Str$, IntegerDisplayOption.i, *ConvertedBytes.Integer, *ConvertedByteCount.Integer)
Protected Result.l, Value.q
Protected *Converter.TInt32ConverterInstance
DebugLogging("StrToBytes")
*Converter = *ThisPtr
Str$ = LTrim(Str$)
If IntegerDisplayOption = #idoHexaDecimalUpperCase Or IntegerDisplayOption = #idoHexaDecimalLowerCase
Str$ = "$" + Str$
EndIf
Value = Val(Str$)
If Value > $FFFFFFFF
PokeQ(@*Converter\ConvertedBytes[0], Value)
*ConvertedByteCount\i = SizeOf(Quad)
Else
PokeL(@*Converter\ConvertedBytes[0], Value)
*ConvertedByteCount\i = SizeOf(Integer)
EndIf
*ConvertedBytes\i = @*Converter\ConvertedBytes[0]
Result = #stbeNone
DebugLogging("StrToBytes End")
ProcedureReturn Result
EndProcedure