Blog. Just Blog

Работа с INI-файлами на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Работа с INI-файлами на Ассемблере
Работа с INI-файлами на Ассемблере

Конфигурационные ini-файлы появились в самых первых версиях Windows. Изначально в них хранились только настройки Windows, а затем они стали использоваться для хранения параметров других приложений. Начиная с Windows 95, Microsoft объявил ini-файлы устаревшими и с тех пор предлагает использовать системный реестр для хранения всех настроек и данных программ. Лично я считаю, что приложения должны быть легко переносимыми между компьютерами, а также легко и полностью деинсталлироваться, поэтому внедрение в систему должно быть минимальным. Хранение всех настроек в ini-файле или в xml-файле в папке с программой - это, на мой взгляд, самое правильное решение, а в реестр нужно залезать только в случае крайней необходимости.

Несложная структура формата ini-файлов позволяет легко обрабатывать их программно и имеет достаточно понятный вид для чтения и изменения человеком. Работать с ini-файлами из приложения одно удовольствие: чтобы читать параметры из файла конфигурации достаточно всего двух функций GetPrivateProfileString и GetPrivateProfileInt, а вот для записи данных обратно есть только одна функция WritePrivateProfileString. Но это хорошо, когда вы обрабатываете ini-файл с известной структурой, когда в приложении заранее определены имена секций и названия ключей.

Пример INI-файла
Пример INI-файла

А вот случай посложнее, когда в связи с особенностью работы приложения, структура ini-файла неизвестна. Или если известны имена секций, но количество и список ключей и их значений могут меняться. Парсить ini-файл самостоятельно - задача не самая тривиальная. При кажущейся простоте структуры, в файле могут быть комментарии, строки могут быть отформатированы разными способами, ключи и значения могут быть разделены как пробелами, так и табуляциями, да мало ли еще может быть вариантов. К счастью, разработчики WinAPI позаботились об этом, и система способна полностью парсить ini-файлы самостоятельно. Сегодня я расскажу, как на Ассемблере прочитать структуру секций, все ключи и их значения из произвольного ini-файла.

Сперва определим в сегменте данных переменные, в которые будут записаны все нужные нам значения.
  1. section '.data' data readable writeable
  2.  
  3. ; Список секций
  4. sections rb 1024
  5. ; Список ключений и значений
  6. keys     rb 1024*32
  7. ; Имя секции
  8. sname    rb 100h
  9. ; Название ключа
  10. key      rb 100h
  11. ; Значение ключа
  12. value    rb 100h
Список секций ini-файла можно получить при помощи функции GetPrivateProfileSectionNames. Она вернет список имен секций в виде последовательности ASCIIZ-строк, окончание списка - нулевой байт. Количество секций и размер блока памяти для них нигде в документации не оговорены, мне кажется, что одного килобайта для этого будет достаточно.

Список имен секций
Список имен секций

Содержимое секций можно прочитать другой функцией - GetPrivateProfileSection. Она вернет список ключей и их значений в виде ASCIIZ-строк в формате "ключ=значение". Окончание списка также определяется нулевым байтом. Все комментарии удаляются, а строки, которые не соответствуют формату ini-файла, игнорируются. При этом максимальный размер полезного содержимого секции, как сказано в описании функции, не должен превышать 32 килобайта.

Список ключей и их значений
Список ключей и их значений

И вот этот список нам все-таки придется парсить самостоятельно. Имя ключа и его значение всегда разделено знаком равенства "=" без пробелов, независимо от того, как эта строчка была записана в исходном файле. Разработчики WinAPI и тут нам очень помогли. Полностью код для парсинга ini-файла выглядит примерно так:
  1.         ; Получить список секций ini-файла
  2.         invoke  GetPrivateProfileSectionNames,sections,1024,ini_file
  3.  
  4.         ; Файл пустой?
  5.         or      eax,eax
  6.         jz      loc_scan_sections_done
  7.  
  8.         ; Указатель на список секций
  9.         mov     esi,sections
  10.  
  11. loc_scan_sections:
  12.         ; Конец списка секций?
  13.         cmp     byte [esi],0
  14.         je      loc_scan_sections_done
  15.  
  16.         ; Имя обрабатываемой секции
  17.         mov     edi,sname
  18. @@:
  19.         lodsb
  20.         stosb
  21.         or      al,al
  22.         jnz     @b
  23.  
  24.         push    esi
  25.  
  26.         ;----------------------------------------------
  27.         ; sname = имя секции
  28.         ;----------------------------------------------
  29.  
  30.         ; Прочитать содержимое секции
  31.         invoke  GetPrivateProfileSection,sname,keys,1024*32,ini_file
  32.         ; Секция пустая?
  33.         or      eax,eax
  34.         jz      loc_scan_keys_done
  35.  
  36.         ; Указатель на список ключений и значений
  37.         mov     esi,keys
  38.  
  39. loc_scan_keys:
  40.         ; Конец списка ключей?
  41.         cmp     byte [esi],0
  42.         je      loc_scan_keys_done
  43.  
  44.         ; Название ключа
  45.         mov     edi,key
  46. @@:
  47.         lodsb
  48.         cmp     al,'='
  49.         je      @f
  50.         stosb
  51.         jmp     @b
  52. @@:
  53.         xor     eax,eax
  54.         stosb
  55.  
  56.         ; Значение ключа
  57.         mov     edi,value
  58. @@:
  59.         lodsb
  60.         stosb
  61.         or      al,al
  62.         jnz     @b
  63.  
  64.         ;----------------------------------------------
  65.         ; key = название ключа
  66.         ; value = значение ключа
  67.         ;----------------------------------------------
  68.  
  69.         ; Следующий ключ
  70.         jmp     loc_scan_keys
  71.  
  72. loc_scan_keys_done:
  73.  
  74.         ; Следующая секция
  75.         pop     esi
  76.         jmp     loc_scan_sections
  77.  
  78. loc_scan_sections_done:
  79.  
  80.         ; Разбор ini-файла завершен
Для удобства обработки имена секций копируются в переменную sname, а имена и значения ключей, соответственно, в переменные key и value. Места в коде, где эти значения можно обрабатывать, выделены комментариями.

В приложении пример программы с исходным текстом, которая парсит находящийся рядом с ней ini-файл и выводит его структуру в окно лога.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Read.INI.File.Demo.zip (3,240 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 1471 | Комментариев: 3

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (21.06.2016 в 00:24):
Цитатасуществует популярный стандартный метод работы со своим файлом настроек - его часто размещали в каталоге %WINDIR%

Если запись в папку с программой по какой-то причине закрыта, то можно хранить настройки в пользовательской папке %USERPROFILE% или %LOCALAPPDATA%, не обязательно же сразу лезть в каталог винды. Экспорт-импорт из/в реестр тоже не панацея, при внезапно рухнувшей системе доступ к реестру может оказаться если не невозможен, то по крайней мере сильно затруднен. А если программа хранит настройки у себя в файле, то после переустановки системы или при переносе программы на другой комп достаточно будет только заново создать ярлычки для ее запуска. При хранении настроек в пользовательской папке легко решается вопрос с персональными настройками для разных учетных записей, если программа подразумевает для них какой-то индивидуальный режим работы. Резервное копирование в автоматическом режиме тоже гораздо легче делать поиском и архивированием *.ini, чем прописыванием в бэкапилке и поддержанием в актуальном состоянии списка из 100500 веток реестра. Короче, сплошные плюсы :)
Реестр must die!
user (20.06.2016 в 19:42):
--Добавлено--

.. когда-то сделал собственную библиотечку на Си (для DOS) с реализацией аналогов Get/Wirite-PrivateProfileInt и Get/Write**String, но, как это часто бывало, попользовался ею сам всего пару раз и забросил - слишком громоздкая оказалась штука, хотя работала вполне нормально ..
С WinAPI всё гораздо проще.
user (20.06.2016 в 19:29):
Немного поразглагольствую на тему, с позволенья.

Действительно, использование собственного файла настроек выглядит предпочтительным во всех случаях, кроме, разве что, случая запуска программы с защищённого от записи носителя.

Но и в этом случае существует популярный стандартный метод работы со своим файлом настроек - его часто размещали в каталоге %WINDIR%. Особенно это было популярно во времена WIN16. Там (в %WINDIR%) обычно накапливались эти самые INI-файлы в приличных количествах от разных программ.

Такой способ тоже имеет недостаток - при запуске разных версий софта он будет писать/читать INI-файл не своей версии.
Примером может служить популярный wave-редактор CoolEdit. У этого редактора в INI-файле хранились регистрационные данные, так что головняк был постоянный.
Решалось запуском CoolEdit'а из пакетного файла, который прежде копировал свой INI из каталога программы в %WINDIR%.
Неудобство заключалось в том, что вновь сохранённые настройки перезаписывались старым файлом при следующем запуске.

Еще один неплохой способ хранения настроек в популярном файловом менеджере FAR - настройки хранятся в реестре, но их можно оттуда экспортировать в reg-файл c помощью самой программы. Для сохранения/переноса на другую машину.

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

Симпатичным представляется вариант, когда программа использует свой INI-файл в каталоге запуска, иначе INI-файл в каталоге %WINDIR%, иначе ключи в реестре. И есть возможность выбрать способ при сохренении настроек.

Ну, как-то так.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0032 сек.) / Память: 4.5 Mb
Наверх