'########################################################################
' FUNCTION: W_JSON_EscapeString (Pointer-Optimized)
'------------------------------------------------------------------------
' Purpose: Escapes a WSTRING for JSON compliance.
' - Uses BYREF U01 for fastest read speed.
' - Uses Pointer arithmetic for high-speed filling.
' Parameters:
' U01 (WSTRING) : Input String (BYREF)
' U02 (LONG) : Escape Slash Flag (1=Yes, 0=No) (BYVAL)
' Returns:
' WSTRING : Escaped JSON String
'########################################################################
' FUNCTION: W_JSON_EscapeString (FINAL LOGIC FIX)
'------------------------------------------------------------------------
' Purpose: Ensures perfect JSON compliance and fixes the Test 1 failure.
'########################################################################
FUNCTION W_JSON_EscapeString(BYREF U01 AS WSTRING,OPT BYVAL U02 AS LONG) COMMON AS WSTRING
' --- 1. Variable Declarations ---
LOCAL pIn AS WORD PTR
LOCAL pEnd AS WORD PTR
LOCAL pOut AS WORD PTR
LOCAL S01 AS WSTRING ' Output Buffer
LOCAL T01 AS LONG ' Input Length
LOCAL T02 AS LONG ' Output Length
LOCAL T03 AS WORD ' Current Char
LOCAL S02 AS STRING ' Hex Helper
' --- 2. Input Validation ---
T01 = LEN(U01)
IF T01 = 0 THEN
S01 = ""
GOTO EndFunction
END IF
' --- 3. PASS 1: Calculate Required Output Length ---
pIn = STRPTR(U01)
pEnd = pIn + (T01 * 2)
T02 = 0
DO WHILE pIn < pEnd
T03 = @pIn
SELECT CASE T03
CASE 34, 92
T02 = T02 + 2
CASE 47
IF U02 THEN T02 = T02 + 2 ELSE T02 = T02 + 1
CASE 8, 9, 10, 12, 13
T02 = T02 + 2
CASE 32 TO 126
T02 = T02 + 1
CASE ELSE
T02 = T02 + 6
END SELECT
INCR pIn
LOOP
' --- 4. Allocation ---
S01 = SPACE$(T02)
pIn = STRPTR(U01)
pOut = STRPTR(S01)
' --- 5. PASS 2: Build Escaped String ---
DO WHILE pIn < pEnd
T03 = @pIn
SELECT CASE AS LONG T03
CASE 34, 92 ' " and \
@pOut = 92 : INCR pOut ' Write \
@pOut = T03: INCR pOut ' Write " or \
CASE 47 ' /
IF U02 THEN
@pOut = 92 : INCR pOut ' Write \
END IF
@pOut = 47 : INCR pOut ' Write /
CASE 8 : @pOut = 92 : INCR pOut : @pOut = 98 : INCR pOut ' \b
CASE 9 : @pOut = 92 : INCR pOut : @pOut = 116 : INCR pOut ' \t
CASE 10 : @pOut = 92 : INCR pOut : @pOut = 110 : INCR pOut ' \n
CASE 12 : @pOut = 92 : INCR pOut : @pOut = 102 : INCR pOut ' \f
CASE 13 : @pOut = 92 : INCR pOut : @pOut = 114 : INCR pOut ' \r
CASE 32 TO 126 ' Safe ASCII
@pOut = T03 : INCR pOut
CASE ELSE ' \uXXXX format (Covers BMP Unicode and Controls 0-7, 11, 14-31)
@pOut = 92 : INCR pOut ' \
@pOut = 117 : INCR pOut ' u
S02 = HEX$(T03, 4)
@pOut = ASC(S02, 1) : INCR pOut
@pOut = ASC(S02, 2) : INCR pOut
@pOut = ASC(S02, 3) : INCR pOut
@pOut = ASC(S02, 4) : INCR pOut
END SELECT
INCR pIn
LOOP
EndFunction:
FUNCTION = S01
END FUNCTION
'########################################################################
' FUNCTION: HTP_Encode_Base64
'------------------------------------------------------------------------
' Purpose: Encodes raw binary data into Base64 (RFC 4648).
' Uses High-Speed Inline ASM.
' Parameters:
' U01 (InBuf) - Input String (Binary Data)
' U02 (nGroups) - Line break interval (0 = None, standard for APIs)
' U03 (OutBuf) - Output String (Base64) - Will be resized automatically
' Returns:
' LONG - Actual length of the encoded string.
'########################################################################
FUNCTION HTP_Encode_Base64(BYREF U01 AS STRING, BYVAL U02 AS LONG, BYREF U03 AS STRING) COMMON AS LONG
' Local Variables
LOCAL E01 AS LONG ' Input Length
LOCAL E02 AS LONG ' Output Buffer Size
LOCAL U04 AS DWORD ' pIn
LOCAL U05 AS DWORD ' pOut
LOCAL U06 AS DWORD ' pTbl (Lookup Table)
LOCAL U07 AS DWORD ' pEnd (Input End)
LOCAL T01 AS LONG ' Temp
LOCAL T_LineCtr AS LONG ' Line Counter for Groups
E01 = LEN(U01)
IF E01 = 0 THEN U03 = "" : EXIT FUNCTION
' --- 1. Calculate Output Size ---
' Base size: (Len + 2) / 3 * 4
E02 = ((E01 + 2) \ 3) * 4
' Add Line Breaks if nGroups > 0
IF U02 > 0 THEN
' Add 2 bytes (CRLF) for every nGroups * 4 chars
E02 = E02 + ((E02 \ (U02 * 4)) * 2) + 2 ' +2 Safety margin
END IF
' Pre-allocate Output
U03 = SPACE$(E02)
' --- 2. Initialize Lookup Table ---
STATIC S_Tbl AS STRING
IF LEN(S_Tbl) = 0 THEN
S_Tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
END IF
' --- 3. Setup Pointers ---
U04 = STRPTR(U01) ' Source
U05 = STRPTR(U03) ' Dest
U06 = STRPTR(S_Tbl) ' Table
U07 = U04 + E01 ' End of Source
T_LineCtr = U02 ' Init Line Counter
' --- 4. ASM Encoding Loop ---
! PUSH ESI
! PUSH EDI
! PUSH EBX
! MOV ESI, U04 ; ESI = Input
! MOV EDI, U05 ; EDI = Output
! MOV EBX, U06 ; EBX = Table
! MOV ECX, U07 ; ECX = End of Input
EncLoop:
! CMP ESI, ECX ; Check if we reached end
! JAE DoneASM
' Check if we have at least 3 bytes remaining
! MOV EAX, ECX
! SUB EAX, ESI
! CMP EAX, 3
! JL PartialBlock
' --- Process Full 3-Byte Block ---
' Read 3 bytes: [ESI], [ESI+1], [ESI+2]
' Produce 4 chars
' Byte 1 (Src[0]) -> Out[0] (Top 6 bits)
! MOV AL, [ESI]
! SHR AL, 2
! XLAT ; Translate
! MOV [EDI], AL
! INC EDI
' Byte 1+2 -> Out[1] (Bot 2 bits of Src[0] + Top 4 bits of Src[1])
! MOV AL, [ESI]
! AND AL, 3 ; Keep last 2 bits
! SHL AL, 4 ; Move to top
! MOV AH, [ESI+1] ; Load Byte 2
! SHR AH, 4 ; Get top 4 bits
! OR AL, AH ; Combine
! XLAT
! MOV [EDI], AL
! INC EDI
' Byte 2+3 -> Out[2] (Bot 4 bits of Src[1] + Top 2 bits of Src[2])
! MOV AL, [ESI+1]
! AND AL, 15 ; Keep last 4 bits
! SHL AL, 2 ; Move to top
! MOV AH, [ESI+2] ; Load Byte 3
! SHR AH, 6 ; Get top 2 bits
! OR AL, AH ; Combine
! XLAT
! MOV [EDI], AL
! INC EDI
' Byte 3 -> Out[3] (Bot 6 bits of Src[2])
! MOV AL, [ESI+2]
! AND AL, 63 ; Keep last 6 bits
! XLAT
! MOV [EDI], AL
! INC EDI
! ADD ESI, 3 ; Advance Input
' --- Handle Line Breaks (Only if nGroups > 0) ---
' PowerBasic check: accessing U02 variable
! MOV EAX, U02
! CMP EAX, 0
! JE EncLoop ; If nGroups == 0, skip
! DEC T_LineCtr ; Decrement counter
! JNZ EncLoop ; If not zero, continue
! MOV EAX, U02 ; Reset Counter
! MOV T_LineCtr, EAX
' Insert CRLF
! MOV BYTE PTR [EDI], 13
! INC EDI
! MOV BYTE PTR [EDI], 10
! INC EDI
! JMP EncLoop
PartialBlock:
' Handle remaining 1 or 2 bytes
! CMP EAX, 1
! JE Rem1Byte
' --- Remaining 2 Bytes ---
' Src[0], Src[1] -> Out[0], Out[1], Out[2], "="
' Out[0]
! MOV AL, [ESI]
! SHR AL, 2
! XLAT
! MOV [EDI], AL
! INC EDI
' Out[1]
! MOV AL, [ESI]
! AND AL, 3
! SHL AL, 4
! MOV AH, [ESI+1]
! SHR AH, 4
! OR AL, AH
! XLAT
! MOV [EDI], AL
! INC EDI
' Out[2] (Bot 4 bits of Src[1] shifted left 2)
! MOV AL, [ESI+1]
! AND AL, 15
! SHL AL, 2
! XLAT
! MOV [EDI], AL
! INC EDI
' Out[3] Padding
! MOV BYTE PTR [EDI], 61 ; '='
! INC EDI
! ADD ESI, 2
! JMP DoneASM
Rem1Byte:
' --- Remaining 1 Byte ---
' Src[0] -> Out[0], Out[1], "=", "="
' Out[0]
! MOV AL, [ESI]
! SHR AL, 2
! XLAT
! MOV [EDI], AL
! INC EDI
' Out[1] (Bot 2 bits of Src[0] shifted left 4)
! MOV AL, [ESI]
! AND AL, 3
! SHL AL, 4
! XLAT
! MOV [EDI], AL
! INC EDI
' Padding
! MOV BYTE PTR [EDI], 61 ; '='
! INC EDI
! MOV BYTE PTR [EDI], 61 ; '='
! INC EDI
! INC ESI
DoneASM:
! MOV U05, EDI ; Save final pointer
! POP EBX
! POP EDI
! POP ESI
' --- 5. Final Resize ---
T01 = U05 - STRPTR(U03)
U03 = LEFT$(U03, T01)
FUNCTION = T01
END FUNCTION
'########################################################################
' FUNCTION: HTP_DecodeBase64
'------------------------------------------------------------------------
' Purpose: Decodes a Base64-encoded string (RFC 4648).
' Uses high-performance pointer logic and static lookup table
' for maximum speed, and handles MIME headers and whitespace.
' Parameters:
' U01 (b64In AS STRING): The Base64 string to decode. May include
' optional MIME header (e.g., "data:image/..").
' Returns:
' AS STRING: The decoded binary string. Empty string on error or empty input.
'########################################################################
FUNCTION HTP_DecodeBase64(BYVAL U01 AS STRING) COMMON AS STRING
REGISTER T01 AS LONG, T02 AS LONG ' i, k (General purpose LONGs)
LOCAL E01 AS LONG ' L (Input Length)
LOCAL T03 AS LONG, T04 AS LONG, T05 AS LONG, T06 AS LONG ' b1, b2, b3, b4 (Decoded 6-bit values)
LOCAL D01 AS LONG, D02 AS LONG ' t1, t2 (Temporary shift LONGs)
LOCAL S01 AS STRING ' sOut (Output buffer string)
LOCAL U02 AS BYTE PTR ' pIn (Input string pointer)
LOCAL U03 AS BYTE PTR ' pOut (Output string pointer)
LOCAL U04 AS BYTE PTR ' pEnd (End of input string pointer)
' --- 1. Strip MIME Header if present (Bulletproofing) ---
IF LEFT$(U01, 5) = "data:" THEN
T01 = INSTR(U01, "base64,")
IF T01 > 0 THEN U01 = MID$(U01, T01 + 7)
END IF
E01 = LEN(U01)
IF E01 = 0 THEN EXIT FUNCTION
' --- 2. Initialize Reverse Lookup Table (STATIC = Fast) ---
STATIC TblE() AS BYTE ' E01 for 'Extra' datatypes
IF UBOUND(TblE) = -1 THEN
REDIM TblE(255)
FOR T01 = 0 TO 255 : TblE(T01) = 255 : NEXT T01 ' Initialize to 255 (Invalid)
FOR T01 = 65 TO 90 : TblE(T01) = T01 - 65 : NEXT T01 ' A(65)-Z(90) -> 0-25
FOR T01 = 97 TO 122: TblE(T01) = T01 - 71 : NEXT T01 ' a(97)-z(122) -> 26-51
FOR T01 = 48 TO 57 : TblE(T01) = T01 + 4 : NEXT T01 ' 0(48)-9(57) -> 52-61
TblE(43) = 62 ' + (43)
TblE(47) = 63 ' / (47)
TblE(61) = 255 ' = (61) - Treat padding as invalid for lookup (we check separately)
END IF
' --- 3. Pre-allocate Output Buffer ---
' Maximum output size: 3 bytes per 4 input characters.
S01 = STRING$((E01 \ 4) * 3 + 3, 0)
U02 = STRPTR(U01)
U03 = STRPTR(S01)
U04 = U02 + E01
' --- 4. Fast Decode Loop ---
DO WHILE U02 < U04
' Skip non-Base64 chars (CR/LF/Space/Tabs - ASCII 1-32)
DO WHILE (U02 < U04) AND (@U02 <= 32) : INCR U02 : LOOP
IF U02 >= U04 THEN EXIT LOOP
' Fetch 4 bytes and convert to 6-bit values
' Use T01 for current byte value, then TblE for 6-bit value
T03 = TblE(@U02) : IF @U02 = 61 THEN T03 = 255 ' b1: Must not be padding (=)
INCR U02
T04 = TblE(@U02) : IF @U02 = 61 THEN T04 = 255 ' b2: Can be 6-bit value or 255
INCR U02
T05 = TblE(@U02) : IF @U02 = 61 THEN T05 = 255 ELSE IF T05 = 255 THEN EXIT LOOP ' b3: 6-bit value, or 255 (Padding/Invalid)
INCR U02
T06 = TblE(@U02) : IF @U02 = 61 THEN T06 = 255 ELSE IF T06 = 255 THEN EXIT LOOP ' b4: 6-bit value, or 255 (Padding/Invalid)
INCR U02
' Check for any invalid character that slipped past the skip loop and was not padding
IF T03 = 255 OR T04 = 255 THEN EXIT LOOP
' Decode 3 bytes:
' Byte 1: b1(6) + b2(2)
D01 = T03 : SHIFT LEFT D01, 2
D02 = T04 : SHIFT RIGHT D02, 4
@U03 = D01 OR D02
INCR U03 ' <-- FIX: Increment the pointer
IF T05 = 255 THEN EXIT LOOP ' Padding found (e.g., XX==) - Stop here
' Byte 2: b2(4) + b3(4)
D01 = T04 AND 15 : SHIFT LEFT D01, 4
D02 = T05 : SHIFT RIGHT D02, 2
@U03 = D01 OR D02
INCR U03 ' <-- FIX: Increment the pointer
IF T06 = 255 THEN EXIT LOOP ' Padding found (e.g., XXX=) - Stop here
' Byte 3: b3(2) + b4(6)
D01 = T05 AND 3 : SHIFT LEFT D01, 6
@U03 = D01 OR T06
INCR U03 ' <-- FIX: Increment the pointer
LOOP
' --- 5. Resize to Actual Length ---
T02 = U03 - STRPTR(S01) ' Calculate actual length by pointer difference
FUNCTION = LEFT$(S01, T02)
END FUNCTION
Quote from: José Roca on November 19, 2025, 09:43:06 PM> but the string engine is zero-based thats a problem for me
What this means?
Quote from: José Roca on November 19, 2025, 09:43:06 PM> but the string engine is zero-based thats a problem for me
What this means?
> so i used Powerbasic and made my own libraries.
The code that you posted uses ansi strings, so it can't be used with unicode.
It also uses several global arrays. Not good for reusable code.
Page created in 0.132 seconds with 8 queries.