Программная реализация утилиты кодирования и декодирования формата BASE 64
ФЕДЕРАЛЬНОЕ Государственное
АВТОНОМНОЕ образовательное учреждение высшего профессионального образования
БЕЛГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ
НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ УНИВЕРСИТЕТ
(НИУ "БелГУ")
ФАКУЛЬТЕТ КОМПЬЮТЕРНЫХ НАУК И
ТЕЛЕКОММУНИКАЦИЙ
КАФЕДРА МАТЕМАТИЧЕСКОГО И
ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
ИНФОРМАЦИОННЫХ СИСТЕМ
Курсовая работа
Программная реализация ультилиты
кодирования и декодирования формата BASE 64
студента дневного отделения 2 курса группы 141103
Дихтяренко Александра Анатольевича
Научный руководитель:
доцент В.В. Румбешт
БЕЛГОРОД 2013
Содержание
Введение
1. Теоретическая часть
1.1 Что такое кодирования/декодирование формата BASE64, его
применение
1.2 Структура BASE64
2. Практическая часть
2.1 Алгоритм кодирования/декодирования
2.2 Реализация программы
2.3 Апробация приложения
Заключение
Список используемой литературы
Приложения
Введение
Необходимо разработать утилиту кодирования/декодирования
формата BASE64. Разработка ведется в программной среде Linux, используя компилятор gcc. Программа будет
писаться на языке С++.
Для того что бы выполнить поставленную задачу необходимо
составить план для изучения данной темы и ее реализации, а конкретно:
· Сбор и изучение материалов по теме
кодирования/декодирования формата BASE64;
· Разобраться с алгоритмом
кодирования/декодирования;
· Реализовать алгоритм, используя полученные
знания;
· Сделать вывод из проведенной работы
1.
Теоретическая часть
1.1 Что такое
кодирования/декодирование формата BASE64, его применение
Дело в том, что изначально для передачи электронной почты в
Интернет использовался только текст (RFC822). Затем, с развитием компьютерных
технологий, потребовалась возможность передачи нетекстовой информации: аудио,
видео, графических файлов, файлов приложений и т.д. Однако почтовые сервера
понимают только текст. Именно поэтому появилась необходимость каким-то образом
преобразовать двоичный файл в текстовый для этого и был придуман BASE64. Этот способ
используется в спецификации MIME.это стандарт описания заголовков e-mail
сообщений. Используя этот стандарт, в одном письме можно отправить сразу
несколько различных вложений. Например, можно положить в письмо архив, видео,
картинки или другие файлы. И все это отправить получателю. Почтовая
программа-получатель, понимающая MIME, достанет из сообщения все, что было
переданно.
Из этого можно сделать вывод, что Base64 - это схема кодирования
символьной строки любого набора байт в последовательность только печатных ASCII
символов.
утилита кодирование декодирование программный
Рисунок.1.1 ASCII символы
1.2 Структура
BASE64
Так как в BASE64 используется алфавит из 64 символов, то для
кодировки нам хватит вместо стандартных 8 байт шесть. При этом изменении, мы
можем кодировать любые цифры с помощью нашего алфавита.
Преобразование происходит по принципу:
Берутся три последовательных байта по восемь бит (всего 24
бита), и побитно делятся на четыре 6-ти битных байта (всего 24 бита). Замечу,
что используется только 6 битов, а 2 остаются "не использованными"
Схематично такое преобразование можно представить:
Рисунок. 1.2 Преобразование в 6 битный вариант
Так кодируется любая информация, но существует еще один
важный момент, дело в том, что не обязательно всегда будет 3 байта, именно по
этому отсутствующие байты заменяют символом "=”
2.
Практическая часть
2.1 Алгоритм
кодирования/декодирования
Кодирование Для начала взять 8-ой (старший) бит исходного
байта и поместить его в начало 6-ти битового байта. Затем на место 8-го бита
исходного байта поместить 7-й бит, а в 6-ти битовом байте первый бит (младший)
переместить на место 2-го бита. После такого перемещения освобождается первый
(младший) бит 6-ти битного числа. В него и поместим старший (бывший седьмой)
бит исходного байта. Затем еще раз пердвинем биты в обоих байтах, после чего
повторяем процедуру
Пример:
Рисунок 2.1 Пример
Рассмотрим шаг 1.
Для проверки установки старшего бита
исходного 8-ми битного байта наложим на него так называемую "маску".
Т.е. применим к нему побитовую операцию AND с числом 128 (10000000).
Рисунок 2.2 Наложение "маски-1"
Как видно из приведенной схемы, проверить установку старшего
бита совсем несложно. Если результатом операции получается число 128, значит
бит установлен, а если в результате получаем 0, значит старший бит не
установлен. Далее в зависимости от полученного результата применим к 6-ти
битовому байту битовую операцию OR с числом 1, которая в любом случае
применения устанавливает первый (младший) байт в 1.
Рисунок 2.3 Наложение "маски-2"
Здесь необходимо учитывать то, что перед применением
побитовой операции OR с числом 1 младший бит 6-ти битового байта всегда 0. В
случае для первых двух шагов потому, что мы сами обнуляем его при
инициализации, для последующих шагов, потому что применяем операцию SHR.
Шаг 2.
Сместим первый бит 6-ти битного байта на вторую позицию,
одновременно обнуляя его первый бит. Сместим седьмой байт 8-ми битного байта на
8-е (старшее) место.
Повторяем шаги 1 и 2 шесть раз для каждого бита 6-ти битного
байта. Одновременно необходимо следить за тем, что если мы обработали восемь
бит байта-источника, следует перейти к новому байту. И последнее - если
обработаны все три байта-источники, следует выйти из функции кодирования.
Декодирование
Декодирование ничем не отличается от кодирования. Делаем тоже
самое, только источник и приемник меняются местами. Все операции происходят в
обратном порядке: проверяем установку первого бита 6-ти битного байта (маску в
этом случае надо накладывать с числом 32 (0010000) и в зависимости от
результата устанавливаем (или не устанавливаем) младший байт 8-ми битного
байта. Затем делаем побитовый сдвиг влево.
После того как мы разобрали весь алгоритм, стоит
подготовиться к реализации программы, для этого изобразим блок схемы:
) Всего алгоритма целиком см. Рисунок.2.4 Блок-схема
№1 (Вся программа в целом)
2) Алгоритм кодирования см. Рисунок.2.5 Блок-схема
№2 (Кодирование)
) Алгоритм декодирования см. Рисунок.2.6 Блок-схема
№3 (Декодирование)
Рисунок 2.4 Блок-схема №1 (Вся программа в целом)
Рисунок 2.5 Блок-схема №2 (Кодирование)
Рисунок 2.6 Блок-схема №3 (Декодирование)
2.2
Реализация программы
Программа реализована таким образом, что состоит из 3 файлов:
kyrsov. cpp;
base64. h;
test. cpp.
Начнем по порядку:
kyrsov. cpp (Созданы функции кодирования/декодирования
текста)
Любая программа, написанная на языке программирования С++
прежде всего начинается с подключения заголовочных файлов, или, другими
словами, с директив препроцессора (include) Директива препроцессора -
это, иными словами, сообщение препроцессору. Нам потребуется всего четыре
библиотеки для работы нашей программы
Здесь мы используем директиву include, которая через
заголовочные файлы подключает к коду программы необходимые библиотеки.
Некоторые заголовочные файлы требуют расширения". h”, так как являются более
старыми и унаследовали такой стиль подключения от языка-основателя С.
В представленном в приложении к курсовой работе программном
коде, имеют место быть следующие строки:
Листинг 1.
#include "base64. h" // Написанный в ручную заголовочный
файл (описан класс string)
#include <iostream> // Стандартная директива потокового
ввода/вывода
Операции ввода/вывода выполняются с помощью классов istream
(потоковый ввод) и ostream (потоковый вывод). Третий класс, iostream, является
производным от них и поддерживает двунаправленный ввод/вывод. Для удобства в
библиотеке определены три стандартных объекта-потока:
· cin - объект класса
istream, соответствующий стандартному вводу. В общем случае он позволяет читать
данные с терминала пользователя;
· cout - объект класса
ostream, соответствующий стандартному выводу. В общем случае он позволяет
выводить данные на терминал пользователя;
· cerr - объект класса
ostream, соответствующий стандартному выводу для ошибок. В этот поток мы
направляем сообщения об ошибках программы.
Вывод осуществляется, как правило, с помощью перегруженного
оператора сдвига влево (<<), а ввод - с помощью оператора сдвига вправо
(>>):
Любая программа также должна содержать функции - основную
(обязательно) и дополнительные (опционально). В языке С++ содержится два типа
функций:
· Функции возвращающие значение;
· Функции, не возвращающие значений.
Для начала рассмотрим пример функции, которая не возвращает
значений./*имя функции*/ (/*параметры функции*/) // заголовок функции
Здесь код начинается с зарезервированного слова void - тип
данных, который не хранит какие-либо данные. Этот тип данных показывает, что
функция не возвращает никаких значений. void никак по-другому не используется и
нужен в программе только для того, чтобы компилятор мог определить тип функции.
После зарезервированного слова void пишется имя функции за которым ставятся две
круглые скобочки, открывающаяся и закрывающаяся. Если функция будет передавать
какие-то данные, то внутри круглых скобочек объявляются параметры функции,
которые отделяются друг от друга запятыми. Вся эта строка называется заголовком
функции, после которого в функции пишутся две фигурные скобочки - внутри
которых будет находится алгоритм, называемый телом функции.
Это был пример дополнительной функции, которая значений не
возвращает, так как тип ее данных - void.
Далее мы создаем две функции, для кодирования текста и для
декодирования текста: base64_encode и base64_decode соответственно.
Разберем их по отдельности.
Листинг 2.
{ret;i = 0;j = 0;char char_array_3 [3];char
char_array_4 [4];
……………}
Здесь мы описываем переменные.
Класс String
Строки - это объекты, которые представляют
Собой последовательности символов. Стандартный строка класс
обеспечивает поддержку таких объектов с интерфейсом, аналогичную стандартные
контейнеры однако добавление функции, специально предназначенные для работы со
строками символов.
В строка класс-это экземпляр basic_string шаблон класса,
который использует char как тип персонажа, его значение по умолчанию
char_traits и распределитель типов.
После этого действия, мы циклично модифицируем из 8 битного
вида в 6 битный вид нашу строку. Начиная с конца
Листнг 3.(in_len--) {_array_3 [i++] = *
(bytes_to_encode++);(i == 3) {_array_4 [0] = (char_array_3 [0] & 0xfc)
>> 2;_array_4 [1] = ( (char_array_3 [0] & 0x03) << 4) + (
(char_array_3 [1] & 0xf0) >> 4);_array_4 [2] = ( (char_array_3 [1]
& 0x0f) << 2) + ( (char_array_3 [2] & 0xc0) >> 6);_array_4
[3] = char_array_3 [2] & 0x3f;
………………………………}
<< - знак побитового смещения
& - знак побитового "и”
Как рассказано и показано в теории здесь специально
используется побитовое умножение для проверки установки старших битов с
последующим смещение.
Далее повторяется эта же операция, но при условии наличия еще
необработанных байтов.
И в конце если не хватает байтов, тоесть их меньше 3, то мы
просто заменяем в комбинации отсутствующие байты на знак "=" b дописываем в строку
результат.
Листинг 4( (i++ < 3))+= '=';
}
Вторая функия base64_decode, ведет и состоит аналогично
только что описанной, но с измененным порядком действий (в обратном) и
поменянными входом и выходом программы местами.
Теперь рассмотрим заголовочный файл base64. h
В нем описан класс стринг
Листинг 6
#include <string> // заголовочный файл подключающий возможности класса string
using namespace std; // подключаемое
пространство имен std
string base64_encode (unsigned char const*,
unsigned int len); // инициализация функции base64_encodebase64_decode (string const& s); // инициализация функции base64_encode
Теперь рассмотрим файл test. cpp (Файл в котором
задается). Так же как и в первом файле используются подключаемые модули:
Стандартная библиотека ввода/вывода <iostream> и заголовочный файл
"base64. h"
Т.к. в любой программе должна находиться главная функция main, то мы так же ее используем.
При создании нового консольного приложения в языке
программирования С++, автоматически создается таккая строка: int main (int argc, char* argv [])
Это - заголовок главной функции main (), в скобочках
которого объявлены параметры argс и argv. Так вот, если программу запускать
через командную строку, то существует возможность передать какую-либо
информацию этой программе через параметры argc и argv []. Первый имеет тип данных int,
и содержит количество параметров, передаваемых в функцию main. Причем argc
никогда не меньше 1, даже когда мы не передаем никакой информации, потому как
первым параметром считается имя функции. Второй параметр - это массив
указателей на строки. Через командную строку можно передать только данные
строкового типа и именно через параметр argv [] и передается какая-либо
информация.
Рисунок 3.1 Схема обьявлений функциив с++
Листинг 7
int main () {
const string s = "kot begit po doroge i myrchit"; // присваиваем
переменной s
текст который хотели бы закодировать.
string encoded = base64_encode
(reinterpret_cast<const unsigned char*> (s. c_str ()), s. length
());decoded = base64_decode (encoded);<< "encoded: " <<
encoded << endl;<< "decoded: " << decoded <<
endl;
return 0;
}
В этом коде мы присваиваем переменным string, то значение которое
получил функции из файла kyrsov. cpp, при этов в функции мы передаем аргументы
После этого воспользовавшись командой вывода cout. Показываем результат на
экран
И после возврщаем 0, командой return 0
Так же здесь присутствуют функции для работы с строковыми
данными
s. c_str ()
s. length ()
Свойство Length возвращает число объектов Char
<#"656317.files/image010.gif">
Скриншот №2 (Пример работы2)
Так как выполнялся запуск программы на операционной системе Linux, то и компилирование и
сборка происходит с помощью консоля.
1 команда. g++ - c kyrsov. cpp test. cpp
Команда благодаря ключу - с создает 2 отдельных объектных
файла, заголовочный файл base64. h,разместим в том же каталоге, что и другие файлы,
его мы подключили внутри программы.
2 команда. g++ kyrsov. o test. o - o result
Команда собирает вместе 2 объектных файла и создает файл
запуск для нашей программы.
команда. /result
Эта команда запускает нашу программу, после чего мы видим
результат на наших скриншотах
На апробации выяснилось, что программа рабочая, выводы верны,
декодирование и кодирование прошли успешно
Заключение
В ходе данной курсовой работы были изучены различные аспекты
языка программирования С++. Так же был разобран алгоритм кодирования
декодирования формата BASE64 и после чего реализован.
Апробация прошла успешно, скриншоты это подтверждают.
Для себя же, я улучшил свои знания и владения языком С++.
Конкретно, работа с классом типа string и функциями, разобрался в компиляции и сборке
программы состоящей из нескольких файлов. Научился создавать собственные
заголовочные файлы и включать их в программу.
Могу сделать окончательный вывод, данная курсовая работа
повысила мое знания и я лучше стал разбираться в программировании, так же
освоил алгоритм кодирования/декодирования формата BASE64.
Список
используемой литературы
1. Холзнер
С. Visual C++6: Учебный курс - СПб: Питер, 2001. - 576 с.
2. Андрей Александреску, Современное
проектирование на С++ - СПб.: Вильямс, 2002. - 335с.
. Брюс
Эккель, Философия С++ - К.: Питер, 2004, - 575с.
. Е.Л.
Романов, Практикум по программированию на С++. СПб: БВХ-Петербург, 2004. - 425
с.
. Страуструп
Б. Программирование: принципы и практика использования C++, исправленное
издание = Programming: Principles and Practice Using C++. - М.:
"Вильямс", 2011. - С.1248. - ISBN 978-5-8459-1705-8
6. <http://www.cppstudio.com/obuchenie_cpp>
. Р. Лафоре,
Объектно-ориентированное программирование в С++. К.: Питер, 2004, - 920с.
. <http://brucha.ru/category/spp/>
Приложения
Приложение 1.
Программная реализация ультилиты кодирования декодирования формата Base64
1) kyrsov. cpp
#include "base64. h"
#include <iostream>namespace std;
// Использование 64 ьитного алфавита base64const
string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// Проверка вводимых значенийinline bool
is_base64 (unsigned char c) {(isalnum (c) || (c == '+') || (c == '/'));
}
// Кодирум наш текстbase64_encode (unsigned char
const* bytes_to_encode, unsigned int in_len) {ret;i = 0;j = 0;char char_array_3
[3];char char_array_4 [4];
// Запускаем цикл в котором выбираем по 3 байта и
модифицируем их, как бы из 8 битного байта в 6 битный байт
while (in_len--) {_array_3 [i++] = *
(bytes_to_encode++);(i == 3) {_array_4 [0] = (char_array_3 [0] & 0xfc)
>> 2;_array_4 [1] = ( (char_array_3 [0] & 0x03) << 4) + (
(char_array_3 [1] & 0xf0) >> 4);_array_4 [2] = ( (char_array_3 [1]
& 0x0f) << 2) + ( (char_array_3 [2] & 0xc0) >> 6);_array_4
[3] = char_array_3 [2] & 0x3f;
// То что получилось запишем в переменную ret
for (i = 0; (i <4); i++)+= base64_chars
[char_array_4 [i]]; = 0;
}
}
// Продолжаем, если отправили не пустое сообщение
if (i)
{(j = i; j < 3; j++)
// лобавляем в конце ноль, что бы сделать сишную строку
char_array_3 [j] = '\0';_array_4 [0] =
(char_array_3 [0] & 0xfc) >> 2;_array_4 [1] = ( (char_array_3 [0]
& 0x03) << 4) + ( (char_array_3 [1] & 0xf0) >> 4);_array_4
[2] = ( (char_array_3 [1] & 0x0f) << 2) + ( (char_array_3 [2] &
0xc0) >> 6);_array_4 [3] = char_array_3 [2] & 0x3f;(j = 0; (j < i
+ 1); j++)+= base64_chars [char_array_4 [j]];
// Если байтов меньше 3, то вместо них записывается знак
"=", сколько отсутствует столько и "="
while ( (i++ < 3))+= '=';
}ret;
}base64_decode (string const& encoded_string)
{in_len = encoded_string. size ();i = 0;j = 0;in_ = 0;char char_array_4 [4],
char_array_3 [3]; ret;
// берем наш закодированную строку, идем обратном порядке и
смотрим наличи пустых байтов
while (in_len - && (encoded_string [in_]!
= '=') && is_base64 (encoded_string [in_])) {_array_4 [i++] =
encoded_string [in_]; in_++;
// аналогичные действия в обратном порядке
if (i ==4) {
for (i = 0; i <4; i++)_array_4 [i] =
base64_chars. find (char_array_4 [i]);_array_3 [0] = (char_array_4 [0] <<
2) + ( (char_array_4 [1] & 0x30) >> 4);_array_3 [1] = ( (char_array_4
[1] & 0xf) << 4) + ( (char_array_4 [2] & 0x3c) >>
2);_array_3 [2] = ( (char_array_4 [2] & 0x3) << 6) + char_array_4
[3];(i = 0; (i < 3); i++)+= char_array_3 [i];= 0;
}
}(i) {(j = i; j <4; j++)_array_4 [j] = 0;(j =
0; j <4; j++)_array_4 [j] = base64_chars. find (char_array_4 [j]);_array_3
[0] = (char_array_4 [0] << 2) + ( (char_array_4 [1] & 0x30) >>
4);_array_3 [1] = ( (char_array_4 [1] & 0xf) << 4) + ( (char_array_4
[2] & 0x3c) >> 2);_array_3 [2] = ( (char_array_4 [2] & 0x3)
<< 6) + char_array_4 [3];(j = 0; (j < i - 1); j++) ret += char_array_3
[j];
}ret;
}
2) base64. h
#include <string>namespace
std;base64_encode (unsigned char const*, unsigned int len);base64_decode
(string const& s);
) test. cpp
#include "base64. h"
#include <iostream>namespace std;main ()
{string s = "kot begit po doroge i myrchit";encoded = base64_encode
(reinterpret_cast<const unsigned char*> (s. c_str ()), s. length
());decoded = base64_decode (encoded);<< "encoded: " <<
encoded << endl;<< "decoded: " << decoded <<
endl; 0;
}
Программная реализация утилиты кодирования декодирования
формата Base64