Tutorial 08: JSON Construction & the "AsmBB Way"

0
#
16
27.12.25 16:23

Tutorial 08: JSON Construction & the "AsmBB Way"

Overview

In this tutorial, we dive into how structured data (specifically JSON) is handled in high-performance assembly web applications. We'll focus on the "AsmBB way," which prioritizes speed and efficiency by avoiding heavy libraries in favor of optimized manual construction and template-driven escaping.

Topics Covered

  1. Manual JSON Building - Using TText (Gap Buffer) for speed.

  2. The cHeadersJSON Constant - Standardizing API responses.

  3. JSON Escaping - Understanding the [json:] template command.

  4. API Patterns - Structuring key-value pairs in assembly.

Manual JSON Building with TText

FreshLib doesn't provide a high-level JSON library. Instead, the most efficient way to generate JSON is using the TText gap buffer. This allows for rapid concatenation without the overhead of complex object models.

The Response Pattern

In AsmBB, API responses are typically built in a TText object and sent directly back to the client.

stdcall TextCreate, sizeof.TText
stdcall TextCat, eax, cHeadersJSON ; "Content-Type: application/json\r\n\r\n"
mov edi, eax                       ; Save destination

stdcall TextCat, edi, txt '{"status":"ok","id":'
stdcall NumToStr, ebx, ntsDec or ntsUnsigned
stdcall TextCat, edi, eax
stdcall StrDel, eax
stdcall TextCat, edi, txt '}'

JSON Escaping & Templates

When working with user-provided data, escaping special characters (like quotes and backslashes) is critical. AsmBB handles this through a specialized command in its template engine.

The json: Command

The render2.asm module implements a [json:] command. It takes a string and re-encodes it for safe inclusion in a JSON block.

Template Usage:

{
  "username": "[json:username]",
  "bio": "[json:user_bio]"
}

Implementation Details: The command scans the input string and replaces problematic characters with their escaped equivalents (\", \, \/, \b, \t, \n, \f, \r).

Practical API Dispatching

Efficiently routing requests to different JSON-generating procedures is done using the Pearson's hash pattern covered in Tutorial 07.

stdcall GetPostString, [esi+TSpecialParams.post_array], txt "func", 0
stdcall SearchInHashTable, eax, tableAPICommands
jc .found
; ... handle 404 ...

Demo Programs

Demo 22: Manual JSON

File: demo22_json_manual.asm

Demonstrates building a nested JSON object manually using TText. Shows how to handle numbers, strings, and boolean values efficiently.

Demo 23: JSON Templates

File: demo23_json_template.asm

Demonstrates how the [json:] escaping logic works. This demo includes a simplified version of the AsmBB escaping routine to show how to process untrusted strings for JSON output.

Critical Implementation Notes

CAUTION

Register Preservation: FreshLib procedures do NOT preserve EAX or EDX. Pointers returned by StrPtr, NumToStr, and TextCreate must be saved before calling other procedures.

Pattern: TextAddString Returns New Pointer

TText may be reallocated during operations. Always update your pointer from EDX:

stdcall TextAddString, ebx, -1, json_start
mov     ebx, edx                    ; EDX = potentially new TText pointer
stdcall TextAddString, ebx, -1, json_data
mov     ebx, edx                    ; Update after EVERY call!

Pattern: Passing Bytes to stdcall

stdcall requires dword arguments. Use movzx for byte values:

; ❌ WRONG - Build error: "invalid size of operand"
stdcall TextAddChar, edx, al

; ✅ CORRECT - Use movzx to extend to dword
movzx   eax, byte [esi]
stdcall TextAddChar, edx, eax

Pattern: Use Literal File Descriptors

For maximum reliability in demos, use 1 directly for STDOUT:

stdcall FileWriteString, 1, msg      ; More reliable than [STDOUT]

Building and Running

cd 08-json-serialization
./build.sh

Reference

  • AsmBB API Handler: asmbb/source/api.asm

  • Template Engine: asmbb/source/render2.asm

  • JSON Headers: asmbb/source/commands.asm

15
27.12.25 16:23
; _______________________________________________________________________________________
;|                                                                                       |
;| ..:: FreshLib Tutorials ::..                                                          |
;|_______________________________________________________________________________________|
;
;  Description: Tutorial 08, Demo 22: Manual JSON Construction.
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; Initialized Data
; ========================================
iglobal
  msg_start  text "--- Demo 22: Manual JSON ---", 13, 10
  msg_gen    text "Generated JSON Response:", 13, 10
  msg_sep    text "------------------------", 13, 10
  msg_done   text "Demo complete.", 13, 10
  msg_crlf   text 13, 10

  cHeaders   text 'Content-Type: application/json', 13, 10, 13, 10
  json_start text '{"status":"success",'
  json_data  text '"data":{'
  json_msg   text '"message":"Hello from FreshLib!",'
  json_ver   text '"version":'
  json_bool  text ',"active":true'
  json_end   text "}}"
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll
        stdcall FileWriteString, [STDOUT], msg_start

        stdcall TextCreate, 1024
        mov     ebx, eax                ; EBX = TText pointer

        stdcall TextAddString, ebx, -1, cHeaders
        mov     ebx, edx
        stdcall TextAddString, ebx, -1, json_start
        mov     ebx, edx
        stdcall TextAddString, ebx, -1, json_data
        mov     ebx, edx
        stdcall TextAddString, ebx, -1, json_msg
        mov     ebx, edx
        stdcall TextAddString, ebx, -1, json_ver
        mov     ebx, edx

        mov     eax, 157
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        mov     edi, eax
        stdcall StrPtr, edi
        stdcall TextAddString, ebx, -1, eax
        mov     ebx, edx
        stdcall StrDel, edi

        stdcall TextAddString, ebx, -1, json_bool
        mov     ebx, edx
        stdcall TextAddString, ebx, -1, json_end
        mov     ebx, edx

; Add zero terminator for string output
        stdcall TextAddChar, ebx, 0
        mov     ebx, edx

        stdcall FileWriteString, [STDOUT], msg_gen
        stdcall FileWriteString, [STDOUT], msg_sep

        stdcall TextMoveGap, ebx, $ffffffff
        mov     eax, ebx                ; TText pointer is also a pointer to the string
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], msg_crlf

        stdcall TextFree, ebx

        stdcall FileWriteString, [STDOUT], msg_sep
        stdcall FileWriteString, [STDOUT], msg_done

.finish:
        FinalizeAll
        stdcall TerminateAll, 0
14
27.12.25 16:23
; _______________________________________________________________________________________
;|                                                                                       |
;| ..:: FreshLib Tutorials ::..                                                          |
;|_______________________________________________________________________________________|
;
;  Description: Tutorial 08, Demo 23: JSON Escaping and Output.
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; Initialized Data
; ========================================
iglobal
  msg_start text "--- Demo 23: JSON Escaping ---", 13, 10
  msg_orig  text "Original: "
  msg_esc   text "Escaped:  "
  msg_crlf  text 13, 10
  s_test    text 'Text with "quotes" and \backslashes\.'
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll
        stdcall FileWriteString, [STDOUT], msg_start

        stdcall FileWriteString, [STDOUT], msg_orig
        stdcall FileWriteString, [STDOUT], s_test
        stdcall FileWriteString, [STDOUT], msg_crlf

        stdcall StrDupMem, s_test
        mov     ebx, eax                ; EBX = string handle

        stdcall JsonEscape, ebx
        mov     edi, eax                ; EDI = TText pointer (escaped)

        stdcall FileWriteString, [STDOUT], msg_esc

; Ensure it's null terminated for FileWriteString
        stdcall TextAddChar, edi, 0
        mov     edi, edx

        stdcall TextMoveGap, edi, $ffffffff
        stdcall FileWriteString, [STDOUT], edi
        stdcall FileWriteString, [STDOUT], msg_crlf

        stdcall StrDel, ebx
        stdcall TextFree, edi

.finish:
        FinalizeAll
        stdcall TerminateAll, 0

; ========================================
; A simple JSON escaping function using TText
; ========================================
proc JsonEscape, .hStr
begin
        pushad
        stdcall StrLen, [.hStr]
        mov     ecx, eax
        shl     eax, 1                  ; Allocate double size just in case
        stdcall TextCreate, eax
        mov     edx, eax                ; EDX = TText

        stdcall StrPtr, [.hStr]
        mov     esi, eax                ; ESI = source pointer
        xor     edi, edi                ; EDI = TText offset (pos in buffer)

.l1:
        dec     ecx
        js      .done
        movzx   eax, byte [esi]
        inc     esi

        cmp     al, '"'
        je      .esc
        cmp     al, '\'
        je      .esc

; Fast add if not escaped
        stdcall TextAddChar, edx, eax
        mov     edx, edx
        jmp     .l1

.esc:
        push    eax
        stdcall TextAddChar, edx, '\'
        mov     edx, edx
        pop     eax
        stdcall TextAddChar, edx, eax
        mov     edx, edx
        jmp     .l1

.done:
        mov     [esp+4*regEAX], edx     ; Return TText in EAX
        popad
        return
endp

Tutorial 08: JSON Construction & the "AsmBB Way"

0
#