Author Topic: Miscellaneous snippets  (Read 25774 times)

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 10094
  • Assembler is fun ;-)
    • MasmBasic
Utf-32 to Utf-16 converter
« Reply #150 on: December 20, 2019, 01:51:02 PM »
To use it, drag a file (e.g. ...FreeBasic\examples\unicode\hello_UTF32LE.bas) over the attached exe.

include \masm32\MasmBasic\MasmBasic.inc         ; download
  Init
  Let esi=FileRead$(CL$())      ; read UTF-32 content into a buffer
  .if dword ptr [esi]!=0FEFFh   ; no BOM found!
        MsgBox 0, CL$(), "Not a UTF-32 file, sorry", MB_OK
  .else
        mov ecx, LastFileSize
        sar ecx, 1
        Let edi=New$(ecx)       ; create a buffer for UTF-16
        sar ecx, 1
        push edi
       .Repeat
                lodsd
                stosw
                dec ecx
       .Until Sign?
       pop edi
       FileWrite "test.txt", edi
       ShEx "test.txt"         ; open in your preferred editor
  .endif
EndOfCode

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 10094
  • Assembler is fun ;-)
    • MasmBasic
Generate random integers and write them to a text file
« Reply #151 on: January 16, 2020, 08:53:47 AM »
Source and exe attached. This snippet generates a text file with integers.

include \masm32\MasmBasic\MasmBasic.inc         ; download
  SetGlobals total
  Init
  Dim MyDw() As DWORD
  mov ecx, Val(Input$("How many numbers: ", "1000000"))         ; suggest one Million
  mov total, ecx
  sar ecx, 4                                    ; divide by 16
  jle bye
  Open "O", #1, "numbers.txt"
  For_ ct=1 To ecx
        For_ ecx=0 To 15
                Print #1, Str$("%i ", Rand(500000)-250000)      ; generate numbers from -250000...249999
        Next
        Print #1
  Next
  Close #1
  NanoTimer()
  StringToArray FileRead$("Numbers.txt"), MyDw()        ; reload textfile and convert to numbers
  PrintLine NanoTimer$(), Str$(" for converting %i numbers", MyDw(?))
  NanoTimer()
  ArraySort MyDw()
  PrintLine NanoTimer$(), " for sorting them"
  For_ ecx=0 To 9                       ; show the smallest numbers
       PrintLine Str$("MyDw(%i)=", ecx), Str$(MyDw(ecx))
  Next
  PrintLine "..."
  For_ ecx=total-9 To total-1           ; show the biggest numbers
       PrintLine Str$("MyDw(%i)=", ecx), Str$(MyDw(ecx))
  Next
bye:
EndOfCode


Sample output (Intel Core i5):
Code: [Select]
How many numbers: 1000000
98 ms for converting 1000000 numbers
103 ms for sorting them
MyDw(0)=-250000
MyDw(1)=-249999
MyDw(2)=-249999
MyDw(3)=-249999
MyDw(4)=-249998
MyDw(5)=-249998
MyDw(6)=-249997
MyDw(7)=-249997
MyDw(8)=-249997
MyDw(9)=-249996
...
MyDw(999991)=249994
MyDw(999992)=249994
MyDw(999993)=249995
MyDw(999994)=249996
MyDw(999995)=249997
MyDw(999996)=249997
MyDw(999997)=249998
MyDw(999998)=249999
MyDw(999999)=249999

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 10094
  • Assembler is fun ;-)
    • MasmBasic
Save frames of a GIF file
« Reply #152 on: January 24, 2020, 12:08:35 PM »
GuiParas equ "Save all frames of a GIF image to file", w300, h200
include \masm32\MasmBasic\Res\MbGui.asm         ; needs MasmBasic 24.1.2020
GuiImageCallback MySave                         ; tell GuiImage to call MySave
Event Paint
  GuiImage wCL$(), fit                          ; load the image specified in the commandline (Unicode is allowed)
EndOfEvents
MySave: If_ Not signed eax<0 Then <SaveImageToFile Str$("frame_%i.gif", eax)>   ; saves current frame to frame_0...n.gif
  ret
GuiEnd


Project attached. Drag an animated *.gif file over the exe, then check its folder for the component files. The exe will also display jpg, bmp, png and tiff, but only multi-frame gif files will trigger the creation of the frame*.gif components. This works also with animated TIFF files, see second attachment, but the output will be *.gif components. No idea how to join them, though :cool:

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 10094
  • Assembler is fun ;-)
    • MasmBasic
Image viewer
« Reply #153 on: February 01, 2020, 03:31:52 PM »
What's new?

- GuiImage now respects the delays of frames in animated GIFs, and also stops looping if the GIF specifies a limit. Simple example (make sure you run it in a folder that contains images; source and exe attached):

include \masm32\MasmBasic\Res\MbGui.asm        ; MasmBasic version 1 Feb 2020 needed for building this code
GetFiles *.gif|*.jpg|*.png|*.jpeg              ; load the Files$() array
SortFiles                                      ; latest on top
GuiControl MyList, "listbox", Files$(), x=800, w=200   ; create a listbox to the right, 20% of width; use Files$() to fill it
GuiControl MyCanvas, "canvas", w=800, WS_THICKFRAME    ; create the canvas to paint on
GuiImageSpeed 50, 2000                         ; 50% speed, 2 seconds pause after an animation

Event CanvasPaint
  .if LbSel>=0
        GuiImage 99, fit                ; background image may be needed for animations with transparency
        GuiImage Files$(LbSel)          ; draw the selected image, use original size (or use fit as above)
  .else
        GuiTextBox 0, 0, 200, auto, "Click into the listbox to select a file", bcol RgbCol(255, 255, 255), font 40
  .endif
GuiEnd


- new CheckStackBalance macro:
Code: [Select]
include \masm32\MasmBasic\MasmBasic.inc
  Init

  CodeSize MyTest
  call MyTest
  useCsb=1 ; put 0 to see a crash

  Exit

  MyTest_s:
  MyTest proc
CheckStackBalance
PrintLine "Hello World"
pushf ; that's a word, right ;-)
pushad ; <<<<<<<<<<<<<<<< a bug! <<<<<<<<<<<
CheckStackBalance
ret
  MyTest endp
  MyTest_endp:
  CodeSize MyTest, echo
end start

If enabled via useCsb=1, it shows e.g. these lines, plus a MsgBox:

Code: [Select]
244     bytes for MyTest
Hello World
** line 16: 8 push instructions in excess - stack is 34 bytes off **

If disabled with useCsb=0, no code is generated but the output looks different:

Code: [Select]
18      bytes for MyTest
Hello World

Plus a "MsgBox" designed by Microsoft :tongue:

- the CodeSize macro may serve to calculate the size of a whole proc or a few instructions between the *_s: and *_endp: labels. In the CodeSize xx, echo variant, the size appears in the output window, and no extra code will be generated

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 10094
  • Assembler is fun ;-)
    • MasmBasic
Find huge and old files on your disk
« Reply #154 on: February 09, 2020, 07:17:03 AM »
include \masm32\MasmBasic\MasmBasic.inc         ; download
  SetGlobals backslash, pattern$
  Init
  .While 1
        PrintLine CrLf$, "Press Escape, Return to exit", CrLf$
        Let pattern$=Input$("What to search for: ", Cat$(CurDir$()+"*.*"))
        .Break .if !Len(eax)
        Cls
        Dim score() As DWORD
        GetFiles pattern$       ; .jpg|*.inc|*.pdf
       For_ ct=0 To eax-1
                xor ecx, ecx
                dec GfAgeHours(ct)
                .if !Sign?
                              shr eax, 2      ; more shifting = less importance for date
                              push eax
                              shr GfSize(ct), 7
                              pop edx
                              mul edx
                              shrd eax, edx, 12
                              xchg eax, ecx
                .endif
                mov score(ct), ecx
        Next
        ArraySort score(-), key() As DWORD, fill
        PrintLine CrLf$, "Size__", Tb$, "Date______  Time____    Path", String$(60, "_")
        fldz
        For_ ct=0 To score(?)-1
                mov ecx, key(ct)
                .if ct<=50
                                push GfSize(ecx)
                                fiadd stack
                                pop edx
               .endif
                .if ct<20
                                mov esi, Files$(ecx)
                                ; mov backslash, Rinstr(esi, "\")
                               PrintLine Str$("%_____i\t", GfSize(ecx)/1024/1024), GfDate$(ecx), Spc2$, GfTime$(ecx), Tb$, Mid$(esi, backslash+1)
                .endif
        Next
        fmul FP4(1.0e-9)
        mov ecx, Cat$("\nDeleting the first 50 files in "+Left$(pattern$, Rinstr(pattern$, "\")-1)+" would free %3f GB of disk space")
        PrintLine Str$(#ecx, ST(0)v)
  .Endw
EndOfCode


Unzip the attachment to some folder and run the exe (or open the *.asc in RichMasm and hit F6). Typical output:
Code: [Select]
Size__  Date______  Time____    Path____________________________________________________________
     2  27.09.2013  02:01:00    C:\Masm32\OllyDbg\ollydbg.exe
     0  19.03.1998  07:28:18    C:\Masm32\bin\link.exe
     0  13.01.1995  05:10:00    C:\Masm32\bin\link16.exe
     1  10.01.2012  00:21:10    C:\Masm32\include\winextra.inc
     0  10.01.2012  00:21:10    C:\Masm32\include\windows.inc
     0  16.03.2000  15:20:48    C:\Masm32\bin\ml.EXE
     0  16.03.2000  15:20:48    C:\Masm32\bin\mlv615.EXE
     0  12.11.2011  08:04:41    C:\Masm32\examples\unicode_generic\diskfile\WININC.INC
     0  13.03.2004  16:30:08    C:\Masm32\examples\advanced\wrep\winequ.inc
     0  16.04.2011  19:09:37    C:\Masm32\bin\poasm.exe
     0  25.01.2010  13:18:04    C:\Masm32\bin\dumppe.exe
     0  22.12.2008  15:15:08    C:\Masm32\lib\msvcrt.000

Deleting the first 50 files in C:\Masm32 would free 0.0410 GB of disk space

So far, it just shows files, i.e. nothing will get deleted. Of course, it becomes more interesting if your \Masm32 folder is a little bit older. My message is Deleting the first 50 files in C:\Masm32 would free 16.8 GB of disk space :cool:

Here is another interesting folder:
Code: [Select]
Size__  Date______  Time____    Path____________________________________________________________
   272  23.04.2011  21:41:44    C:\Windows\Installer\21386cd2.msp
   189  28.03.2011  18:00:22    C:\Windows\Installer\42fec0e.msp
   164  28.03.2011  17:45:18    C:\Windows\Installer\42fec0d.msp
   114  27.07.2007  09:03:06    C:\Windows\Installer\21386a4c.msp
   378  01.09.2017  01:43:52    C:\Windows\Installer\30be8f0e.msi
   245  21.06.2016  05:45:27    C:\Windows\Installer\2ad6e39c.msi
   207  06.11.2015  16:00:20    C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SetupCache\v4.6.01055\NetFx_Full.mzz
    69  22.03.2010  19:36:56    C:\Windows\Installer\$PatchCache$\Managed\00004159FA0090400000000000F01FEC\14.0.4763\MSORES.DLL
    63  10.06.2009  23:02:16    C:\Windows\IME\IMESC5\DICTS\PINTLGT.IMD
    63  10.06.2009  23:02:16    C:\Windows\winsxs\amd64_microsoft-windows-i..e-trigramdictionary_31bf3856ad364e35_6.1.7600.16385_none_12d6b2e35
    55  22.07.2009  10:17:30    C:\Windows\Installer\$PatchCache$\Managed\1D763DBFF246FC747BB9B94EF83B0470\10.0.1600\ENG_RE_sqlservr_exe_64
    69  18.01.2012  02:24:38    C:\Windows\Installer\$PatchCache$\Managed\00004159FA0090400000000000F01FEC\14.0.7015\MSORES.DLL
    55  22.09.2011  21:07:34    C:\Windows\Installer\$PatchCache$\Managed\1D763DBFF246FC747BB9B94EF83B0470\10.3.5500\ENG_RE_sqlservr_exe_64
    37  17.12.2007  14:57:48    C:\Windows\Installer\27f64005.msi
    36  17.12.2007  14:57:48    C:\Windows\Installer\27f64006.msp
    43  11.06.2010  17:52:10    C:\Windows\Installer\42cdaff.msp
    96  21.06.2016  05:44:58    C:\Windows\Installer\2ad6e0ec.msp
    32  10.06.2009  22:43:23    C:\Windows\Fonts\mingliub.ttc
    32  10.06.2009  22:43:23    C:\Windows\winsxs\amd64_microsoft-windows-font-truetype-mingliub_31bf3856ad364e35_6.1.7600.16385_none_251699455
    77  20.09.2015  10:27:56    C:\Windows\Installer\$PatchCache$\Managed\00006109C10000000000000000F01FEC\16.0.4288\MSORES.DLL

Deleting the first 50 files in C:\Windows would free 3.83 GB of disk space

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 10094
  • Assembler is fun ;-)
    • MasmBasic
Find *.xls but not *.xlsx files
« Reply #155 on: March 02, 2020, 02:17:00 AM »
Under the hood of GetFiles, FindFirstFile and FindNextFile are working. Unfortunately, for these API functions, *.xls and *.xlsx are just the same thing. Here is a workaround that filters unwanted *.xlsx files out - it sets the zero flag in a callback function thus telling GetFiles not to include the file in the Files$() array:

include \masm32\MasmBasic\MasmBasic.inc         ; download
.code

cbGetFiles:                     ; the callback function
  .if wInstr(edi, ".xlsx")
        or ecx, -1              ; combined with the inc ecx below, this sets Zero?
  .endif
  inc ecx
  ret

  Init
  GfCallback cbGetFiles         ; define a callback function
  GetFiles *.xls
  SortFiles                     ; latest on top
  For_ ebx=0 To eax-1           ; print the results
       PrintLine Str$(GfSize(ebx)), Tb$, GfDate$(ebx), Spc2$, GfTime$(ebx), Tb$, Files$(ebx)
  Next
EndOfCode


Project attached.

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 10094
  • Assembler is fun ;-)
    • MasmBasic
Adding two numbers
« Reply #156 on: March 06, 2020, 01:47:38 AM »
GuiParas equ "adding two numbers", w560, h84, icon Lens
include \masm32\MasmBasic\Res\MbGui.asm
GuiControl MyEdit, "edit", h=0+28, "1234+1000h", font -16:FW_SEMIBOLD
GuiControl MyStatusBar, "statusbar", "Change the number to see the sum in dec, hex and binary format", font -14:FW_MEDIUM
Event Command
  .if nCode==EN_CHANGE
        mov ecx, Win$(hMyEdit)          ; get the text from the edit control
        push Val(ecx)                   ; save first integer to stack
        and edx, 127                    ; get #chars used
        lea ecx, [ecx+edx+1]            ; skip the plus sign
        void Val(ecx)
        If_ edx==-127 Then xor eax, eax ; second value was invalid or empty
        pop ecx                         ; pop first value
        add ecx, eax                    ; sum
        SetWin$ hMyStatusBar=Str$("Sum is %i = ", ecx)+Hex$(ecx)+"h = "+Bin$(ecx)+"b"
  .endif
GuiEnd