;___________________________________________________________
; TrimZ does not require a Null padded buffer receiving the
; characters. However, if it IS Null padded AND fIsFillZ<>0,
; TrimZ can perform a faster binary search.
;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
; Function TrimZ(StrZ As String, _
;      Optional ByVal fIsFillZ As long) As String

; TrimZ "strZ[ZZZZZZZZZZZZZZZZZ]" >> TrimZ = "str"

; fIsFillZ = BufferIsNullFilled ' Fill not required

 .486            ; 32-bit instruction set
 .model flat     ; Protected memory, 4GB limit
 .code           ; Start of code

TrimZ proc near

   push esi           ; preserve ptr register
   mov esi,[esp+12]   ; copy string descriptor
   xor eax, eax       ; zero default return
   mov esi,[esi]      ; extract string pointer
   mov edx, eax       ; assign (double) nulls
   test esi,esi       ; validate string pointer
   jz _exitp          ; exit null string passed

   cmp dx, [esp+16]   ; compare fill flag to zero
   je _seek           ; bin search only if null-fill

   mov ecx,[esi-4]    ; extract byte length of str
   cmp dx,[esi+ecx-2] ; if not pre-null-filled buffer
   jne _seek          ; (or allocated to req length)

  _bin:               ; binary loop while nulls
   shr ecx, 1         ; divide char count by 2
   jz _exitp          ; empty null-filled buffer
   and cl, 0feh       ; 11111110 round down odd
   cmp dx,[esi+ecx]   ; test for null character
   je _bin            ; continue while null char

   mov eax, ecx       ; prep idx for search
   shr ecx, 1         ; divide char pos by 2
   and cl, 0feh       ; round down odd pos
   add ecx, eax       ; step search back up
   cmp dx,[esi+ecx]   ; test for null char
   je _seek           ; beyond valid chars
   mov eax, ecx       ; close enough, walk up

  _seek:              ; seek from pos for nulls
   sub eax, 2         ; offset idx before walk

  _walk:              ; walk up unicode chars
   add eax, 2         ; offset idx to next wchar
   cmp dx,[esi+eax]   ; test for null terminator
   jne _walk          ; if not continue search

   shr eax, 1         ; convert result to char cnt
   mov edx, 8876543h  ; api address patched on init
   push eax           ; SysAllocStringLen len param
   push esi           ; string to copy StrPtr(str)
   call edx           ; call SysAllocStringLen api

  _exitp:
   mov edx,[esp+20]   ; get ptr to return variable
   mov [edx], eax     ; assign function result

   pop esi         ; restore pointer register
   xor eax, eax    ; clear eax to tell VB okay
   ret 16          ; cleanup (lpObj, p1, p2, ret)

TrimZ endp     ; end of procedure
end TrimZ      ; end of code, indicate entry point
