Blog. Just Blog

Работа с Quoted-Printable строками на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Механизм конвертации Quoted-Printable предназначен для представления данных, в основном состоящих из байтов, соответствующих символам, имеющим изображение в символьном наборе ASCII. Если конвертируемые данные в основном представляют собой ASCII-текст, то конечная их форма остается узнаваемой и читаемой для человека. Как правило, такое кодирование используется при передаче бинарных данных или текстов в различных кодировках через электронную почту. Сообщение, полностью состоящее из ASCII-символов, также может быть конвертировано в Quoted-Printable, что гарантирует его содержимому целостность при прохождении через всякие шлюзы, в которых происходит языковая перекодировка символов или преобразование концов строк и т.д. В результате данного кодирования все байты сообщения будут иметь такие значения, которые в дальнейшем не будут модифицированы почтовым транспортом.

Согласно спецификации, в Quoted-Printable байты должны быть представлены в соответствии со следующими правилами:
  • Каждый байт, кроме тех, которые используются для обозначения конца строки, может быть представлен с помощью двух шестнадцатеричных цифр, предваряемых знаком "=". При написании шестнадцатеричных цифр с A по F должны использоваться заглавные буквы. Кроме тех случаев, когда нижеследующие правила позволяют альтернативное кодирование, данное правило является обязательным.

  • Байты с десятичным значением с 33 по 60 и с 62 по 126 МОГУТ быть представлены ASCII-символами, соответствующими этим значениям (с '!' по '<' и с '>' по '~').

  • Пробел в кодированной строке может быть заменен на символ подчеркивания "_".

  • Байты со значениями 9 и 32 МОГУТ быть представлены как ASCII-символы "Табуляция" и "Пробел", но НЕ ДОЛЖНЫ быть представлены так в конце строки. Везде, где они представлены соответствующими ASCII-символами, за ними должен следовать символ, имеющий графическое изображение (печатный символ). В конце же строки символы табуляции и пробела должны быть представлены в соответствии с правилом #1, так как некоторые почтовые транспорты могут убирать пробелы в конце строки.

  • Конец строки в тексте письма должен быть представлен (в соответствии с RFC 822) последовательностью CRLF. Так как в каноническом представлении текста не требуется визуального отображения символов конца строки, в Quoted-Printable не используется видимых символов для обозначения конца строки.

  • В соответствии со спецификацией Quoted-Printable, длина строки не должна превышать 76 символов. В противном случае используется "мягкий" перевод строки, представимый знаком равенства. Например, если исходная строка имела вид:

    Если программист в девять утра уже на работе, значит он там же и ночевал.

    то в Quoted-Printable encoding он может быть представлена следующим образом:

    Если программист в девять утра =
    уже на работе, значит =
    он там же и ночевал.

    Это обеспечивает механизм восстановления исходной длины строки пользовательским почтовым агентом.
Для решения некоторых своих задач я написал на Ассемблере две функции - для кодирования произвольной строки по правилам Quoted-Printable и раскодирования Quoted-Printable данных. При этом, если данные не в точности соответствуют спецификации, то функция раскодирования старается максимально корректно их восстановить.

Функция Quoted-Printable-декодирования принимает в качестве параметров три значения: указатель на исходную строку, длина исходной строки и указатель на буфер-приемник для раскодированной строки.
  1. ;-----------------------------------------------------------------------
  2. ; Функция Quoted-Printable-декодирования
  3. ; by ManHunter / PCL
  4. ; http://www.manhunter.ru
  5. ;-----------------------------------------------------------------------
  6. ; Параметры:
  7. ;       lpData - указатель на строку
  8. ;       dSize  - длина строки
  9. ;       lpBuff - указатель на буфер-приемник
  10. ;-----------------------------------------------------------------------
  11. proc    qp_decode lpData:DWORD, dSize:DWORD, lpBuff:DWORD
  12.         push    eax ebx ecx edi esi
  13.  
  14.         mov     ecx,[dSize]
  15.         mov     esi,[lpData]
  16.         mov     edi,[lpBuff]
  17.  
  18.         or      ecx,ecx
  19.         jz      .loc_done
  20. .loc_decode:
  21.         lodsb
  22.  
  23.         ; Замена символа подчеркивания на пробел
  24.         ; для поддержки стандартам QP-кодирования
  25.         cmp     al,'_'
  26.         jne     @f
  27.         mov     al,' '
  28.         jmp     .loc_store
  29. @@:
  30.         ; Возможно, это закодированный символ
  31.         cmp     al,'='
  32.         jne     .loc_store
  33.  
  34.         ; Строка заканчивается?
  35.         cmp     ecx,3
  36.         jb      .loc_store
  37.  
  38.         ; Мягкий перенос строки?
  39.         cmp     word [esi],0A0Dh
  40.         jne     .first_digit
  41.         inc     esi
  42.         inc     esi
  43.         dec     ecx
  44.         dec     ecx
  45.         jmp     .loc_loop
  46.  
  47.         ; Проверить два следующих символа
  48. .first_digit:
  49.         ; Первый символ за '='
  50.         mov     bl,byte [esi]
  51.         cmp     bl,'0'
  52.         jb      .loc_store
  53.         cmp     bl,'9'
  54.         ja      @f
  55.         sub     bl,'0'
  56.         shl     bl,4
  57.         jmp     .second_digit
  58. @@:
  59.         ; Символ в нижний регистр
  60.         or      bl,20h
  61.         cmp     bl,'a'
  62.         jb      .loc_store
  63.         cmp     bl,'f'
  64.         ja      .loc_store
  65.         sub     bl,'a'-10
  66.         shl     bl,4
  67.  
  68. .second_digit:
  69.         ; Второй символ за '='
  70.         mov     bh,byte [esi+1]
  71.         cmp     bh,'0'
  72.         jb      .loc_store
  73.         cmp     bh,'9'
  74.         ja      @f
  75.         sub     bh,'0'
  76.         jmp     .loc_make_byte
  77. @@:
  78.         ; Символ в нижний регистр
  79.         or      bh,20h
  80.         cmp     bh,'a'
  81.         jb      .loc_store
  82.         cmp     bh,'f'
  83.         ja      .loc_store
  84.         sub     bh,'a'-10
  85.  
  86. .loc_make_byte:
  87.         ; Собрать байт из двух половинок
  88.         add     bl,bh
  89.         mov     al,bl
  90.  
  91.         ; Пропустить следующие символы
  92.         dec     ecx
  93.         dec     ecx
  94.         inc     esi
  95.         inc     esi
  96.  
  97. .loc_store:
  98.         ; Записать раскодированный символ в строку
  99.         stosb
  100. .loc_loop:
  101.         loop    .loc_decode
  102. .loc_done:
  103.         ; Символ конца строки
  104.         mov     al,0
  105.         stosb
  106.  
  107.         pop     esi edi ecx ebx eax
  108.         ret
  109. endp
Исходная строка может в точности соответствовать спецификации Quoted-Printable, но может и отличаться. В этом случае все последовательности символов, подходящие под формат Quoted-Printable, в том числе и мягкие переносы, будут перекодированы, а все остальные символы скопированы без изменений. Размер буфера-приемника не проверяется, поэтому он должен быть не менее длины исходной строки с учетом завершающего нулевого символа (признак окончания строки).

Функция кодирования Quoted-Printable принимает четыре параметра: указатель на исходную строку, длина исходной строки, указатель на буфер-приемник для закодированной строки и максимальная длина строки, после которой будет записываться символ мягкого переноса. Если мягкие переносы использовать не требуется, этот параметр должен быть равен -1.
  1. ;-----------------------------------------------------------------------
  2. ; Функция Quoted-Printable-кодирования
  3. ; by ManHunter / PCL
  4. ; http://www.manhunter.ru
  5. ;-----------------------------------------------------------------------
  6. ; Параметры:
  7. ;       lpData - указатель на строку
  8. ;       dSize  - длина строки
  9. ;       lpBuff - указатель на буфер-приемник
  10. ;       dLen   - длина строки для мягкого переноса (рекомендуется 76
  11. ;                символов), -1 = без лимита
  12. ;-----------------------------------------------------------------------
  13. proc    qp_encode lpData:DWORD, dSize:DWORD, lpBuff:DWORD, dLen:DWORD
  14.         push    eax ecx edi esi
  15.  
  16.         mov     ecx,[dSize]
  17.         mov     esi,[lpData]
  18.         mov     edi,[lpBuff]
  19.  
  20.         ; Проверка и корректировка длины
  21.         cmp     [dLen],-1
  22.         jne     @f
  23.         sub     [dLen],3
  24.         cmp     [dLen],3
  25.         ja      @f
  26.         mov     [dLen],3
  27. @@:
  28.         or      ecx,ecx
  29.         jz      .loc_done
  30.  
  31.         xor     ebx,ebx
  32. .loc_encode:
  33.         mov     al,'='
  34.         stosb
  35.  
  36.         lodsb
  37.  
  38.         ; Перевести байт в HEX-строку
  39.         movzx   eax,al
  40.         ror     eax,4
  41.         and     al,0Fh
  42.         daa
  43.         add     al,0F0h
  44.         adc     al,40h
  45.         stosb
  46.  
  47.         shr     eax,28
  48.         and     al,0Fh
  49.         daa
  50.         add     al,0F0h
  51.         adc     al,40h
  52.         stosb
  53.  
  54.         ; Требуется ли мягкий перенос?
  55.         add     ebx,3
  56.         cmp     ebx,[dLen]
  57.         jb      @f
  58.         xor     ebx,ebx
  59.         mov     al,'='
  60.         stosb
  61.         mov     eax,0A0Dh
  62.         stosw
  63. @@:
  64.         loop    .loc_encode
  65. .loc_done:
  66.         ; Символ конца строки
  67.         mov     al,0
  68.         stosb
  69.  
  70.         pop     esi edi ecx eax
  71.         ret
  72. endp
При кодировании все символы без исключения переводятся в Quoted-Printable представление. Размер буфера для приема кодированной строки не проверяется и должен заранее определяться с тем расчетом, что каждый символ исходной строки преобразуется в три закодированных символа плюс запас для трехбайтных последовательностей мягкого переноса (если задано параметром кодирования) и нулевого символа окончания строки.

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

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

Quoted.Printable.Demo.zip (5,604 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (28.12.2015 в 21:25):
В функции декодирования добавил замену подчеркивания "_" на пробел, т.к. подобная замена используется в почтовых программах. Код прокомментирован, если такую замену делать не надо, то удалите его из исходника.

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

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

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