home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Anachriz / programming / patcher2.asm.txt < prev    next >
Encoding:
Text File  |  2000-05-25  |  22.3 KB  |  860 lines

  1. ;A patcher with search capability, the patch becomes usefull for more versions!
  2. ;Multiple string patching added!
  3. ;Multiple file patching added!
  4. ;TO-DO: - comments (almost finished)
  5. ;       - finish interface / readible output (almost finished)
  6. ;       - for each file add an array of approved filesizes
  7. ;       - print also filesizes if they don't match
  8. ;       - possibility for correcting date/attributes
  9. ;       - (longterm) CRC-32 correcting possibility
  10. ;Copyright (c) 1998,1999 Anarchriz. All rights reserved.
  11. ;currently version 28.01.1999
  12.  
  13. .model tiny
  14.  
  15. .stack 200h
  16.  
  17. NUMBEROFFILES   equ 2           ; <--
  18.  
  19. STEPSIZE        equ 32768
  20. MAXSTRINGSIZE   equ 32
  21. MAXSTRINGS      equ 32
  22. MAXFILES        equ 8
  23. LOCATIONFILESIZE equ 6
  24.  
  25. .data
  26.  
  27. ;Messages
  28. beginMsg        db 'The Patcher  version 28.01.1999 - copyright (c) 1998,1999 Anarchriz',10,13,'$'
  29. patchMsg        db 'Test patch Message, by Anarchriz ;)',10,13,'$'
  30. patchingMsg     db 'Patching file: $'
  31. filesizeMsg     db ' The expected filesize and the current filesize do not match, continue?',10,13
  32.                 db '  y)es, a)lways or n)o : $'
  33. offsetMsg       db ' Expected offset ######## and found ######## for string ##, continue ?',10,13
  34.                 db '  y)es, a)lways or n)o : $'
  35. newline         db 10,13,'$'
  36. succesMsg       db 'Patching was succesfull!',10,13,'$'
  37.  
  38. ;Error Messages
  39. noFilesToPatchErrorMsg db 'ERROR: no files to patch',10,13,'$'
  40. filenameTolongMsg db 'ERROR: given filename to long',10,13,'$'
  41. fileNotFoundMsg db 'ERROR: did not found the file to patch',10,13,'$'
  42. readErrorMsg    db 'ERROR: error on reading file',10,13,'$'
  43. moveErrorMsg    db 'ERROR: error on moving file pointer',10,13,'$'
  44. writeErrorMsg   db 'ERROR: error on writing file',10,13,'$'
  45. errorOnOpeningMsg db 'ERROR: error on opening the file',10,13,'$'
  46. nothingToDoErrorMsg db 'ERROR: no string(s) to search & patch',10,13,'$'
  47. stringNotFoundMsg db 'String(s) to search&patch not found or multiple occurrences.',10,13,'$'
  48. closeErrorMsg   db 'ERROR: error on closing file',10,13,'$'
  49. noSuccesMsg     db 'Patching was not succesfull!',10,13,'$'
  50.  
  51. ;Variables
  52.  
  53. patchFiles      db 'blabla.txt',0       ;Filename, ends with an 0x0 !!
  54.                 dd 12345h               ;Expected filesize
  55.                 dw 2                    ;number of strings to patch
  56.  
  57.                 db 3                    ;begin first patch&search string
  58.                 db 'abc'
  59.                 db 'def'
  60.                 dd 2ch
  61.  
  62.                 db 4                            ;begin second patch&search string
  63.                 db 31h, 32h, 33h, 34h
  64.                 db 32h, 33h, 34h, 31h
  65.                 dd 84h
  66.  
  67.                 db 'blabla2.txt',0      ;FILE 2 !
  68.                 dd 12345h
  69.                 dw 2
  70.  
  71.                 db 6
  72.                 db 'qwertz'
  73.                 db 'zullez'
  74.                 dd 46
  75.  
  76.                 db 6
  77.                 db 'qwerty'
  78.                 db 'rtyuio'
  79.                 dd 0cbah
  80.  
  81. offsetsStrings  dw MAXSTRINGS+1 dup (?)
  82. firstChars      db MAXSTRINGS dup (?)
  83. foundOffsets    dd MAXSTRINGS dup (0ffffffffh)
  84.  
  85. tempOffset      dd (?)
  86. patchFilesOffset dw (?)
  87. beginStringsOffset dw (?)
  88. numberOfStrings dw (?)
  89. continueAlways  db 0                    ;flag to check if user wants to continue always
  90. fileNumber      db 0
  91. fileHandle      dw 0
  92. bufferEdge      db MAXSTRINGSIZE-1 dup (0)
  93. asciiHex        db '0123456789ABCDEF'
  94. dta             db 64 dup (?)
  95. readBuffer      db STEPSIZE dup (?)
  96.  
  97. .code
  98. .386
  99. start:
  100.         ; INIT
  101.         mov     ax, @data
  102.         mov     ds, ax
  103.  
  104.         push    ds
  105.         pop     es ;es=ds
  106.  
  107.         xor     ebx, ebx
  108.  
  109. ;* set DiskTransferArea for function findfile *
  110.         mov     ah, 1ah
  111.         mov     dx, offset dta
  112.         int     21h
  113.  
  114. ;* print start messages *
  115.         mov     dx, offset beginMsg
  116.         call   PrintMsg
  117.  
  118.         mov     dx, offset patchMsg
  119.         call   PrintMsg
  120.  
  121. ;* check if we have something to do *
  122.         mov     ax, NUMBEROFFILES
  123.         cmp     ax, 0
  124.         jbe    noFilesToPatchError      ;fatal error
  125.  
  126. ;* set base offset for first file *
  127.         mov     [patchFilesOffset], offset patchFiles
  128.         ; INIT end
  129.  
  130. BigPatchLoop:
  131. ;* check if filename is to long *
  132.         mov     al, 0
  133.         cld
  134.         mov     di, [patchFilesOffset]
  135.         mov     cx, 256
  136.         repne   scasb
  137.         jz     EOFfilename
  138.         jmp    filenameTolong           ;fatal error
  139.  
  140. ;* get the number of strings to search&patch for this file
  141. ;   and the offset of the beginning of the strings set *
  142. EOFfilename:
  143.         add     di, 4
  144.         mov     ax, [di]
  145.         mov     [numberOfStrings], ax
  146.         inc     di
  147.         inc     di
  148.         mov     [beginStringsOffset], di
  149.  
  150. ;* check if we have something to do *
  151.         mov     cx, [numberOfStrings]    ;NUMBEROFSTRINGS
  152.         cmp     cx, 0
  153.         je     nothingToDoError         ;fatal error (chosen)
  154.  
  155.  
  156. ;* print which file we are currently patching *
  157.         mov     dx, offset patchingMsg
  158.         call   PrintMsg
  159.         mov     byte ptr[di-7], '$'     ;make 0 terminated string printable
  160.         mov     dx, [patchFilesOffset]
  161.         call   PrintMsg
  162.         mov     byte ptr[di-7], 0       ;restore string
  163.         mov     dx, offset newline
  164.         call   PrintMsg
  165.  
  166. ;* get & check the size of the file to patch *
  167.         mov     dx, [patchFilesOffset]
  168.         call   FindFile
  169.         cmp     ax, 0ffffh
  170.         je     fileNotFound             ;fatal error
  171.  
  172.         cmp     [continueAlways], 1
  173.         je     equalFilesize            ;no question needed
  174.  
  175.         mov     eax, dword ptr[dta+1ah] ;filesize in DTA
  176.         mov     di, [beginStringsOffset]
  177.         cmp     eax, dword ptr[di-LOCATIONFILESIZE] ;filesize in patchFiles
  178.         je     equalFilesize
  179.  
  180.         mov     ax, offset filesizeMsg
  181.         call   AskYesNo
  182.         cmp     al,'y'
  183.         je     equalFilesize
  184.         cmp     al,'a'
  185.         jne    forcedExit
  186.  
  187.         mov     [continueAlways], 1
  188.  
  189. equalFilesize:
  190. ;* open file to patch *
  191.         mov     dx, [patchFilesOffset]
  192.         call   OpenFile
  193.         cmp     ax, 0ffffh
  194.         je     errorOnOpening           ;fatal error
  195.  
  196.         mov     [fileHandle], ax
  197.  
  198. ;* init the strings to search for *
  199.         call   InitStrings
  200.  
  201. ;* search the offsets of the strings *
  202.         mov     si, offset fileHandle
  203.         mov     [tempOffset], 0
  204.         call   SearchString
  205.         cmp     ax, 0
  206.         jne    doubleOrNotFoundError    ;fatal error
  207.  
  208.         ;note: there is no check for if the offsets+strings overlap
  209.  
  210.         cmp     [continueAlways], 1
  211.         je     equalOffsets
  212.  
  213. ;* check if the offsets match the expected ones *
  214.         call   CheckOffsets
  215.         cmp     ax, 0ffffh
  216.         je     forcedExit
  217.  
  218. equalOffsets:
  219. ;* move and write new strings to file *
  220.         mov     si, offset fileHandle
  221.         call   WriteOffsets
  222.         cmp     ax,0ffffh
  223.         je     writeError               ;fatal error
  224.         cmp     ax,0fffeh
  225.         je     moveError                ;fatal error
  226.  
  227.         mov     si, offset fileHandle
  228.         call   CloseFile
  229.         cmp     ax, 0ffffh
  230.         je     closeError               ;fatal error
  231.  
  232. ;* now preparing to patch next file (resetting foundOffsets) if needed *
  233.         inc     [fileNumber]
  234.         cmp     [fileNumber], NUMBEROFFILES
  235.         je     AllDone
  236.  
  237.         xor     ebx, ebx
  238.         mov     bx, [numberOfStrings]
  239.         mov     ax, [offsetsStrings+2*ebx]
  240.         mov     [patchFilesOffset], ax
  241. initFoundOffsetsLoop:
  242.         dec     ebx
  243.         mov     [foundOffsets+4*ebx], 0ffffffffh
  244.         cmp     ebx, 0
  245.         jne    initFoundOffsetsLoop
  246.  
  247.         jmp    BigPatchLoop
  248.  
  249. AllDone:
  250.         ;successfull!
  251.         mov     dx, offset succesMsg
  252.         call   PrintMsg
  253.  
  254.         mov     al, 0
  255.         jmp    exit
  256.  
  257. ;**************************
  258. ;* Exit                   *
  259. ;**************************
  260. exit:
  261.         cmp     al, 0
  262.         je     exitNow
  263.         mov     dx, offset nosuccesMsg
  264.         call   PrintMsg
  265.  exitNow:
  266.         mov     ah, 4ch
  267.         int     21h
  268.  
  269. closeExit:
  270.         push    ax
  271.         mov     si, offset fileHandle
  272.         call   CloseFile
  273.         cmp     ax, 0ffffh
  274.         pop     ax
  275.         je     closeError
  276.         jmp exit
  277.  
  278. forcedExit:
  279.         mov     al,11
  280.         jmp    closeExit
  281. ;**************************
  282. ;* Error handlers         *
  283. ;**************************
  284. noFilesToPatchError:                    ;should never happen
  285.         mov     dx, offset noFilesToPatchErrorMsg
  286.         call   PrintMsg
  287.         mov     al, 1
  288.         jmp    exit
  289.  
  290. filenameTolong:                         ;should never happen
  291.         mov     dx, offset filenameTolongMsg
  292.         call   PrintMsg
  293.         mov     al, 2
  294.         jmp    exit
  295.  
  296. nothingToDoError:                       ;should never happen
  297.         mov     dx, offset nothingToDoErrorMsg
  298.         call   PrintMsg
  299.         mov     al, 5
  300.         jmp     exit
  301.  
  302. fileNotFound:
  303.         mov     dx, offset fileNotFoundMsg
  304.         call   PrintMsg
  305.         mov     al, 3
  306.         jmp    exit
  307.  
  308. errorOnOpening:                         ;happens when file is read-only
  309.         mov     dx, offset errorOnOpeningMsg
  310.         call   PrintMsg
  311.         mov     al, 4
  312.         jmp    exit
  313.  
  314.  
  315. doubleOrNotFoundError:
  316.         mov     dx, offset stringNotFoundMsg
  317.         call   PrintMsg
  318.         mov     al, 6
  319.         jmp     closeExit
  320.  
  321. readError:                              ;bad sectors?
  322.         mov     dx, offset readErrorMsg
  323.         call   PrintMsg
  324.         mov     al, 7
  325.         jmp     closeExit
  326.  
  327. moveError:                              ;should never happen
  328.         mov     dx, offset moveErrorMsg
  329.         call   PrintMsg
  330.         mov     al, 8
  331.         jmp     closeExit
  332.  
  333. writeError:                             ;bad sectors?
  334.         mov     dx, offset writeErrorMsg
  335.         call   PrintMsg
  336.         mov     al, 9
  337.         jmp     closeExit
  338.  
  339. closeError:                             ;removed floppy?
  340.         mov     dx, offset closeErrorMsg
  341.         call   PrintMsg
  342.         mov     al, 10
  343.         jmp    exit
  344.  
  345. ;**************************
  346. ;* String routines        *
  347. ;**************************
  348.  
  349. ;Parameters:    foundOffsets
  350. ;               offsetsStrings  ;array with offsets of the strings to search&patch
  351. ;returns:       ax=0    ok.
  352. ;               ax=ffff not ok, user said no
  353. CheckOffsets proc
  354.         push    ebx
  355.         push    dx
  356.         push    di
  357.  
  358.         xor     ecx, ecx
  359.         mov     cx, [numberOfStrings]    ;NUMBEROFSTRINGS
  360.         xor     ebx, ebx
  361.  checkOffsetLoop:
  362.         mov     eax, [foundOffsets+4*ebx];found offset of the string
  363.         mov     di, [offsetsStrings+2*ebx+2]
  364.         cmp     eax, dword ptr[di-4]     ;expected offset of the string
  365.         jne    askOffset
  366.   checkOffsetLoop2:
  367.         inc     ebx
  368.         cmp     ebx, ecx
  369.         jne    checkOffsetLoop
  370.         jmp    checkOffsetOk
  371.  
  372.  askOffset:
  373.  ;* print question with offsetnumbers *
  374.         push    cx
  375.         mov     dx, offset offsetMsg + 35
  376.         mov     cl, 8
  377.         ;       eax=foundOffset
  378.         call   AsciiOffset
  379.         mov     dx, offset offsetMsg + 55
  380.         mov     al, bl
  381.         mov     cl, 2
  382.         call   AsciiOffset
  383.         mov     dx, offset offsetMsg + 16
  384.         mov     cl, 8
  385.         mov     eax, dword ptr[di-4]    ;=expected offset
  386.         call   AsciiOffset
  387.         pop     cx
  388.  
  389.         mov     ax, offset offsetMsg
  390.         call   AskYesNo                 ;ask to continue if offsets are not equal
  391.         cmp     al,'y'
  392.         je     checkOffsetLoop2
  393.         cmp     al,'a'
  394.         jne    checkOffsetError
  395.         mov     [continueAlways], 1     ;never ask anymore
  396.  checkOffsetOk:
  397.         xor     ax, ax
  398.  checkOffsetReturn:
  399.         pop     di
  400.         pop     dx
  401.         pop     ebx
  402.         ret
  403.  
  404.  checkOffsetError:
  405.         mov     ax, 0ffffh
  406.         jmp    checkOffsetReturn
  407. CheckOffsets endp
  408.  
  409. InitStrings proc
  410.         push    ax
  411.         push    bx
  412.         push    cx
  413.         push    dx
  414.         push    di
  415.         push    si
  416.  
  417.         mov     bx, [beginStringsOffset]      ;begin offset of strings tabel
  418.         mov     di, 0
  419.         mov     si, 0
  420.         mov     cx, [numberOfStrings]    ;NUMBEROFSTRINGS
  421.  initStringsLoop:
  422.         cmp     cx, 0
  423.         je     initStringsReturn
  424.  
  425.         mov     [offsetsStrings+di], bx
  426.         xor     ax, ax
  427.         mov     al, [bx]
  428.         shl     ax, 1
  429.         inc     bx
  430.         mov     dl, [bx]
  431.         mov     [firstChars+si], dl
  432.         add     ax, 4
  433.         add     bx, ax
  434.  
  435.         inc     di
  436.         inc     di
  437.         inc     si
  438.         dec     cx
  439.         jmp     initStringsLoop
  440.  
  441.  initStringsReturn:
  442.         mov     [offsetsStrings+di], bx ;offset after all other offsets
  443.  
  444.         pop     si
  445.         pop     di
  446.         pop     dx
  447.         pop     cx
  448.         pop     bx
  449.         pop     ax
  450.         ret
  451. InitStrings endp
  452.  
  453. ;Parameters:    ds:si   pointer to file handle
  454. ;returns:       ax=ffff no strings found
  455. ;               ax=fffe double strings found
  456. ;               ax=0    all ok.
  457. SearchString proc
  458.         push    ebx
  459.         push    cx
  460.         push    dx
  461.         push    di
  462.  
  463.  ;* first STEPSIZE bytes and init this search *
  464.  readLoop:
  465.         mov     dx, offset readBuffer
  466.         call   ReadFile
  467.         cmp     ax, 0ffffh
  468.         je     readError
  469.         cmp     ax, 0
  470.         je     noMoreStrings
  471.         mov     bx, dx
  472.         sub     bx, (MAXSTRINGSIZE-1)   ; point to MAXSTRINGSIZE-1 bytes before readbuffer (bufferEdge)
  473.  
  474.  initSearch:
  475.  ;di: points to the first character of each string
  476.  ;ax: is bytes read (functions as counter)
  477.  ;bx: is pointer to buffer where we are searching in
  478.         mov     di, 0
  479.  searchLoop:
  480.         mov     cl, [firstChars+di]
  481.         cmp     byte ptr[bx], cl
  482.         je     checkString
  483.   searchLoop2:
  484.         inc     di
  485.         cmp     di, [numberOfStrings]    ;NUMBEROFSTRINGS
  486.         jne    searchLoop
  487.   searchLoop3:
  488.         inc     bx
  489.         dec     ax
  490.         cmp     ax, 0
  491.         jne    initSearch
  492.  
  493.   ;* copy MAXSTRINGSIZE-1 bytes from end readBuffer to bufferEdge *
  494.         push    si
  495.         mov     di, offset bufferEdge
  496.         mov     si, offset readBuffer + STEPSIZE - (MAXSTRINGSIZE-1)
  497.         mov     cx, MAXSTRINGSIZE - 1
  498.         cld
  499.         rep     movsb
  500.         pop     si
  501.  
  502.         add     [tempOffset], STEPSIZE
  503.         jmp     readLoop
  504.  
  505.  checkString:
  506.  ;* first character matched, now check the rest of the string *
  507.         push    cx
  508.         push    si
  509.         push    di
  510.  
  511.         mov     si, bx
  512.         inc     si
  513.         shl     di, 1
  514.  
  515.         mov     di, [offsetsStrings+di]
  516.         xor     cx, cx
  517.         mov     cl, [di]
  518.         dec     cx                      ;cx=stringsize-1
  519.         inc     di                      ;strings beginnen 1 later + 1 char
  520.         inc     di
  521.         cld
  522.         repz    cmpsb                   ;compare ds:si with es:di for cx bytes
  523.  
  524.         pop     di
  525.         pop     si
  526.         pop     cx
  527.         je     foundString
  528.  
  529.         jmp    searchLoop2      ;no match, continue checking first character of ither strings
  530.  
  531.  foundString:
  532.  ;* now found a string, store offset if not already found *
  533.         push    ebx
  534.         push    di
  535.  
  536.         sub     bx, offset readBuffer
  537.         movsx   ebx, bx
  538.         add     ebx, [tempOffset]
  539.         shl     di, 2
  540.         cmp     [foundOffsets+di], 0ffffffffh
  541.         jne    doubleStrings
  542.         mov     [foundOffsets+di], ebx
  543.  
  544.         pop     di
  545.         pop     ebx
  546.         jmp    searchLoop3      ;continue searching strings
  547.  
  548.  noMoreStrings:
  549.  ;* end of search, check if a string is not found *
  550.         xor     ebx, ebx
  551.         mov     bx, [numberOfStrings]    ;NUMBEROFSTRINGS
  552.   noMoreStringsLoop:
  553.         dec     ebx
  554.         cmp     [foundOffsets+4*ebx],0ffffffffh
  555.         je     stringsNotFound
  556.         cmp     ebx, 0
  557.         jne    noMoreStringsLoop
  558.         xor     ax, ax
  559.  
  560.  searchStringReturn:
  561.         pop     di
  562.         pop     dx
  563.         pop     cx
  564.         pop     ebx
  565.         ret
  566.  
  567.  stringsNotFound:
  568.         mov     ax,0ffffh
  569.         jmp    searchStringReturn
  570.  doubleStrings:
  571.         pop     di
  572.         pop     ebx
  573.         mov     ax,0fffeh
  574.         jmp    searchStringReturn
  575.  
  576. SearchString endp
  577.  
  578. ;Parameters:    ds:si   pointer to file handle
  579. ;               foundOffsets
  580. ;               offsetsStrings
  581. ;returns:       ax=ffff error while writing
  582. ;               ax=fffe error while moving file pointer
  583. ;               ax=0    all ok. I hope ;)
  584. WriteOffsets proc
  585.         push    ebx
  586.         push    dx
  587.         push    di
  588.  
  589.         xor     ebx, ebx
  590.  
  591.  writeOffsetsLoop:
  592.         mov     eax, [foundOffsets+4*ebx]
  593.         ;si pointer filehandle
  594.         call   MoveFile
  595.         cmp     eax, 0ffffffffh
  596.         je     writeOffsetsMoveError
  597.  
  598.         mov     di, [offsetsStrings+2*ebx]
  599.         xor     dx, dx
  600.         mov     dl, [di]
  601.         mov     ax, dx                  ;ax holds stringsize
  602.         inc     dx
  603.         add     dx, di                  ;dx now holds the offset of new string
  604.  
  605.         ;si=offset fileHandle
  606.         call   WriteFile
  607.         cmp     ax, 0ffffh
  608.         je      writeOffsetsWriteError
  609.  
  610.         inc     ebx
  611.         cmp     bx, [numberOfStrings] ; I suppose ebx < 65536
  612.         jne    writeOffsetsLoop
  613.  
  614.         xor     ax, ax
  615.  
  616.  writeOffsetsReturn:
  617.         pop     di
  618.         pop     dx
  619.         pop     ebx
  620.         ret
  621.  
  622.  writeOffsetsMoveError:
  623.         mov     ax, 0fffeh
  624.         jmp    writeOffsetsReturn
  625.  writeOffsetsWriteError:
  626.         mov     ax, 0ffffh
  627.         jmp    writeOffsetsReturn
  628. WriteOffsets endp
  629.  
  630. ;**************************
  631. ;*** File routines      ***
  632. ;**************************
  633. ;eax=offset ; ds:si=pointer filehandle
  634. ;return eax=0ffffffffh on error
  635. MoveFile proc
  636.         push    bx
  637.         push    cx
  638.         push    dx
  639.  
  640.         mov     dx, ax
  641.         shr     eax, 16
  642.         mov     cx, ax
  643.  
  644.         mov     ax, 4200h
  645.         mov     bx, [si]
  646.         int     21h
  647.         jc     moveFileError
  648.  
  649.  moveFileReturn:
  650.         pop     dx
  651.         pop     cx
  652.         pop     bx
  653.         ret
  654.  
  655.  moveFileError:
  656.         mov     eax, 0ffffffffh
  657.         jmp     moveFileReturn
  658. MoveFile endp
  659.  
  660. ;ds:dx=pointer filename
  661. ;return: ax<0ffffh=handle.;ax=true=open error.
  662. OpenFile proc
  663.         mov     ax, 3d02h
  664.         int     21h
  665.         jc     open_error
  666.         
  667.         ret
  668.  open_error:
  669.         mov     ax, 0ffffh
  670.         ret
  671. OpenFile endp
  672.  
  673. ;ds:dx=pointer readbuffer ; ds:si=pointer filehandle
  674. ;return ax=ax=read bytes;ax=0ffffh=read error.
  675. ReadFile proc
  676.         push    bx
  677.         push    cx
  678.  
  679.         mov     ah, 3fh
  680.         mov     bx, [si]
  681.         mov     cx, STEPSIZE
  682.         int     21h
  683.         jc     read_error
  684.  
  685.  ReadFile_return:
  686.         pop     cx
  687.         pop     bx
  688.         ret
  689.  read_error:
  690.         mov     ax, 0ffffh
  691.         jmp    ReadFile_return
  692. ReadFile endp
  693.  
  694. ;ds:dx=pointer (write)readbuffer ; ds:si=pointer filehandle ; ax=bytes to write
  695. ;return ax=written bytes;ax=0ffffh=write error.
  696. WriteFile proc
  697.         push    bx
  698.         push    cx
  699.  
  700.         mov     cx, ax
  701.         mov     ah, 40h
  702.         mov     bx, [si]
  703.         int     21h
  704.         jc     write_error
  705.  
  706.  WriteFile_return:
  707.         pop     cx
  708.         pop     bx
  709.         ret
  710.  write_error:
  711.         mov     ax, 0ffffh
  712.         jmp    WriteFile_return
  713. WriteFile endp
  714.  
  715. ;ds:si=pointer filehandle
  716. CloseFile proc
  717.         push    bx
  718.         mov     ah, 3eh
  719.         mov     bx, [si]
  720.         cmp     bx, 0
  721.         je     doNotClose
  722.         int     21h
  723.         jc     close_error
  724.         mov     word ptr[si], 0
  725.  doNotClose:
  726.         xor     ax,ax
  727.  CloseFile_return:
  728.         pop     bx
  729.         ret
  730.  close_error:
  731.         mov     ax, 0ffffh
  732.         jmp    CloseFile_return
  733. CloseFile endp
  734.  
  735.  
  736. ;ds:dx=point file spec
  737. ;return: ax=ffffh -> file not found else ax=n/a
  738. FindFile proc
  739.         push    cx
  740.  
  741.         xor     cx, cx
  742.         mov     ah, 4eh
  743.         int     21h
  744.         jc      not_found
  745.  
  746.  FindFile_return:
  747.         pop     cx
  748.         ret
  749.  
  750.  not_found:
  751.         mov     ax, 0ffffh
  752.         jmp    FindFile_return
  753. FindFile endp
  754.  
  755.  
  756. ;****************************
  757. ;* Miscellaneous routines   *
  758. ;****************************
  759. PrintMsg proc
  760.         push    ax
  761.         mov     ah,9
  762.         int     21h
  763.         pop     ax
  764.         ret
  765. PrintMsg endp
  766.  
  767. ;ax=offset question
  768. ;returns: al=key in ascii
  769. AskYesNo proc
  770.         push    dx
  771.  
  772.         mov     dx, ax
  773.         call   PrintMsg
  774.         xor     ax, ax
  775.         int     16h
  776.  
  777.         cmp     al, 61h
  778.         jae    askYesNoLowercase
  779.         add     al, 34
  780.  askYesNoLowercase:
  781.  
  782.         mov     dl, al
  783.         mov     ah, 2
  784.         int     21h
  785.  
  786.         mov     dx, offset newline
  787.         call   PrintMsg
  788.  
  789.         pop     dx
  790.         ret
  791. AskYesNo endp
  792.  
  793. ;parameters:    eax     offset to convert
  794. ;               cl      length in characters
  795. ;               ds:dx   pointer to writebuffer (at least 8 bytes)
  796. ;returns:       nothing
  797. AsciiOffset proc
  798.         push    eax
  799.         push    bx
  800.         push    cx
  801.         push    si
  802.  
  803.         mov     si, dx
  804.         mov     ch, 0
  805.         add     si, cx
  806.  asciiOffsetLoop:
  807.         mov     bx, ax
  808.         and     bx, 0000000000001111b
  809.         mov     bl, [asciiHex+bx]
  810.         mov     [si], bl
  811.         shr     eax, 4
  812.         dec     si
  813.         dec     cl
  814.         jnz    asciiOffsetLoop
  815.  
  816.         pop     si
  817.         pop     cx
  818.         pop     bx
  819.         pop     eax
  820.         ret
  821. AsciiOffset endp
  822.  
  823. ;Alert! This routine does NOT work! It gives divide by zero error!
  824. ;Parameters:    eax     filesize to convert
  825. ;               ds:dx   pointer to writebuffer (at least 10 bytes)
  826. DecimalFilesize proc
  827.         push    eax
  828.         push    ebx
  829.         push    ecx
  830.         push    edx
  831.         push    di
  832.  
  833.         mov     ecx, 1000000000         ;10^9
  834.         mov     di, dx
  835.  
  836.  decimalFilesizeLoop:
  837.         div     ecx                     ;eax=eax/ecx ;
  838.         add     al, 30h
  839.         mov     [di], al
  840.  
  841.         mov     ebx, edx
  842.         mov     eax, ecx
  843.         mov     ecx, 10
  844.         div     ecx
  845.         mov     ecx, eax
  846.         mov     eax, ebx
  847.         inc     di
  848.         cmp     ecx, 0
  849.         jne    decimalFilesizeLoop
  850.  
  851.         pop     di
  852.         pop     edx
  853.         pop     ecx
  854.         pop     ebx
  855.         pop     eax
  856.         ret
  857. DecimalFilesize endp
  858.  
  859. end start
  860.