It is not an official JSON extension, but some companies does this.
To make it fast and without additional memory usage, I used the memory of the string and replace all comments with spaces.
Spaces are allowed inside of a JSON, so I can afterwards using ParseJSON() as usual.
I'm using a state machine to detect the different possibilities.
Code: Select all
;
; LoadJSONC()
;
; https://www.purebasic.fr/english/viewtopic.php?t=83647
;
; V1.0.1 2024.02.24 allow single /
; V1.0.0 2024.02.23 first version
;
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
Enumeration LoadJSONC_States
#LoadJSONC_State_Search
#LoadJSONC_State_FirstSlashFound
#LoadJSONC_State_SecondSlashFound
#LoadJSONC_State_FirstAsteriskFound
#LoadJSONC_State_SecondAsteriskFound
EndEnumeration
Procedure.i LoadJSONC(JSON.i, Filename$, Flags.i=0)
Protected File.i, Format.i, JSON$, *CharPtr.Character, State.i, EscapeFlag.i
File = ReadFile(#PB_Any, Filename$)
If File
Format = ReadStringFormat(File)
JSON$ = ReadString(File, Format|#PB_File_IgnoreEOL)
CloseFile(File)
If JSON$ <> ""
*CharPtr = @JSON$
While *CharPtr\c <> #Null
Select State
Case #LoadJSONC_State_Search
Select *CharPtr\c
Case '/'
If Not EscapeFlag
; maybe start o a comment
State = #LoadJSONC_State_FirstSlashFound
EndIf
Case '\'
; the next character is escaped -> ignore it
EscapeFlag = #True
Default
EscapeFlag = #False
EndSelect
Case #LoadJSONC_State_FirstSlashFound
Select *CharPtr\c
Case '/'
; // detected -> replace them
*CharPtr - SizeOf(Character)
*CharPtr\c = ' '
*CharPtr + SizeOf(Character)
*CharPtr\c = ' '
State = #LoadJSONC_State_SecondSlashFound
Case '*'
; /* detected -> replace them
*CharPtr - SizeOf(Character)
*CharPtr\c = ' '
*CharPtr + SizeOf(Character)
*CharPtr\c = ' '
State = #LoadJSONC_State_FirstAsteriskFound
Default
State = #LoadJSONC_State_Search
EndSelect
Case #LoadJSONC_State_SecondSlashFound
; wait until end of line is reached
If *CharPtr\c = #LF Or *CharPtr\c = #CR
State = #LoadJSONC_State_Search
Else
*CharPtr\c = ' '
EndIf
Case #LoadJSONC_State_FirstAsteriskFound
; wait for second * -> replace everything
If *CharPtr\c = '*'
State = #LoadJSONC_State_SecondAsteriskFound
EndIf
*CharPtr\c = ' '
Case #LoadJSONC_State_SecondAsteriskFound
If *CharPtr\c = '/'
; */ found -> replace it and start searching for comments
*CharPtr\c = ' '
State = #LoadJSONC_State_Search
Else
; not a comment termination -> replace it ands wait for */
*CharPtr\c = ' '
State = #LoadJSONC_State_FirstAsteriskFound
EndIf
EndSelect
*CharPtr + SizeOf(Character)
Wend
JSON = ParseJSON(JSON, JSON$, Flags)
EndIf
EndIf
ProcedureReturn JSON
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Define Filename$, JSON.i
Filename$ = OpenFileRequester("Choose a JSONC file", "", "JSONC|*.json;*jsonc", 0)
If Filename$
JSON = LoadJSONC(#PB_Any, Filename$)
If JSON
Debug ComposeJSON(JSON, #PB_JSON_PrettyPrint)
FreeJSON(JSON)
EndIf
EndIf
CompilerEndIf
Code: Select all
/*
* Description
*/
{
// rainbows
"uni/corn": /* ? */ "c\/*/ake"
}