1
1
Attribute VB_Name = "JsonConverter"
2
2
''
3
- ' VBA-JSON v2.2.3
3
+ ' VBA-JSON v2.2.4
4
4
' (c) Tim Hall - https://github.com/VBA-tools/VBA-JSON
5
5
'
6
6
' JSON Converter for VBA
@@ -54,7 +54,7 @@ Option Explicit
54
54
Private Declare PtrSafe Function utc_popen Lib "libc .dylib " Alias "popen " _
55
55
(ByVal utc_Command As String , ByVal utc_Mode As String ) As LongPtr
56
56
Private Declare PtrSafe Function utc_pclose Lib "libc .dylib " Alias "pclose " _
57
- (ByVal utc_File As Long ) As LongPtr
57
+ (ByVal utc_File As LongPtr ) As LongPtr
58
58
Private Declare PtrSafe Function utc_fread Lib "libc .dylib " Alias "fread " _
59
59
(ByVal utc_Buffer As String , ByVal utc_Size As LongPtr , ByVal utc_Number As LongPtr , ByVal utc_File As LongPtr ) As LongPtr
60
60
Private Declare PtrSafe Function utc_feof Lib "libc .dylib " Alias "feof " _
@@ -140,7 +140,6 @@ End Type
140
140
#End If
141
141
' === End VBA-UTC
142
142
143
-
144
143
Private Type json_Options
145
144
' VBA only stores 15 significant digits, so any numbers larger than that are truncated
146
145
' This can lead to issues when BIGINT's are used (e.g. for Ids or Credit Cards), as they will be invalid above 15 digits
@@ -198,7 +197,9 @@ End Function
198
197
' @return {String}
199
198
''
200
199
Public Function ConvertToJson (ByVal JsonValue As Variant , Optional ByVal Whitespace As Variant , Optional ByVal json_CurrentIndentation As Long = 0 ) As String
201
- Dim cSA As New clsStringAppend
200
+ Dim json_Buffer As String
201
+ Dim json_BufferPosition As Long
202
+ Dim json_BufferLength As Long
202
203
Dim json_Index As Long
203
204
Dim json_LBound As Long
204
205
Dim json_UBound As Long
@@ -257,7 +258,7 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
257
258
End If
258
259
259
260
' Array
260
- cSA.Append "["
261
+ json_BufferAppend json_Buffer, "[" , json_BufferPosition, json_BufferLength
261
262
262
263
On Error Resume Next
263
264
@@ -272,21 +273,21 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
272
273
json_IsFirstItem = False
273
274
Else
274
275
' Append comma to previous line
275
- cSA.Append ","
276
+ json_BufferAppend json_Buffer, "," , json_BufferPosition, json_BufferLength
276
277
End If
277
278
278
279
If json_LBound2D >= 0 And json_UBound2D >= 0 Then
279
280
' 2D Array
280
281
If json_PrettyPrint Then
281
- cSA.Append vbNewLine
282
+ json_BufferAppend json_Buffer, vbNewLine, json_BufferPosition, json_BufferLength
282
283
End If
283
- cSA.Append json_Indentation & "["
284
+ json_BufferAppend json_Buffer, json_Indentation & "[" , json_BufferPosition, json_BufferLength
284
285
285
286
For json_Index2D = json_LBound2D To json_UBound2D
286
287
If json_IsFirstItem2D Then
287
288
json_IsFirstItem2D = False
288
289
Else
289
- cSA.Append ","
290
+ json_BufferAppend json_Buffer, "," , json_BufferPosition, json_BufferLength
290
291
End If
291
292
292
293
json_Converted = ConvertToJson(JsonValue(json_Index, json_Index2D), Whitespace, json_CurrentIndentation + 2 )
@@ -303,14 +304,14 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
303
304
json_Converted = vbNewLine & json_InnerIndentation & json_Converted
304
305
End If
305
306
306
- cSA.Append json_Converted
307
+ json_BufferAppend json_Buffer, json_Converted, json_BufferPosition, json_BufferLength
307
308
Next json_Index2D
308
309
309
310
If json_PrettyPrint Then
310
- cSA.Append vbNewLine
311
+ json_BufferAppend json_Buffer, vbNewLine, json_BufferPosition, json_BufferLength
311
312
End If
312
313
313
- cSA.Append json_Indentation & "]"
314
+ json_BufferAppend json_Buffer, json_Indentation & "]" , json_BufferPosition, json_BufferLength
314
315
json_IsFirstItem2D = True
315
316
Else
316
317
' 1D Array
@@ -328,15 +329,15 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
328
329
json_Converted = vbNewLine & json_Indentation & json_Converted
329
330
End If
330
331
331
- cSA.Append json_Converted
332
+ json_BufferAppend json_Buffer, json_Converted, json_BufferPosition, json_BufferLength
332
333
End If
333
334
Next json_Index
334
335
End If
335
336
336
337
On Error GoTo 0
337
338
338
339
If json_PrettyPrint Then
339
- cSA.Append vbNewLine
340
+ json_BufferAppend json_Buffer, vbNewLine, json_BufferPosition, json_BufferLength
340
341
341
342
If VBA.VarType(Whitespace) = VBA.vbString Then
342
343
json_Indentation = VBA.String $(json_CurrentIndentation, Whitespace)
@@ -345,9 +346,9 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
345
346
End If
346
347
End If
347
348
348
- cSA.Append json_Indentation & "]"
349
+ json_BufferAppend json_Buffer, json_Indentation & "]" , json_BufferPosition, json_BufferLength
349
350
350
- ConvertToJson = cSA.Report
351
+ ConvertToJson = json_BufferToString(json_Buffer, json_BufferPosition, json_BufferLength)
351
352
352
353
' Dictionary or Collection
353
354
Case VBA.vbObject
@@ -361,7 +362,7 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
361
362
362
363
' Dictionary
363
364
If VBA.TypeName(JsonValue) = "Dictionary" Then
364
- cSA.Append "{"
365
+ json_BufferAppend json_Buffer, "{" , json_BufferPosition, json_BufferLength
365
366
For Each json_Key In JsonValue.Keys
366
367
' For Objects, undefined (Empty/Nothing) is not added to object
367
368
json_Converted = ConvertToJson(JsonValue(json_Key), Whitespace, json_CurrentIndentation + 1 )
@@ -375,7 +376,7 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
375
376
If json_IsFirstItem Then
376
377
json_IsFirstItem = False
377
378
Else
378
- cSA.Append ","
379
+ json_BufferAppend json_Buffer, "," , json_BufferPosition, json_BufferLength
379
380
End If
380
381
381
382
If json_PrettyPrint Then
@@ -384,12 +385,12 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
384
385
json_Converted = """" & json_Key & """:" & json_Converted
385
386
End If
386
387
387
- cSA.Append json_Converted
388
+ json_BufferAppend json_Buffer, json_Converted, json_BufferPosition, json_BufferLength
388
389
End If
389
390
Next json_Key
390
391
391
392
If json_PrettyPrint Then
392
- cSA.Append vbNewLine
393
+ json_BufferAppend json_Buffer, vbNewLine, json_BufferPosition, json_BufferLength
393
394
394
395
If VBA.VarType(Whitespace) = VBA.vbString Then
395
396
json_Indentation = VBA.String $(json_CurrentIndentation, Whitespace)
@@ -398,16 +399,16 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
398
399
End If
399
400
End If
400
401
401
- cSA.Append json_Indentation & "}"
402
+ json_BufferAppend json_Buffer, json_Indentation & "}" , json_BufferPosition, json_BufferLength
402
403
403
404
' Collection
404
405
ElseIf VBA.TypeName(JsonValue) = "Collection" Then
405
- cSA.Append "["
406
+ json_BufferAppend json_Buffer, "[" , json_BufferPosition, json_BufferLength
406
407
For Each json_Value In JsonValue
407
408
If json_IsFirstItem Then
408
409
json_IsFirstItem = False
409
410
Else
410
- cSA.Append ","
411
+ json_BufferAppend json_Buffer, "," , json_BufferPosition, json_BufferLength
411
412
End If
412
413
413
414
json_Converted = ConvertToJson(json_Value, Whitespace, json_CurrentIndentation + 1 )
@@ -424,11 +425,11 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
424
425
json_Converted = vbNewLine & json_Indentation & json_Converted
425
426
End If
426
427
427
- cSA.Append json_Converted
428
+ json_BufferAppend json_Buffer, json_Converted, json_BufferPosition, json_BufferLength
428
429
Next json_Value
429
430
430
431
If json_PrettyPrint Then
431
- cSA.Append vbNewLine
432
+ json_BufferAppend json_Buffer, vbNewLine, json_BufferPosition, json_BufferLength
432
433
433
434
If VBA.VarType(Whitespace) = VBA.vbString Then
434
435
json_Indentation = VBA.String $(json_CurrentIndentation, Whitespace)
@@ -437,10 +438,10 @@ Public Function ConvertToJson(ByVal JsonValue As Variant, Optional ByVal Whitesp
437
438
End If
438
439
End If
439
440
440
- cSA.Append json_Indentation & "]"
441
+ json_BufferAppend json_Buffer, json_Indentation & "]" , json_BufferPosition, json_BufferLength
441
442
End If
442
443
443
- ConvertToJson = cSA.Report
444
+ ConvertToJson = json_BufferToString(json_Buffer, json_BufferPosition, json_BufferLength)
444
445
Case VBA.vbInteger, VBA.vbLong, VBA.vbSingle, VBA.vbDouble, VBA.vbCurrency, VBA.vbDecimal
445
446
' Number (use decimals for numbers)
446
447
ConvertToJson = VBA.Replace(JsonValue, "," , "." )
@@ -544,7 +545,9 @@ Private Function json_ParseString(json_String As String, ByRef json_Index As Lon
544
545
Dim json_Quote As String
545
546
Dim json_Char As String
546
547
Dim json_Code As String
547
- Dim cSA As New clsStringAppend
548
+ Dim json_Buffer As String
549
+ Dim json_BufferPosition As Long
550
+ Dim json_BufferLength As Long
548
551
549
552
json_SkipSpaces json_String, json_Index
550
553
@@ -563,36 +566,36 @@ Private Function json_ParseString(json_String As String, ByRef json_Index As Lon
563
566
564
567
Select Case json_Char
565
568
Case """" , "\" , "/" , "'"
566
- cSA.Append json_Char
569
+ json_BufferAppend json_Buffer, json_Char, json_BufferPosition, json_BufferLength
567
570
json_Index = json_Index + 1
568
571
Case "b"
569
- cSA.Append vbBack
572
+ json_BufferAppend json_Buffer, vbBack, json_BufferPosition, json_BufferLength
570
573
json_Index = json_Index + 1
571
574
Case "f"
572
- cSA.Append vbFormFeed
575
+ json_BufferAppend json_Buffer, vbFormFeed, json_BufferPosition, json_BufferLength
573
576
json_Index = json_Index + 1
574
577
Case "n"
575
- cSA.Append vbCrLf
578
+ json_BufferAppend json_Buffer, vbCrLf, json_BufferPosition, json_BufferLength
576
579
json_Index = json_Index + 1
577
580
Case "r"
578
- cSA.Append vbCr
581
+ json_BufferAppend json_Buffer, vbCr, json_BufferPosition, json_BufferLength
579
582
json_Index = json_Index + 1
580
583
Case "t"
581
- cSA.Append vbTab
584
+ json_BufferAppend json_Buffer, vbTab, json_BufferPosition, json_BufferLength
582
585
json_Index = json_Index + 1
583
586
Case "u"
584
587
' Unicode character escape (e.g. \u00a9 = Copyright)
585
588
json_Index = json_Index + 1
586
589
json_Code = VBA.Mid$(json_String, json_Index, 4 )
587
- cSA.Append VBA.ChrW(VBA.Val("&h" + json_Code))
590
+ json_BufferAppend json_Buffer, VBA.ChrW(VBA.Val("&h" + json_Code)), json_BufferPosition, json_BufferLength
588
591
json_Index = json_Index + 4
589
592
End Select
590
593
Case json_Quote
591
- json_ParseString = cSA.Report
594
+ json_ParseString = json_BufferToString(json_Buffer, json_BufferPosition, json_BufferLength)
592
595
json_Index = json_Index + 1
593
596
Exit Function
594
597
Case Else
595
- cSA.Append json_Char
598
+ json_BufferAppend json_Buffer, json_Char, json_BufferPosition, json_BufferLength
596
599
json_Index = json_Index + 1
597
600
End Select
598
601
Loop
@@ -678,7 +681,9 @@ Private Function json_Encode(ByVal json_Text As Variant) As String
678
681
Dim json_Index As Long
679
682
Dim json_Char As String
680
683
Dim json_AscCode As Long
681
- Dim cSA As New clsStringAppend
684
+ Dim json_Buffer As String
685
+ Dim json_BufferPosition As Long
686
+ Dim json_BufferLength As Long
682
687
683
688
For json_Index = 1 To VBA.Len(json_Text)
684
689
json_Char = VBA.Mid$(json_Text, json_Index, 1 )
@@ -725,10 +730,10 @@ Private Function json_Encode(ByVal json_Text As Variant) As String
725
730
json_Char = "\u" & VBA.Right$("0000" & VBA.Hex$(json_AscCode), 4 )
726
731
End Select
727
732
728
- cSA.Append json_Char
733
+ json_BufferAppend json_Buffer, json_Char, json_BufferPosition, json_BufferLength
729
734
Next json_Index
730
735
731
- json_Encode = cSA.Report
736
+ json_Encode = json_BufferToString(json_Buffer, json_BufferPosition, json_BufferLength)
732
737
End Function
733
738
734
739
Private Function json_Peek (json_String As String , ByVal json_Index As Long , Optional json_NumberOfCharacters As Long = 1 ) As String
@@ -801,10 +806,62 @@ Private Function json_ParseErrorMessage(json_String As String, ByRef json_Index
801
806
ErrorMessage
802
807
End Function
803
808
809
+ Private Sub json_BufferAppend (ByRef json_Buffer As String , _
810
+ ByRef json_Append As Variant , _
811
+ ByRef json_BufferPosition As Long , _
812
+ ByRef json_BufferLength As Long )
813
+ ' VBA can be slow to append strings due to allocating a new string for each append
814
+ ' Instead of using the traditional append, allocate a large empty string and then copy string at append position
815
+ '
816
+ ' Example:
817
+ ' Buffer: "abc "
818
+ ' Append: "def"
819
+ ' Buffer Position: 3
820
+ ' Buffer Length: 5
821
+ '
822
+ ' Buffer position + Append length > Buffer length -> Append chunk of blank space to buffer
823
+ ' Buffer: "abc "
824
+ ' Buffer Length: 10
825
+ '
826
+ ' Put "def" into buffer at position 3 (0-based)
827
+ ' Buffer: "abcdef "
828
+ '
829
+ ' Approach based on cStringBuilder from vbAccelerator
830
+ ' http://www.vbaccelerator.com/home/VB/Code/Techniques/RunTime_Debug_Tracing/VB6_Tracer_Utility_zip_cStringBuilder_cls.asp
831
+ '
832
+ ' and clsStringAppend from Philip Swannell
833
+ ' https://github.com/VBA-tools/VBA-JSON/pull/82
834
+
835
+ Dim json_AppendLength As Long
836
+ Dim json_LengthPlusPosition As Long
804
837
838
+ json_AppendLength = VBA.Len(json_Append)
839
+ json_LengthPlusPosition = json_AppendLength + json_BufferPosition
840
+
841
+ If json_LengthPlusPosition > json_BufferLength Then
842
+ ' Appending would overflow buffer, add chunk
843
+ ' (double buffer length or append length, whichever is bigger)
844
+ Dim json_AddedLength As Long
845
+ json_AddedLength = IIf (json_AppendLength > json_BufferLength, json_AppendLength, json_BufferLength)
846
+
847
+ json_Buffer = json_Buffer & VBA.Space$(json_AddedLength)
848
+ json_BufferLength = json_BufferLength + json_AddedLength
849
+ End If
850
+
851
+ ' Note: Namespacing with VBA.Mid$ doesn't work properly here, throwing compile error:
852
+ ' Function call on left-hand side of assignment must return Variant or Object
853
+ Mid$(json_Buffer, json_BufferPosition + 1 , json_AppendLength) = CStr(json_Append)
854
+ json_BufferPosition = json_BufferPosition + json_AppendLength
855
+ End Sub
856
+
857
+ Private Function json_BufferToString (ByRef json_Buffer As String , ByVal json_BufferPosition As Long , ByVal json_BufferLength As Long ) As String
858
+ If json_BufferPosition > 0 Then
859
+ json_BufferToString = VBA.Left$(json_Buffer, json_BufferPosition)
860
+ End If
861
+ End Function
805
862
806
863
''
807
- ' VBA-UTC v1.0.3
864
+ ' VBA-UTC v1.0.5
808
865
' (c) Tim Hall - https://github.com/VBA-tools/VBA-UtcConverter
809
866
'
810
867
' UTC/ISO 8601 Converter for VBA
@@ -952,7 +1009,7 @@ Public Function ParseIso(utc_IsoString As String) As Date
952
1009
ParseIso = ParseUtc(ParseIso)
953
1010
954
1011
If utc_HasOffset Then
955
- ParseIso = ParseIso + utc_Offset
1012
+ ParseIso = ParseIso - utc_Offset
956
1013
End If
957
1014
End If
958
1015
@@ -1036,15 +1093,15 @@ Private Function utc_ExecuteInShell(utc_ShellCommand As String) As utc_ShellResu
1036
1093
1037
1094
Do While utc_feof(utc_File) = 0
1038
1095
utc_Chunk = VBA.Space$(50 )
1039
- utc_Read = utc_fread(utc_Chunk, 1 , Len(utc_Chunk) - 1 , utc_File)
1096
+ utc_Read = CLng( utc_fread(utc_Chunk, 1 , Len(utc_Chunk) - 1 , utc_File) )
1040
1097
If utc_Read > 0 Then
1041
- utc_Chunk = VBA.Left$(utc_Chunk, utc_Read)
1098
+ utc_Chunk = VBA.Left$(utc_Chunk, CLng( utc_Read) )
1042
1099
utc_ExecuteInShell.utc_Output = utc_ExecuteInShell.utc_Output & utc_Chunk
1043
1100
End If
1044
1101
Loop
1045
1102
1046
1103
utc_ErrorHandling:
1047
- utc_ExecuteInShell.utc_ExitCode = utc_pclose(utc_File)
1104
+ utc_ExecuteInShell.utc_ExitCode = CLng( utc_pclose(utc_File) )
1048
1105
End Function
1049
1106
1050
1107
#Else
@@ -1065,9 +1122,3 @@ Private Function utc_SystemTimeToDate(utc_Value As utc_SYSTEMTIME) As Date
1065
1122
End Function
1066
1123
1067
1124
#End If
1068
-
1069
-
1070
-
1071
-
1072
-
1073
-
0 commit comments