Crossplatform UUID/GUID functions (API Version)

Share your advanced PureBasic knowledge/code with the community.
Justin
Addict
Addict
Posts: 829
Joined: Sat Apr 26, 2003 2:49 pm

Crossplatform UUID/GUID functions (API Version)

Post by Justin »

Functions to create unique identifiers in binary or string format like "59a7461e-a234-4b41-8237-9be9e338b58e" for example.
I have seen some code in the forum using pb functions but i wanted to try the API versions.

I think in linux the lib is included but if not use: sudo apt-get install uuid-dev

In mac i used an autorelease pool for each call, i guess everything is released correctly. Wilbert?

Very easy to use, function names are self explanatory, see example.

Edit: Fixed objects release.
Edit2: Fixed objects release again.

Code: Select all

;Crossplatform UUID functions.
;Justin 11/19
;Ver: 1.2

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
	
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
	ImportC "-luuid"
		uuid_generate_time_safe_(id.i) As "uuid_generate_time_safe"
		uuid_unparse_(uuid.i, c.i) As "uuid_unparse"
		uuid_parse_(st.p-UTF8, uid.i) As "uuid_parse"
	EndImport
	
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS

CompilerEndIf 

;- UUID
Structure UUID
	data1.l
	data2.w
	data3.w
	data4.b[8]
EndStructure

Macro uuid_IsEqual(uid1, uid2)
	CompareMemory(uid1, uid2, SizeOf(UUID))
EndMacro 

;Creates a new UUID in binary format.
Procedure uuid_Create(*uid.UUID)
	Protected ret
	
	If *uid = #Null : ProcedureReturn #False : EndIf
	
	ret = #False
	
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		If UuidCreate_(*uid) = #RPC_S_OK
			ret = #True
		EndIf 

	CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux		
		If uuid_generate_time_safe_(*uid) = 0
			ret = #True
		EndIf 
	
	CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
		Protected.i idref
				
		idref = CocoaMessage(0, CocoaMessage(0, 0, "NSUUID alloc"), "init")
		If idref
			CocoaMessage(0, idref, "getUUIDBytes:", *uid)
			CocoaMessage(0, idref, "release") ;alloc
			CocoaMessage(0, idref, "release") ;init
			ret = #True
		EndIf 
	CompilerEndIf 
	
	ProcedureReturn ret 
EndProcedure

;Transforms a binary uuid to its string representation.
Procedure.s uuid_ToString(*uid.UUID)
	Protected.s st
	
	If *uid = #Null : ProcedureReturn "" : EndIf 

	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		Protected.i pst
		
		If UuidToString_(*uid, @pst) = #RPC_S_OK
			If pst
				st = PeekS(pst, -1, #PB_Unicode)
				RpcStringFree_(@pst)
			EndIf
		EndIf 

	CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
		Protected.i buf

		buf = AllocateMemory(37)
		uuid_unparse_(*uid, buf)
		st = PeekS(buf, -1, #PB_UTF8)
		FreeMemory(buf)
		
	CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
		Protected.i idref, nsStr, strBuf
				
		idref = CocoaMessage(0, CocoaMessage(0, 0, "NSUUID alloc"), "initWithUUIDBytes:", *uid)
		If idref
			nsStr = CocoaMessage(0, idref, "UUIDString")
			If nsStr
				strBuf = CocoaMessage(0, nsStr, "UTF8String")
				If strBuf
					st = PeekS(strBuf, -1, #PB_UTF8)
				EndIf
				
				CocoaMessage(0, nsStr, "release")
			EndIf 
			
			CocoaMessage(0, idref, "release") ;alloc
			CocoaMessage(0, idref, "release") ;init
		EndIf 
	CompilerEndIf 
	
	ProcedureReturn st
EndProcedure

;Transfrom a string uuid to its binary format.
Procedure uuid_FromString(st.s, *uid.UUID)
	Protected ret
	
	If *uid = #Null : ProcedureReturn #Null : EndIf
	
	ret = #False
	
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		If UuidFromString_(st, *uid) = #RPC_S_OK
			ret = #True
		EndIf 
		
	CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
		If uuid_parse_(st, *uid) = 0
			ret = #True
		EndIf
		
	CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
		Protected.i idref
				
		idref = CocoaMessage(0, CocoaMessage(0, 0, "NSUUID alloc"), "initWithUUIDString:$", @st)
		If idref
			CocoaMessage(0, idref, "getUUIDBytes:", *uid)
			CocoaMessage(0, idref, "release") ;alloc
			CocoaMessage(0, idref, "release") ;init
			ret = #True
		EndIf 	
	CompilerEndIf 
	
	ProcedureReturn ret
EndProcedure

Procedure uuid_IsNull(*uid.UUID)
	Protected.UUID idNull
	
	ProcedureReturn uuid_IsEqual(*uid, @idNull)
EndProcedure


;- TEST
EnableExplicit

Define.s sid2
Define.UUID id1, id2

sid2 = "59a7461e-a234-4b41-8237-9be9e338b58e"

uuid_Create(@id1)
uuid_FromString(sid2, @id2)

Debug uuid_ToString(@id1)
Debug uuid_ToString(@id2)

Debug "Are equal " + uuid_IsEqual(@id1, @id2)
Last edited by Justin on Tue Nov 19, 2019 11:30 pm, edited 3 times in total.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Crossplatform UUID/GUID functions (API Version)

Post by Kwai chang caine »

Compiler wrote:cf618a44-aba9-406b-b47e-ca5a8c2f440e
Are equal 0
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Crossplatform UUID/GUID functions (API Version)

Post by wilbert »

Justin wrote:In mac i used an autorelease pool for each call, i guess everything is released correctly. Wilbert?
No, when you use alloc / init, the returned object is not an autorelease object but it should be released manually.
And according to the docs, getUUIDBytes does not have a return value so checking it for being equal to 16 is not safe.

Example ...

Code: Select all

idref = CocoaMessage(0, 0, "NSUUID new")
CocoaMessage(0, idref, "getUUIDBytes:", *uid)
CocoaMessage(0, idref, "release")
ret = #True

idref = CocoaMessage(0, CocoaMessage(0, 0, "NSUUID alloc"), "initWithUUIDString:$", @st)
CocoaMessage(0, idref, "getUUIDBytes:", *uid)
CocoaMessage(0, idref, "release")
ret = #True
By the way, the following C functions are available both on macOS and Linux.
uuid_parse, uuid_unparse, uuid_generate, uuid_generate_random, uuid_generate_time
Windows (x64)
Raspberry Pi OS (Arm64)
Justin
Addict
Addict
Posts: 829
Joined: Sat Apr 26, 2003 2:49 pm

Re: Crossplatform UUID/GUID functions (API Version)

Post by Justin »

Hi Wilbert, thanks for the tips.

I got rid of the autorelease pool and did it manually, code updated.

With the C functions should be trivial using import, i leave the cocoa version for reference.
Justin
Addict
Addict
Posts: 829
Joined: Sat Apr 26, 2003 2:49 pm

Re: Crossplatform UUID/GUID functions (API Version)

Post by Justin »

Fixed the release stuff again it seems a release its needed for both alloc and init. I think is ok now.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Crossplatform UUID/GUID functions (API Version)

Post by mk-soft »

Endlich eine gültige UUID für alle OS :wink:

Wenn du noch statt Define in Procedure Protected verwendest und
für "ret.b" und "Procedure.b" statt Byte den Type Integer verwendest, ist alles gut.

Boolean als Rückgabewert ist auf allen OS ein Type Integer. Sonst wird mehr unnötiger ASM Code erzeugt, um das Byte zu Filtern.
Man spart also nichts, wenn man Byte für Boolean nimmt.

Kleine Anpassung für Windows ...
Es kann drei verschiedene Ergebnisse kommen. Ich glaube alles drei sind akzeptabel.

Code: Select all

;Creates a new UUID in binary format.
Procedure uuid_Create(*uid.UUID)
  Protected.i ret
  
  If *uid = #Null : ProcedureReturn #False : EndIf
  
  ret = #False
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Protected r1
    r1 = UuidCreate_(*uid)
    If r1 = #RPC_S_OK Or r1 = #RPC_S_UUID_LOCAL_ONLY Or r1 = #RPC_S_UUID_NO_ADDRESS
      ret = #True
    EndIf 
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Justin
Addict
Addict
Posts: 829
Joined: Sat Apr 26, 2003 2:49 pm

Re: Crossplatform UUID/GUID functions (API Version)

Post by Justin »

Hi mk-soft,
i changed to protected and return integer. About the error codes i'm not sure, i think i will stick to RPC_S_OK otherwise i would have to somehow handle those errors.
Everything
Enthusiast
Enthusiast
Posts: 224
Joined: Sat Jul 07, 2018 6:50 pm

Re: Crossplatform UUID/GUID functions (API Version)

Post by Everything »

mk-soft wrote:

Code: Select all

    r1 = UuidCreate_(*uid)
BTW
If you do not need such level of security, your application can use the UuidCreateSequential function, which behaves exactly as the UuidCreate function does on all other versions of the operating system.
The UuidCreateSequential function tends to be slightly faster than the UuidCreate function. When the performance of the generation of a UUID is a significant consideration, the UuidCreateSequential function may be used.
Post Reply