今天在把宿舍机器上的东西往家里机器上腾的时候,无意中发现了一年多以前用汇编写的一个文件分割器。这一年过去了,一直没有用汇编,也忘得差不多了。再看这个以前自己用汇编写的小程序时,心里有一种莫名的感觉,于是想放到blog上纪念一下。下面是源代码:
; File Splitter V1.0 ; Author: LuPeipei(goodname008) ; Date: 2003.11.29 ; BLOG: http://blog.csdn.net/goodname008
FILE_CREATE EQU 3CH ;Create File FILE_OPEN EQU 3DH ;Open File FILE_READ EQU 3FH ;Read File FILE_WRITE EQU 40H ;Write File FILE_CLOSE EQU 3EH ;Close File FILE_MOVEPTR EQU 42H ;Move File Pointer FILE_DELETE EQU 41H ;Delete File
ERR_IFN EQU 01H ;Invalid File Number ERR_FNF EQU 02H ;File Not Found ERR_PNF EQU 03H ;Path Not Found ERR_TMF EQU 04H ;Too Many File opened ERR_RIO EQU 05H ;Refuse Input/Output ERR_IFH EQU 06H ;Invalid File Handler
ATTR_ARCHIVE EQU 00H ;File Attrib: Archive ATTR_READONLY EQU 01H ;File Attrib: Read-only ATTR_HIDDEN EQU 02H ;File Attrib: Hidden ATTR_SYSTEM EQU 04H ;File Attrib: System
MODE_READ EQU 00H ;File open Mode: Read-only MODE_WRITE EQU 01H ;File open Mode: Write-only MODE_RW EQU 02H ;File open Mode: Read and Write
DSEG SEGMENT ERROR_OF DB 'Failed to open file.',0DH,0AH,'$' ERROR_MP DB 'Failed to move the pointer of file.',0DH,0AH,'$' ERROR_FS DB 'The file size must be more than 1MB and less than 4096MB.',0DH,0AH,'$' ERROR_VC DB 'The number of volume must be more than 1 and less than 100.',0DH,0AH,'$' ERROR_CF DB 'Falied to create file.',0DH,0AH,'$' ERROR_WF DB 'Insufficient disk space.',0DH,0AH,'$'
COMPLETE DB 'Complete successfully!!!',0DH,0AH DB 'Thank you for using this software.',0DH,0AH,'$'
LOGO DB 'LPP (R) File Splitter version 1.0',0DH,0AH DB 'Copyright (C) LPP software studio 2003-2004. All rights reserved.',0DH,0AH,0DH,0AH DB 'Options: 1 -- Split 2 -- Combine',0DH,0AH,0DH,0AH DB 'Your choice: $'
PROMPTSF DB 'Source filename: $' FILESIZE DB 'File size: ',8 DUP('$') OPTIONSIZE DB 'Volume size options: 1 -- Floppy Disk (1.44 MB) 2 -- Custom.',0DH,0AH,0DH,0AH DB 'Your choice: $' PROMPTS DB 'Volume size(MB): $' PROMPTTF DB 'Target filename(don',"'",'t input extend name): $' SFSIZE DD ? TFSIZE DW ? SFNUM DW ? TFNUM DW ? SFNAME DB 65,?,65 DUP(0),'$' TFNAME DB 65,?,65 DUP(0),'.ext',0,'$' VSIZE DB 4,?,4 DUP(0),'$' PDIGIT DB 0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9 BUFFER DB 60736 DUP(?),'$' FLAG DB ? DSEG ENDS
SSEG SEGMENT STACK DB 100 DUP(?) SSEG ENDS
CSEG SEGMENT ASSUME CS:CSEG,DS:DSEG,SS:SSEG
START: MOV AX,DSEG MOV DS,AX
LEA DX,LOGO ;print Author ,Copyrights and options MOV AH,9H INT 21H
MOV AH,1H ;get user choice INT 21H CALL PRINTCRLF
CMP AL ,'1' ;1 -- Split 2 -- Combine JE SPLIT CMP AL ,'2' JE COMBINE MOV AH,4CH INT 21H
COMBINE:CALL COMBINEMODULE
SPLIT : CALL SPLITMODULE
;----------------------------------------------------------------------------
COMBINEMODULE PROC MOV PROMPTTF[15],':' MOV PROMPTTF[16],' ' MOV PROMPTTF[17],'$' LEA DX,PROMPTTF ;print "Target filename:" MOV AH,9H INT 21H
LEA DX,TFNAME ;get the target filename from user MOV AH,0AH INT 21H
MOV DL,TFNAME+1 ;set the last filename char to 0 XOR DH,DH MOV DI,DX MOV TFNAME[DI+2],0 CALL PRINTCRLF
LEA DX,TFNAME+2 ;create target file MOV AH,FILE_CREATE MOV CX,ATTR_ARCHIVE INT 21H MOV TFNUM,AX ;save target file number to TFNUM JNC COK_CF ;if error then EXIT LEA DX,ERROR_CF MOV AH,9H INT 21H MOV AH,4CH INT 21H
COK_CF: LEA DX,PROMPTSF ;print "Source filename:" MOV AH,9H INT 21H
LEA DX,SFNAME ;get the source filename from user MOV AH,0AH INT 21H CALL PRINTCRLF
MOV DL,SFNAME+1 ;set the last filename char to 0 XOR DH,DH MOV DI,DX LEA DI,SFNAME[DI] ;source filename extendsion's number --> DI MOV BYTE PTR [DI+2],0 MOV BYTE PTR [DI+3],'$' CALL PRINTCRLF CALL PRINTCRLF
MOV TFSIZE,0FFFFH ;copy 1048576 bytes per time XOR AX,AX
C_NEXT: PUSH AX CALL HEXTODECASC ;change source file extend name MOV BX,AX
LEA DX,SFNAME+2 ;open source file MOV AH,FILE_OPEN MOV AL,MODE_READ INT 21H
MOV SFNUM,AX ;save source file number JNC COK_OF ;if error then EXIT
CMP BX,0 ;if complete the EXIT JNE EXITCSU
CALL PRINTCRLF LEA DX,ERROR_OF ;print "Falied to open file." MOV AH,9H INT 21H MOV AH,4CH INT 21H
EXITCSU:CALL PRINTCRLF LEA DX,COMPLETE ;print "Complete successfully ..." MOV AH,9H INT 21H MOV AH,4CH INT 21H
COK_OF: LEA DX,SFNAME+2 ;print source filename MOV AH,9H INT 21H MOV DL,'.' ;print "......" MOV AH,2H INT 21H INT 21H INT 21H INT 21H INT 21H INT 21H CALL PRINTCRLF
CCOPY: CALL COPYBYTES JC EXITCWF ;if disk full then EXIT CMP FLAG,1 ;if complete then EXIT JNE CCOPY
MOV BX,SFNUM ;close source file MOV AH,FILE_CLOSE INT 21H
POP AX INC AX
JMP C_NEXT
EXITCWF:CALL PRINTCRLF LEA DX,ERROR_WF ;print "Insufficient disk space." MOV AH,9H INT 21H MOV AH,4CH INT 21H
COMBINEMODULE ENDP
;----------------------------------------------------------------------------
SPLITMODULE PROC LEA DX,PROMPTSF ;print "Source filename:" MOV AH,9H INT 21H
LEA DX,SFNAME ;get the source filename from user MOV AH,0AH INT 21H CALL PRINTCRLF
MOV DL,SFNAME+1 ;set the last filename char to 0 XOR DH,DH MOV SI,DX MOV SFNAME[SI+2],0 CALL PRINTCRLF
LEA DX,SFNAME+2 ;open source file MOV AH,FILE_OPEN MOV AL,MODE_READ INT 21H JNC SOK_OF ;if error then EXIT LEA DX,ERROR_OF MOV AH,9H INT 21H MOV AH,4CH INT 21H
SOK_OF: MOV SFNUM,AX ;save source file number MOV BX,AX XOR CX,CX ;get the length of file(Bytes) --> DX:AX XOR DX,DX MOV AL,02H MOV AH,FILE_MOVEPTR INT 21H JNC SOK_MP ;if error occured then EXIT LEA DX,ERROR_MP MOV AH,9H INT 21H MOV AH,4CH INT 21H
SOK_MP: CMP DX,0010H ;if the length of file is less than 1MB or more than 4096MB then EXIT JB EXIT_FS CMP DX,0FFF0H JNA SOK_FS EXIT_FS:LEA DX,ERROR_FS MOV AH,9H INT 21H MOV AH,4CH INT 21H
SOK_FS: MOV WORD PTR SFSIZE,AX MOV WORD PTR SFSIZE+2,DX MOV AX,DX ;the length of file(MB) --> AX MOV CL,4 SHR AX,CL
PUSH AX ;save the length of file to stack MOV DX,AX LEA BX,FILESIZE[11] CALL HEXTODECASC5 MOV FILESIZE[DI+11],'.' MOV FILESIZE[DI+12],'0'
MOV AX,WORD PTR SFSIZE+2 AND AX,000FH ;calculate the point part ( XXXX.p MB ) LEA BX,PDIGIT XLAT MOV DX,AX LEA BX,FILESIZE[DI+12] CALL HEXTODECASC5
MOV FILESIZE[SI+11+1],'0' LEA DX,FILESIZE MOV AH,9H INT 21H MOV AH,2H ;show ' MB' after source file size MOV DL,' ' INT 21H MOV DL,'M' INT 21H MOV DL,'B' INT 21H CALL PRINTCRLF CALL PRINTCRLF
MOV BX,SFNUM ;set file pointer to 0000:0000 XOR CX,CX XOR DX,DX MOV AL,00H MOV AH,FILE_MOVEPTR INT 21H
LEA DX,OPTIONSIZE ;print volume size options information MOV AH,9H INT 21H
MOV AH,1H ;get user choice INT 21H CALL PRINTCRLF
CMP AL,'1' ;1 -- Floppy Disk (1.44 MB) 2 -- Custom. JE FLP CMP AL ,'2' JE CUSTOM MOV AH,4CH INT 21H ;if FLOPPY then check file size FLP: CMP WORD PTR SFSIZE+2,0016H JB EXIT_VC JE CMPLOW MOV AX,WORD PTR SFSIZE+2 CMP AX,8B0H JA EXIT_VC JMP SOK_VC CMPLOW: CMP WORD PTR SFSIZE,3E00H JB EXIT_VC JMP SOK_VC
CUSTOM: LEA DX,PROMPTS ;print "Volume size:" MOV AH,9H INT 21H
LEA DX,VSIZE ;get volume size to AX (n:MB) CALL RECEIVENUM LEA DX,VSIZE+2 CALL ASCTOHEX CALL BCDTOHEX
CMP AX,0 JE EXIT_VC MOV SI,AX ;AX --> SI (volume size, n:MB) MOV TFSIZE,AX ;save volume size to memory POP AX ;restore the length of file from stack
XOR DX,DX ;volume count --> AX (actually in AL ) DIV SI CMP AX,0 ;if volume count = 0 or more than 100 then EXIT JE EXIT_VC CMP AX,64H JNA SOK_VC EXIT_VC:LEA DX,ERROR_VC MOV AH,9H INT 21H MOV AH,4CH INT 21H
SOK_VC: LEA DX,PROMPTTF ;print "Target filename:" MOV AH,9H INT 21H
LEA DX,TFNAME ;get the target filename from user MOV AH,0AH INT 21H CALL PRINTCRLF MOV DL,TFNAME+1 ;set the last filename char to '.' XOR DH,DH MOV SI,DX MOV TFNAME[SI+2],'.' ;set target filename format "X:/********.Lnn" MOV TFNAME[SI+3],'L'
LEA DI,TFNAME[SI+4] ;target filename extendsion's number --> DI MOV BYTE PTR [DI+3],'$' MOV BYTE PTR [DI+2],0 ;set the last filename char to 0
XOR AX,AX ;the first volume name is *.L00 CALL PRINTCRLF
S_NEXT: PUSH AX ;save the last two extension (.L**) to stack CALL HEXTODECASC ;set target filename extension (.Lnn)
LEA DX,TFNAME[2] ;print filename (volume) MOV AH,9H INT 21H MOV DL,'.' ;print "......" after filename MOV AH,2H INT 21H INT 21H INT 21H INT 21H INT 21H INT 21H CALL PRINTCRLF
LEA DX,TFNAME[2] ;create target file (volume) MOV CX,ATTR_ARCHIVE MOV AH,FILE_CREATE INT 21H JNC SOK_CF ;if error occurs then EXIT
LEA DX,ERROR_CF MOV AH,9H INT 21H MOV AH,4CH INT 21H
SOK_CF: MOV TFNUM,AX ;save file number to TFNUM
MOV CX,TFSIZE ;copy (1048576 * volume size) bytes JCXZ CPYFLP COPY: CALL COPYBYTES JC EXIT_WF ;if disk full then EXIT CMP FLAG,1 ;if complete then EXIT JE EXIT_SU LOOP COPY JMP CLOSE
CPYFLP: CALL COPYBYTES ;copy 1457664 (1.44 MB) bytes JC EXIT_WF ;if disk full then EXIT CMP FLAG,1 ;if complete then EXIT JE EXIT_SU
CLOSE: MOV BX,TFNUM ;close target file (volume) MOV AH,FILE_CLOSE INT 21H
POP AX ;restore the last two extension (.L**) from stack INC AX JMP S_NEXT
EXIT_WF:CALL PRINTCRLF LEA DX,ERROR_WF ;print "Insufficient disk space." MOV AH,9H INT 21H JMP EXIT
EXIT_SU:CALL PRINTCRLF LEA DX,COMPLETE ;print "Complete successfully ......" MOV AH,9H INT 21H
EXIT: MOV BX,TFNUM ;close target file (the LAST volume!!!) MOV AH,FILE_CLOSE INT 21H MOV BX,SFNUM ;close source file INT 21H MOV AH,4CH INT 21H
SPLITMODULE ENDP ;----------------------------------------------------------------------------
;Proc Name: COPYBYTES ;Function: copy some bytes (1MB or 1.44MB) from SFNUM (source file number) to TFNUM(target file number) ;Parameter: (none, actually in the memory TFSIZE,SFNUM,TFNUM) ;RetValue: CF: if there are not enough bytes for reading, CF = 1 ;Notice: (1) it can be only used in this program!!!!! COPYBYTES PROC PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI
MOV FLAG,0
MOV SI,24 ;repeat 24 times, copy 60736 bytes per time MOV DI,60736 ;24 * 60736 = 1457664 (1.44 MB) CMP TFSIZE,0 JE C_READ MOV SI,32 ;repeat 32 times, copy 32768 bytes per time MOV DI,32768 ;32 * 32768 = 1048576
C_READ: MOV BX,SFNUM ;read DI bytes from source file MOV CX,DI LEA DX,BUFFER MOV AH,FILE_READ INT 21H
CMP AX,CX ;check out: whether read DI bytes or not JE C_WRITE MOV FLAG,1
C_WRITE:MOV BX,TFNUM ;write DI bytes to target file MOV CX,AX LEA DX,BUFFER MOV AH,FILE_WRITE INT 21H STC CMP AX,CX ;if disk full then return (CF = 1) JNE C_RET
CMP FLAG,1 ;if complete then return (FLAG = 1) JE C_CLC
DEC SI JNZ C_READ
C_CLC: CLC C_RET: POP DI POP SI POP DX POP CX POP BX POP AX RET COPYBYTES ENDP
;Proc Name: BCDTOHEX ;Function: Convert BCD number to HEX number ;Parameter: AX = the BCD number ;RetValue: AX = the HEX number ;Notice: (1) algorithm: ; BCD - (8 * C18 + 4 * 9C + 2 * 6) = HEX ; 8421 - (8 * C18 + 4 * 9C + 2 * 6) BCDTOHEX PROC PUSH BX PUSH CX PUSH DX PUSH SI
MOV BX,AX ; 2 * 6 MOV CL,4 SHR AL,CL XOR AH,AH MOV CH,6 MUL CH
MOV SI,AX ; 2 * 6 --> SI
MOV AL,BH ; 4 * 9C AND AL ,0FH MOV CH,9CH MUL CH
XOR DX,DX ; 4 * 9C + 2 * 6 ADD AX,SI
MOV SI,AX ; 4 * 9C + 2 * 6 --> SI
MOV AL,BH ; 8 * C18 SHR AL,CL XOR AH,AH MOV CX, 0C 18H MUL CX
ADD AX,SI ; 8 * C18 + 4 * 9C + 2 * 6
MOV SI,AX ; 8 * C18 + 4 * 9C + 2 * 6 --> SI
MOV AX,BX ; 8421 - (8 * C18 + 4 * 9C + 2 * 6) --> AX SUB AX,SI
POP SI POP DX POP CX POP BX RET BCDTOHEX ENDP
;Proc Name: RECEIVENUM ;Function: Receive a number from keyboard (Decimal) ;Parameter: DX = the first address of the buffer ;RetValue: Bytes in buffer (i.e. '0018') ;Notice: (1) the first byte from DX is the length of number you want receive ; (2) the second byte from DX is the length of number you inputed actually ; (3) the buffer is not include [ENTER] RECEIVENUM PROC PUSH SI PUSH AX PUSH BX PUSH CX PUSH DX
MOV SI,DX ;save the length to BL,CL MOV BL,BYTE PTR [SI] MOV CL,BYTE PTR [SI] XOR CH,CH
R_AGN: MOV AH,8H ;waiting input INT 21H CMP AL,0DH ;if [ENTER] then save number string and return JE R_ENT CMP AL,8 ;if [BACKSPACE] then delete the last number JE R_BACK CMP CL,0 ;if get the length then BEEP JE R_BEEP CMP AL,'0' ;if '0' <= ASCII <= '9' then SHOW else BEEP JB R_BEEP CMP AL ,'9' JBE R_SHOW
R_BEEP: MOV DL,7H ;BEEP and receive again MOV AH,2H INT 21H JMP R_AGN
R_SHOW: MOV DL, AL ;show character MOV AH,2H INT 21H MOV BYTE PTR [SI+2], AL ;save character to memory INC SI LOOP R_AGN ;receive again JMP R_AGN ;*** when CX = 0, don't execute R_BACK
R_BACK: CMP CL,BL ;avoid deleting extra character JE R_AGN MOV DL,8 ;show [BACKSPACE] MOV AH,2H INT 21H MOV DL,' ' ;clear current cursor's position INT 21H MOV DL,8 ;show [BACKSPACE] again INT 21H CMP CX,0 ;if CX = 0 then not save it to memory JE R_BAGN MOV BYTE PTR [SI+2],0 R_BAGN: DEC SI INC CX JMP R_AGN
R_ENT: MOV DL,0DH ;finish inputing, print 0DH,0AH MOV AH,2H INT 21H MOV DL,0AH INT 21H
POP DX ;restore DX
MOV SI,DX ;save actually length MOV AL,BYTE PTR [SI] XOR AH,AH SUB AL,CL MOV BYTE PTR [SI+1], AL
CMP AL,0 ;if input nothing or input full length then RETURN JE R_RETN CMP AL,BL JE R_RETN
MOV BX,AX ;add leading-zero (i.e. '0018') MOV CX,BX R_PRE0: MOV AL,[SI+BX+1] MOV [SI+5], AL MOV BYTE PTR [SI+BX+1],0 DEC SI LOOP R_PRE0
R_RETN: POP CX POP BX POP AX POP SI RET RECEIVENUM ENDP
;Proc Name: ASCTOHEX ;Function: ASCII to HEX number ;Parameter: DX = the first address of the 4 bytes that you want to convert ;RetValue: AX = the HEX number ;Notice: (1) no error handling ; (2) not (HIGH HIGH LOW LOW) ASCTOHEX PROC PUSH BX PUSH CX PUSH DX PUSH SI
MOV CL,4
MOV SI,DX ;1 MOV BX,SI CALL ASCTOHEX_BYTE MOV AH,DL ;AX: 0000 1111 0000 0000
INC SI ;2 MOV BX,SI CALL ASCTOHEX_BYTE MOV AL ,DL ;AX: 0000 1111 0000 2222
SHL AL ,CL ;AX: 0000 1111 2222 0000
SHL AX,CL ;AX: 1111 2222 0000 0000
INC SI ;3 MOV BX,SI CALL ASCTOHEX_BYTE MOV DH,DL ;DX: 0000 3333 0000 0000
INC SI ;4 MOV BX,SI CALL ASCTOHEX_BYTE ;DX: 0000 3333 0000 4444 SHL DL,CL ;DX: 0000 3333 4444 0000
SHR DX,CL ;DX: 0000 0000 3333 4444 MOV AL ,DL ;AX: 1111 2222 3333 4444
POP SI POP DX POP CX POP BX RET ASCTOHEX ENDP
;Proc Name: ASCTOHEX_BYTE ;Function: ASCII to HEX number by byte ;Parameter: BX = address of the byte that you want to convert ;RetValue: DL = the HEX number ;Notice: (1) no error handling ASCTOHEX_BYTE PROC MOV DL,[BX] CMP DL,'0' JAE AE_0 JMP EXIT_P AE_0: CMP DL,'9' JBE BE_9 CMP DL,'A' JAE AE_DA JMP EXIT_P BE_9: SUB DL,30H JMP EXIT_P AE_DA: CMP DL,'Z' JBE BE_DZ CMP DL,'a' JAE AE_XA JMP EXIT_P BE_DZ: SUB DL,37H JMP EXIT_P AE_XA: CMP DL,'z' JBE BE_XZ JMP EXIT_P BE_XZ: SUB DL,57H EXIT_P: RET ASCTOHEX_BYTE ENDP
;Proc Name: HEXTODECASC ;Function: Convert HEX number to ASCII string of Decimal number ;Parameter: AL = the HEX number you want to convert ; DI = the base pointer that the result will save in, buffer size must be 2. ;RetValue: 2 bytes from the base pointer(DI) in data segment HEXTODECASC PROC PUSH AX PUSH CX PUSH DX PUSH DI MOV DL,10 MOV CX,2 H_NEXT: XOR AH,AH DIV DL ADD AL,30H MOV [DI], AL INC DI MOV DL,1 MOV AL ,AH LOOP H_NEXT POP DI POP DX POP CX POP AX RET HEXTODECASC ENDP
;Proc Name: HEXTODECASC5 ;Function: Convert HEX number to ASCII string of Decimal number ;Parameter: DX = the HEX number you want to convert ; BX = the base pointer that the result will save in, buffer size must be 5. ;RetValue: DI = the number of digit ; 5 bytes from the base pointer(BX) in data segment ;Notice: (1)Variable NUMBER must not be appear in data segment of main procedure ; (2)The tag of segment in main procedure must be "DSEG" HEXTODECASC5 PROC DSEG_DENO SEGMENT NUMBER DW 10000,1000,100,10,1 DSEG_DENO ENDS PUSH SI PUSH AX PUSH CX PUSH DX PUSH DS XOR SI,SI XOR DI,DI MOV CX,5 H5_NEXT:MOV AX,DX MOV DX,DSEG_DENO MOV DS,DX XOR DX,DX DIV WORD PTR [SI] CMP AL ,0 JZ H5_ZERO ADD AL,30H PUSH BX MOV BX,DSEG MOV DS,BX POP BX MOV [BX][DI],AL INC DI H5_ZERO:ADD SI,2 LOOP H5_NEXT ;MOV BYTE PTR [BX][DI],'M' ;spcial in this program POP DS POP DX POP CX POP AX POP SI RET HEXTODECASC5 ENDP
;Proc Name: PRINTCRLF ;Function: Set the next print position to next line ;Parameter: (none) PRINTCRLF PROC PUSH AX PUSH DX
MOV AH,2H MOV DL,0DH INT 21H MOV DL,0AH INT 21H
POP DX POP AX RET PRINTCRLF ENDP
CSEG ENDS END START |
汇编这种语言,只要一放下,就不太容易再捡起来了。但通过学习汇编可以对计算机的底层机制有一个更深层次的了解,而这种了解是不会让人轻易忘记的,并且对今后使用高级语言编程时有很大的好处。
上面的这个用于文件分割的小程序也是我初学汇编时写的,有些想法可能并不尽如人意,还希望高手多多指点。
源代码下载地址:http://csdngoodname008.51.net/File.zip
*-------------------------------------------*
* 转载请通知作者并注明出处,CSDN欢迎您! *
* 作者:卢培培(goodname008) *
* 邮箱:[email protected] *
* 专栏:http://blog.csdn.net/goodname008 *
*-------------------------------------------*