переименовать (заменить символ) в именах файлов и папок

Тема в разделе "WASM.BEGINNERS", создана пользователем hack_virii, 4 окт 2011.

  1. hack_virii

    hack_virii New Member

    Публикаций:
    0
    Регистрация:
    7 июн 2009
    Сообщения:
    71
    Доброго времени суток, Уважаемые!

    Не знал в какой раздел написать свой вопрос.

    Прошу помощи кодом, ссылкой, советом. Кому не жалко.


    Необходимо обойти каталог (включая подкаталоги) и заменить в именах файлов недопустимые символы, на указанный(е).
    Не представляю как подойти к данному вопросу.
    На php все было просто (грубый пример):

    list();
    if (is_dir($file)) then list($file)
    else ...

    Здесь же мне разбираться полгода. Начиная с рекурсии по файлам и папкам и заканчивая заменой символа.

    Если у кого есть ссылки или на работки, буду премного благодарен.

    Решение подойдет на асме, на VB, на BAT.. хоть на чем-нибудь, кроме PHP (нет возможности стартовать Denwer, нужно независимый скрипт\приложение).
     
  2. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    hack_virii
    Пример на fasm. EnumFilesCallback, правда, написана очень стрёмно, но её всё равно надо своей заменить. А EnumFilesFrom делает рекурсивный обход и вполне себе реюзабельна. Для переименования (замены символов) используйте MoveFile внутри своей EnumFilesCallback.
     
  3. hack_virii

    hack_virii New Member

    Публикаций:
    0
    Регистрация:
    7 июн 2009
    Сообщения:
    71
    l_inc, спасибо, добрый человек!

    Ну накрутил!)
    Уже 2 часа верчу. Пока безрезультатно.
    А fasm компилит!:)

    Буду разбираться. Спасибо!
     
  4. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    hack_virii
    Если что, дальнейшие вопросы принимаются.
     
  5. hack_virii

    hack_virii New Member

    Публикаций:
    0
    Регистрация:
    7 июн 2009
    Сообщения:
    71
    Уважаемый l_inc, помогите, пожалуйста, с функцией перебора файлов и папок.
    fasm'овский синтаксис мне чужд, я долго догонял, что stdcall это вызов функции. Или ее объявление?Оо
    В общем, мой навык асма в NNN раз ниже Вашего, прошу помощи.

    Думаю, с поиском и заменой символа в имени файла я смогу разобраться.

    Благодарю за отклик.
     
  6. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    hack_virii
    Эм... Так я ж с ней и помог. EnumFilesFrom перебирает все файлы и для каждого файла вызывает функцию, указатель на которую передан третьим параметром (callback). В данном случае это функция EnumFilesCallback.

    Первым параметром (path) передаётся указатель путь к папке (без слеша на конце), в которой нужно перебирать содержимое.

    Вторым параметром (maxlevel) передаётся максимально допустимый уровень вложенности (если нуль, то вхождения во вложенные папки не будет, т.е. без рекурсии).

    Третьим параметром (callback) передаётся указатель на callback.

    Четвёртым параметром (custom) можно передать любое пользовательское значение. Оно будет каждый раз передаваться внутрь callback'а. Это может быть, например, хендл файла, в который внутри callback'а пишутся результаты перебора. Или указатель на некоторую более сложную структуру.

    stdcall — это вызов функции по указателю на функцию. А invoke — вызов по указателю на указатель (чаще всего применяется для вызова API).
    Ладно. Всё равно я с тех пор исправил баги и слегка улучшил поведение EnumFilesFrom (хотя можно ещё улучшать и улучшать... например, можно значительно понизить расход памяти), поэтому rename_files.asm целиком:
    Код (Text):
    1. format PE GUI 4.0
    2.  
    3. include 'win32a.inc'
    4.  
    5. entry start
    6.  
    7. proc start uses ebx edi
    8.     local curDir[MAX_PATH]:BYTE
    9.     lea ebx,[curDir]                    ;ebx - current directory pointer
    10.     invoke GetCurrentDirectory,MAX_PATH,ebx
    11.     lea edi,[ebx+eax]
    12.  
    13.     stdcall EnumFilesFrom,ebx,-1,EnumFilesCallback,0
    14.     cmp eax,-1
    15.     jz .error
    16.         invoke MessageBox,NULL,msgCompleteText,msgCompleteTitle,MB_OK
    17. ret
    18. .error:
    19.     invoke MessageBox,NULL,msgFileErrText,msgFileErrTitle,MB_OK
    20. ret
    21. endp
    22.  
    23. ;returns postition of the found char or -1 if not found
    24. proc strrchr uses esi edi, string, char
    25.     mov esi,dword[string]
    26.     mov edi,dword[string]
    27.     .next_char:
    28.         lodsb
    29.         cmp al,byte[char]
    30.         jnz .not_found
    31.             mov edi,esi
    32.         .not_found:
    33.     test al,al
    34.     jnz .next_char
    35.    
    36.     lea eax,[edi-1]
    37.     sub eax,dword[string]
    38.     sbb eax,eax
    39.     not eax
    40.     and eax,edi
    41.     add eax,-1
    42. ret
    43. endp
    44.  
    45. ;returns number of copied characters, including null-character
    46. proc strcpy uses esi edi, dest, src, destlen
    47.     mov edi,dword[dest]
    48.     mov esi,dword[src]
    49.     mov ecx,dword[destlen]
    50.     test ecx,ecx
    51.     jz .exit
    52.    
    53.     .next_char:
    54.         lodsb
    55.         stosb
    56.         add ecx,-1
    57.         jz .exit
    58.     test al,al
    59.     jnz .next_char
    60.    
    61.     .exit:
    62.     xor al,al
    63.     mov byte[edi-1],al
    64.     mov eax,dword[destlen]
    65.     sub eax,ecx
    66. ret
    67. endp
    68.  
    69. ;returns 0 to continue file enumeration
    70. ;returns -1 to stop enumeration within current directory
    71. ;returns anything else to stop enumeration completely
    72. proc EnumFilesCallback uses esi edi ebx, filePath, fileAttributes, custom
    73.     ;do not change directories names
    74.     test dword[fileAttributes],FILE_ATTRIBUTE_DIRECTORY
    75.     jnz .exit_continue
    76.  
    77.     ;find file path length
    78.     stdcall strrchr,dword[filePath],0  
    79.     sub eax,dword[filePath]
    80.     lea edi,[eax+1]                     ;edi - file path length (including null-character)
    81.    
    82.     ;allocate some space for new file path
    83.     invoke GetProcessHeap
    84.     invoke HeapAlloc,eax,0,edi
    85.     test eax,eax
    86.     jz .exit_continue
    87.    
    88.     ;copy original file path
    89.     mov ebx,eax                         ;ebx - new file path pointer
    90.     stdcall strcpy,ebx,dword[filePath],edi
    91.    
    92.     ;find a pointer to the file name
    93.     stdcall strrchr,ebx,'\'
    94.     mov esi,eax                         ;esi - pointer to the character right before the file name
    95.    
    96.     ;modify file name
    97.     .next_char:
    98.         add esi,1
    99.         cmp byte[esi],'a'
    100.         je .replace_a
    101.         cmp byte[esi],'b'
    102.         je .replace_b
    103.         cmp byte[esi],'c'
    104.         je .replace_c
    105.         cmp byte[esi],0
    106.         je .rename_file
    107.         jmp .next_char
    108.         .replace_a:
    109.             mov byte[esi],'x'
    110.         jmp .next_char
    111.         .replace_b:
    112.             mov byte[esi],'y'
    113.         jmp .next_char
    114.         .replace_c:
    115.             mov byte[esi],'z'
    116.         jmp .next_char
    117.     .rename_file:
    118.     invoke MoveFile,dword[filePath],ebx
    119.    
    120.     ;free resources
    121.     invoke GetProcessHeap
    122.     invoke HeapFree,eax,0,ebx
    123. .exit_continue:
    124.     xor eax,eax
    125. ret
    126. endp
    127.  
    128. ;returns 0 if full enumeration accomplished or
    129. ;       -1 on error (call GetLastError to get extended info) or
    130. ;       any other stop-value, returned by the callback
    131. proc EnumFilesFrom uses ebx esi edi, path, maxdepth, callback, custom
    132.     locals
    133.         fileData        WIN32_FIND_DATA <>
    134.         rb (3-($-$$+3) mod 4)           ;4 bytes alignment
    135.         dwCurFileMaxLen dd ?
    136.     endl
    137.    
    138.     ;find initial path length (excluding null-character)
    139.     stdcall strrchr,dword[path],0
    140.     sub eax,dword[path]
    141.    
    142.     ;allocate some more (reserve for future file names to possibly prevent HeapReAlloc's)
    143.     add eax,33
    144.     mov dword[dwCurFileMaxLen],eax
    145.     invoke GetProcessHeap
    146.     invoke HeapAlloc,eax,0,dword[dwCurFileMaxLen]
    147.     mov edi,eax                         ;edi - path start position
    148.    
    149.     ;return error if HeapAlloc returned 0
    150.     cmp eax,1
    151.     sbb eax,eax
    152.     jc .exit
    153.    
    154.     ;make a local copy of the initial path
    155.     stdcall strcpy,edi,dword[path],dword[dwCurFileMaxLen]
    156.     lea esi,[edi+eax]                   ;esi - path end position (right after '\'-character)
    157.     mov dword[edi+eax-1],'\*'
    158.  
    159.     ;start files enumeration
    160.     lea edx,[fileData]
    161.     invoke FindFirstFile,edi,edx
    162.    
    163.     ;return error if FindFirstFile returned INVALID_HANDLE_VALUE
    164.     cmp eax,INVALID_HANDLE_VALUE
    165.     jnz .enumerationSuccessful
    166.         invoke GetProcessHeap
    167.         invoke HeapFree,eax,0,edi
    168.         mov eax,-1
    169.         jmp .exit
    170.     .enumerationSuccessful:
    171.     mov ebx,eax                         ;ebx - file search handle
    172.     .process_file:
    173.         lea edx,[fileData.cFileName]
    174.         ;find null-character pointer
    175.         stdcall strrchr,edx,0
    176.        
    177.         ;calculate how much is needed for path + current file name + null-character
    178.         ;(esi-edi)+(eax-fileData.cFileName)+1
    179.         add eax,esi
    180.         lea edx,[fileData.cFileName+edi-1]
    181.         sub eax,edx
    182.        
    183.         ;reallocate if more space required
    184.         cmp dword[dwCurFileMaxLen],eax
    185.         jae .enoughSpace
    186.             mov dword[dwCurFileMaxLen],eax
    187.             invoke GetProcessHeap
    188.             invoke HeapReAlloc,eax,0,edi,dword[dwCurFileMaxLen]
    189.            
    190.             ;return error (-1) if HeapAlloc returned 0
    191.             cmp eax,1
    192.             sbb edx,edx
    193.             jc .exitFreeResources
    194.            
    195.             sub esi,edi        
    196.             mov edi,eax                     ;save new path start position
    197.             add esi,eax                     ;save new path end position
    198.         .enoughSpace:
    199.        
    200.         ;append file name to the end of current path
    201.         lea edx,[fileData.cFileName]
    202.         stdcall strcpy,esi,edx,dword[dwCurFileMaxLen]
    203.        
    204.         ;call the callback function
    205.         ;   if 0 returned, continue enumeration
    206.         ;   if -1 returned, stop enumeration within current directory
    207.         ;   else stop enumeration completely
    208.         invoke callback,edi,dword[fileData.dwFileAttributes],dword[custom]
    209.         test eax,eax
    210.         mov edx,eax
    211.         jnz .exitFreeResources
    212.        
    213.         ;check, whether current file is subdirectory
    214.         test dword[fileData.dwFileAttributes],FILE_ATTRIBUTE_DIRECTORY
    215.         jz .next_file
    216.         cmp dword[maxdepth],0
    217.         jz .next_file
    218.         cmp byte[fileData.cFileName],'.'
    219.         jnz .validSubdir
    220.         cmp byte[fileData.cFileName+1],0
    221.         jz .next_file
    222.         cmp byte[fileData.cFileName+1],'.'
    223.         jnz .validSubdir
    224.         cmp byte[fileData.cFileName+2],0
    225.         jz .next_file
    226.         .validSubdir:
    227.             ;go to subdirectory
    228.             mov edx,dword[maxdepth]
    229.             add edx,-1
    230.             stdcall EnumFilesFrom,edi,edx,dword[callback],dword[custom]
    231.            
    232.             ;stop further enumeration if stopped by callback (not 0 and not -1),
    233.             ;i.e. continue enumeration if EnumFilesFrom returned error (-1)
    234.             lea edx,[eax+1]
    235.             sub edx,1
    236.             ja .exitFreeResources
    237.         .next_file:
    238.        
    239.         ;continue files enumeration
    240.         lea edx,[fileData]
    241.         invoke FindNextFile,ebx,edx
    242.     test eax,eax
    243.     jnz .process_file
    244.     xor edx,edx
    245.    
    246.     ;free resources
    247.     .exitFreeResources:
    248.     push edx
    249.         invoke GetProcessHeap
    250.         invoke HeapFree,eax,0,edi
    251.         invoke FindClose,ebx
    252.     pop eax
    253.     .exit:
    254. ret
    255. endp
    256.  
    257. data import
    258.     library kernel32,'kernel32.dll',\
    259.             user32,'user32.dll'
    260.    
    261.     import kernel32,\
    262.             FindFirstFile,'FindFirstFileA',\
    263.             FindNextFile,'FindNextFileA',\
    264.             FindClose,'FindClose',\
    265.             GetCurrentDirectory,'GetCurrentDirectoryA',\
    266.             GetProcessHeap,'GetProcessHeap',\
    267.             HeapAlloc,'HeapAlloc',\
    268.             HeapReAlloc,'HeapReAlloc',\
    269.             HeapFree,'HeapFree',\
    270.             MoveFile,'MoveFileA'
    271.            
    272.     import user32,\
    273.             MessageBox,'MessageBoxA'
    274. end data
    275.  
    276.  
    277. msgFileErrTitle         db 'Error',0
    278. msgFileErrText          db 'Could not enumerate files',0
    279.  
    280. msgCompleteTitle        db 'Info',0
    281. msgCompleteText         db 'Files renaming successfully complete',0
    Я думаю, понятно, что нужно изменить, чтобы выбрать, какие символы на какие менять (см. комментарий modify file name). Это для простейшего случая один символ на другой символ. Для более изощрённых замен алгоритм придётся усложнить.
    А если ещё и bat-файлик сообразить, то можно нужную папку (или файл из этой папки) просто мышкой на него сбрасывать:
    Код (Text):
    1. @echo off
    2. cd /d "%~1"
    3. start %~dp0\rename_files.exe
     
  7. hack_virii

    hack_virii New Member

    Публикаций:
    0
    Регистрация:
    7 июн 2009
    Сообщения:
    71
    Ух! Потрясающе офигительно! Магия!

    l_inc, Человечище!!!

    ОГРОМНЕЙШЕЕ СПАСИБО!!!

    В каком городе живешь? Давай пивом угощу!


    В одном месте кода (LEA EAX,DWORD PTR DS:[EDI-1]), OllyDbg поместил в EAX значение \xDD - издевается, сволочь.)

    Разбираюсь. Постараюсь не доставать по пустякам, только если будет реальная запара.

    Спасибо!
     
  8. hack_virii

    hack_virii New Member

    Публикаций:
    0
    Регистрация:
    7 июн 2009
    Сообщения:
    71
    Все-таки запара обнаружилась.
    Необходимо заменить любые точки в имени файла, кроме расширения.
    Помогите, пожалуйста, как-то рационально сделать проверку.
    Пока что получается так:
    Код (Text):
    1.     ;modify file name
    2.     next_char:
    3.         add esi,1
    4.         cmp byte[esi],'~'
    5.         je replace_a
    6.         cmp byte[esi],'#'
    7.         je replace_a
    8.         cmp byte[esi],'%'
    9.         je replace_a
    10.         cmp byte[esi],'&'
    11.         je replace_a
    12.         cmp byte[esi],'*'
    13.         je replace_a
    14.         cmp byte[esi],'{'
    15.         je replace_a
    16.         cmp byte[esi],'}'
    17.         je replace_a
    18.         cmp byte[esi],':'
    19.         je replace_a
    20.         cmp byte[esi],'<'
    21.         je replace_a
    22.         cmp byte[esi],'>'
    23.         je replace_a
    24.         cmp byte[esi],'?'
    25.         je replace_a
    26.         cmp byte[esi],'+'
    27.         je replace_a
    28.         cmp byte[esi],'|'
    29.         je replace_a
    30.         cmp byte[esi],'"'
    31.         je replace_a
    32.         cmp byte[esi],"'"
    33.         je replace_a
    34.         cmp byte[esi],"$"
    35.         je replace_a
    36.         cmp byte[esi],"@"
    37.         je replace_a
    38.         cmp byte[esi],"="
    39.         je replace_a
    40.  
    41.     cmp byte[esi],'.'
    42.     jnz L2
    43.     ;do not change directories names
    44.     test dword[fileAttributes],FILE_ATTRIBUTE_DIRECTORY
    45.     jz L4
    46.     jmp replace_a
    47.  
    48. L4:                              
    49. cmp byte[esi+3],0          
    50. jne replace_a
    51.  
    52. L2:
    53.         cmp byte[esi],0
    54.         je rename_file
    55.         jmp next_char
    56.         replace_a:
    57.             mov byte[esi],'_'
    58.         jmp next_char
    59.     rename_file:
    60.     invoke MoveFile,dword[filePath],ebx
    Затыка в L4. Кол-во символов в расширении может быть 2-4 символа.
    Как их проверить наиболее компактно?
     
  9. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Расширение может быть любой длины, не только 2, 3 или 4 символа. Правильнее в данном случае проходить имя файла с конца и при обнаружении первой точки устанавливать некий флаг, говорящий о том, что все следующие встречаемые точки следует заменить.
    Кстати, имя файла не может содержать знаки
    Код (Text):
    1. /\:*?"<>|
    , на них можно проверку не делать.
     
  10. hack_virii

    hack_virii New Member

    Публикаций:
    0
    Регистрация:
    7 июн 2009
    Сообщения:
    71
    Ezrah, спасибо!
    Лишние символы убрал (действительно, винда же не даст задать подобное имя).
    А с точкой.. Если я так все переверну, то еще неделю возиться буду. А надо срочно. Чтоб работало.
    Потом обязательно оптимизирую. Актуально все-таки.

    Пока что сделал через ***, но вроде работает.) Пускай и быдлокод. Все приходит с опытом.(с)

    Код (Text):
    1. format PE GUI 4.0
    2.  
    3. include 'include/win32a.inc'
    4.  
    5. entry start
    6.  
    7. proc start uses ebx edi
    8. L1:
    9.  
    10.     local curDir[MAX_PATH]:BYTE
    11.     lea ebx,[curDir]            ;ebx - current directory pointer
    12.     invoke GetCurrentDirectory,MAX_PATH,ebx
    13.     lea edi,[ebx+eax]
    14.  
    15.     stdcall EnumFilesFrom,ebx,25,EnumFilesCallback,0
    16.     cmp eax,-1
    17.     jz .error
    18.  
    19. sub byte[Counter],1
    20. cmp byte[Counter],0
    21. ja L1
    22.  
    23.     invoke MessageBox,NULL,msgCompleteText,msgCompleteTitle,MB_OK
    24. ret
    25. .error:
    26.     invoke MessageBox,NULL,msgFileErrText,msgFileErrTitle,MB_OK
    27. ret
    28. endp
    29.  
    30. ;returns postition of the found char or -1 if not found
    31. proc strrchr uses esi edi, string, char
    32.     mov esi,dword[string]
    33.     mov edi,dword[string]
    34.     .next_char:
    35.     lodsb
    36.     cmp al,byte[char]
    37.     jnz .not_found
    38.         mov edi,esi
    39.     .not_found:
    40.     test al,al
    41.     jnz .next_char
    42.    
    43.     lea eax,[edi-1]
    44.     sub eax,dword[string]
    45.     sbb eax,eax
    46.     not eax
    47.     and eax,edi
    48.     add eax,-1
    49. ret
    50. endp
    51.  
    52. ;returns number of copied characters, including null-character
    53. proc strcpy uses esi edi, dest, src, destlen
    54.     mov edi,dword[dest]
    55.     mov esi,dword[src]
    56.     mov ecx,dword[destlen]
    57.     test ecx,ecx
    58.     jz .exit
    59.    
    60.     .next_char:
    61.     lodsb
    62.     stosb
    63.     add ecx,-1
    64.     jz .exit
    65.     test al,al
    66.     jnz .next_char
    67.    
    68.     .exit:
    69.     xor al,al
    70.     mov byte[edi-1],al
    71.     mov eax,dword[destlen]
    72.     sub eax,ecx
    73. ret
    74. endp
    75.  
    76. ;returns 0 to continue file enumeration
    77. ;returns -1 to stop enumeration within current directory
    78. ;returns anything else to stop enumeration completely
    79. proc EnumFilesCallback uses esi edi ebx, filePath, fileAttributes, custom
    80.     ;find file path length
    81.     stdcall strrchr,dword[filePath],0    
    82.     sub eax,dword[filePath]
    83.     lea edi,[eax+1]            ;edi - file path length (including null-character)
    84.    
    85.     ;allocate some space for new file path
    86.     invoke GetProcessHeap
    87.     invoke HeapAlloc,eax,0,edi
    88.     test eax,eax
    89. jz exit_continue
    90.    
    91. L3:    ;copy original file path
    92.     mov ebx,eax                ;ebx - new file path pointer
    93.     stdcall strcpy,ebx,dword[filePath],edi
    94.    
    95.     ;find a pointer to the file name
    96.     stdcall strrchr,ebx,'\'
    97.     mov esi,eax                ;esi - pointer to the character right before the file name
    98.    
    99.     ;modify file name
    100.     next_char:
    101.     add esi,1
    102.     cmp byte[esi],'~'
    103.     je replace_a
    104.     cmp byte[esi],'#'
    105.     je replace_a
    106.     cmp byte[esi],'%'
    107.     je replace_a
    108.     cmp byte[esi],'&'
    109.     je replace_a
    110.     cmp byte[esi],'{'
    111.     je replace_a
    112.     cmp byte[esi],'}'
    113.     je replace_a
    114.     cmp byte[esi],'+'
    115.     je replace_a
    116.     cmp byte[esi],"'"
    117.     je replace_a
    118.     cmp byte[esi],"$"
    119.     je replace_a
    120.     cmp byte[esi],"@"
    121.     je replace_a
    122.     cmp byte[esi],"="
    123.     je replace_a
    124.  
    125.     cmp byte[esi],'.'
    126.     jnz L2
    127.     ;do not change directories names
    128.     test dword[fileAttributes],FILE_ATTRIBUTE_DIRECTORY
    129.     jz L4
    130.     jmp replace_a
    131.  
    132. L4:
    133. push esi
    134. push edi
    135. push eax
    136. push ecx
    137. mov dword[Address],esi
    138. mov edi,esi
    139. inc edi
    140. mov al,'.'
    141. mov ecx,25
    142. cld
    143. repne scasb
    144. jnz Quit
    145. ;dec edi
    146. mov edi,dword[Address]
    147. mov byte[edi],'_'
    148. jmp Quit
    149.  
    150. Quit:
    151. pop ecx
    152. pop eax
    153. pop edi
    154. pop esi
    155. jmp L2
    156.  
    157. L2:
    158.     cmp byte[esi],0
    159.     je rename_file
    160.     jmp next_char
    161.     replace_a:
    162.         mov byte[esi],'_'
    163.     jmp next_char
    164.     rename_file:
    165.     invoke MoveFile,dword[filePath],ebx
    166.    
    167.     ;free resources
    168.     invoke GetProcessHeap
    169.     invoke HeapFree,eax,0,ebx
    170. exit_continue:
    171.     xor eax,eax
    172. ret
    173. endp
    174.  
    175. ;returns 0 if full enumeration accomplished or
    176. ;        -1 on error (call GetLastError to get extended info) or
    177. ;        any other stop-value, returned by the callback
    178. proc EnumFilesFrom uses ebx esi edi, path, maxdepth, callback, custom
    179.     locals
    180.     fileData    WIN32_FIND_DATA <>
    181.     rb (3-($-$$+3) mod 4)        ;4 bytes alignment
    182.     dwCurFileMaxLen dd ?
    183.     endl
    184.    
    185.     ;find initial path length (excluding null-character)
    186.     stdcall strrchr,dword[path],0
    187.     sub eax,dword[path]
    188.    
    189.     ;allocate some more (reserve for future file names to possibly prevent HeapReAlloc's)
    190.     add eax,33
    191.     mov dword[dwCurFileMaxLen],eax
    192.     invoke GetProcessHeap
    193.     invoke HeapAlloc,eax,0,dword[dwCurFileMaxLen]
    194.     mov edi,eax                ;edi - path start position
    195.    
    196.     ;return error if HeapAlloc returned 0
    197.     cmp eax,1
    198.     sbb eax,eax
    199.     jc .exit
    200.    
    201.     ;make a local copy of the initial path
    202.     stdcall strcpy,edi,dword[path],dword[dwCurFileMaxLen]
    203.     lea esi,[edi+eax]            ;esi - path end position (right after '\'-character)
    204.     mov dword[edi+eax-1],'\*'
    205.  
    206.     ;start files enumeration
    207.     lea edx,[fileData]
    208.     invoke FindFirstFile,edi,edx
    209.    
    210.     ;return error if FindFirstFile returned INVALID_HANDLE_VALUE
    211.     cmp eax,INVALID_HANDLE_VALUE
    212.     jnz .enumerationSuccessful
    213.     invoke GetProcessHeap
    214.     invoke HeapFree,eax,0,edi
    215.     mov eax,-1
    216.     jmp .exit
    217.     .enumerationSuccessful:
    218.     mov ebx,eax                ;ebx - file search handle
    219.     .process_file:
    220.     lea edx,[fileData.cFileName]
    221.     ;find null-character pointer
    222.     stdcall strrchr,edx,0
    223.    
    224.     ;calculate how much is needed for path + current file name + null-character
    225.     ;(esi-edi)+(eax-fileData.cFileName)+1
    226.     add eax,esi
    227.     lea edx,[fileData.cFileName+edi-1]
    228.     sub eax,edx
    229.    
    230.     ;reallocate if more space required
    231.     cmp dword[dwCurFileMaxLen],eax
    232.     jae .enoughSpace
    233.         mov dword[dwCurFileMaxLen],eax
    234.         invoke GetProcessHeap
    235.         invoke HeapReAlloc,eax,0,edi,dword[dwCurFileMaxLen]
    236.        
    237.         ;return error (-1) if HeapAlloc returned 0
    238.         cmp eax,1
    239.         sbb edx,edx
    240.         jc .exitFreeResources
    241.        
    242.         sub esi,edi        
    243.         mov edi,eax                ;save new path start position
    244.         add esi,eax                ;save new path end position
    245.     .enoughSpace:
    246.    
    247.     ;append file name to the end of current path
    248.     lea edx,[fileData.cFileName]
    249.     stdcall strcpy,esi,edx,dword[dwCurFileMaxLen]
    250.    
    251.     ;call the callback function
    252.     ;    if 0 returned, continue enumeration
    253.     ;    if -1 returned, stop enumeration within current directory
    254.     ;    else stop enumeration completely
    255.     invoke callback,edi,dword[fileData.dwFileAttributes],dword[custom]
    256.     test eax,eax
    257.     mov edx,eax
    258.     jnz .exitFreeResources
    259.    
    260.     ;check, whether current file is subdirectory
    261.     test dword[fileData.dwFileAttributes],FILE_ATTRIBUTE_DIRECTORY
    262.     jz .next_file
    263.     cmp dword[maxdepth],0
    264.     jz .next_file
    265.     cmp byte[fileData.cFileName],'.'
    266.     jnz .validSubdir
    267.     cmp byte[fileData.cFileName+1],0
    268.     jz .next_file
    269.     cmp byte[fileData.cFileName+1],'.'
    270.     jnz .validSubdir
    271.     cmp byte[fileData.cFileName+2],0
    272.     jz .next_file
    273.     .validSubdir:
    274.         ;go to subdirectory
    275.         mov edx,dword[maxdepth]
    276.         add edx,-1
    277.         stdcall EnumFilesFrom,edi,edx,dword[callback],dword[custom]
    278.        
    279.         ;stop further enumeration if stopped by callback (not 0 and not -1),
    280.         ;i.e. continue enumeration if EnumFilesFrom returned error (-1)
    281.         lea edx,[eax+1]
    282.         sub edx,1
    283.         ja .exitFreeResources
    284.     .next_file:
    285.    
    286.     ;continue files enumeration
    287.     lea edx,[fileData]
    288.     invoke FindNextFile,ebx,edx
    289.     test eax,eax
    290.     jnz .process_file
    291.     xor edx,edx
    292.    
    293.     ;free resources
    294.     .exitFreeResources:    
    295.     push edx
    296.     invoke GetProcessHeap
    297.     invoke HeapFree,eax,0,edi
    298.     invoke FindClose,ebx
    299.     pop eax
    300.     .exit:
    301. ret
    302. endp
    303.  
    304. data import
    305.     library kernel32,'kernel32.dll',\
    306.         user32,'user32.dll'
    307.    
    308.     import kernel32,\
    309.         FindFirstFile,'FindFirstFileA',\
    310.         FindNextFile,'FindNextFileA',\
    311.         FindClose,'FindClose',\
    312.         GetCurrentDirectory,'GetCurrentDirectoryA',\
    313.         GetProcessHeap,'GetProcessHeap',\
    314.         HeapAlloc,'HeapAlloc',\
    315.         HeapReAlloc,'HeapReAlloc',\
    316.         HeapFree,'HeapFree',\
    317.         MoveFile,'MoveFileA'
    318.        
    319.     import user32,\
    320.         MessageBox,'MessageBoxA'
    321. end data
    322.  
    323.  
    324. msgFileErrTitle     db 'Error',0
    325. msgFileErrText        db 'Could not enumerate files',0
    326.  
    327. msgCompleteTitle    db 'Info',0
    328. msgCompleteText     db 'Files renaming successfully complete',0
    329. Counter         db 10
    330. Address         dd ?
    l_inc, спасибо большое! Выручил!
    На авторство сего кода, естественно, не претендую. Он твой (Ваш).

    Ezrah, благодарю за совет!


    Если господа модераторы не закроют тему, я еще отпишусь, как удалось оптимизировать.
     
  11. hack_virii

    hack_virii New Member

    Публикаций:
    0
    Регистрация:
    7 июн 2009
    Сообщения:
    71
    Шайтан!

    Ezrah прав.
    Нужен альтернативный способ поиска точек.
    Неправильный подход сканить память до ближайшей точки после текущей.
    Ошибка в этом куске:
    Код (Text):
    1. push eax
    2. push ecx
    3. mov dword[Address],esi
    4. mov edi,esi
    5. inc edi
    6. mov al,'.'
    7. mov ecx,25
    8. cld
    9. repne scasb
    10. jnz Quit
    11. ;dec edi
    12. mov edi,dword[Address]
    13. mov byte[edi],'_'
    14. jmp Quit
    А именно:
    mov ecx,25.

    Поди угадай, что в памяти лежит и где будет след. точка.
    25 символов на имя файла - это я лихо.

    Сорри! Надеюсь никто не пострадал.)
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    hack_virii
    Ну с учётом наличия ф-ии strrchr сделать это крайне просто:
    Код (Text):
    1. ...
    2.     ;find a pointer to the file name
    3.     stdcall strrchr,ebx,'\'
    4.     mov esi,eax                 ;esi - pointer to the character right before the file name
    5.    
    6.     ;find position of the last dot
    7.     stdcall strrchr,esi,'.'
    8.     mov edx,eax                ;edx - position of the last dot or -1
    9.  
    10.     ;modify file name
    11.     .next_char:
    12.     add esi,1
    13.  
    14.     cmp esi,edx
    15.     je .next_char
    16.  
    17.     cmp byte[esi],'~'
    18.     je replace_a
    19.     cmp byte[esi],'#'
    20. ...
    Добавлено, как видите, всего четыре строчки. Кстати, имена всех локальных меток крайне желательно начинать с точки. Иначе нарвётесь на неожиданные проблемы. Да и все прочие извращения, добавленные Вами, похоже, можно убрать.
    Не Бог весть какой код. Можете претендовать, если хотите. :)