Программная реализация утилиты кодирования и декодирования формата BASE 64
Как видно из приведенной схемы, проверить установку старшего бита совсем несложно. Если результатом операции получается число 128, значит бит установлен, а если в результате получаем 0, значит старший бит не установлен. Далее в зависимости от полученного результата применим к 6-ти битовому байту битовую операцию OR с числом 1, которая в любом случае применения устанавливает первый (младший) байт… Читать ещё >
Программная реализация утилиты кодирования и декодирования формата BASE 64 (реферат, курсовая, диплом, контрольная)
ФЕДЕРАЛЬНОЕ Государственное АВТОНОМНОЕ образовательное учреждение высшего профессионального образования
БЕЛГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ УНИВЕРСИТЕТ
(НИУ «БелГУ»)
ФАКУЛЬТЕТ КОМПЬЮТЕРНЫХ НАУК И ТЕЛЕКОММУНИКАЦИЙ КАФЕДРА МАТЕМАТИЧЕСКОГО И ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИНФОРМАЦИОННЫХ СИСТЕМ
Курсовая работа
Программная реализация ультилиты кодирования и декодирования формата BASE 64
студента дневного отделения 2 курса группы 141 103
Дихтяренко Александра Анатольевича
Научный руководитель:
доцент В.В. Румбешт
БЕЛГОРОД 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.
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 (10 000 000).
Рисунок 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 (10 000) и в зависимости от результата устанавливаем (или не устанавливаем) младший байт 8-ми битного байта. Затем делаем побитовый сдвиг влево.
После того как мы разобрали весь алгоритм, стоит подготовиться к реализации программы, для этого изобразим блок схемы:
1) Всего алгоритма целиком см. Рисунок.2.4 Блок-схема № 1 (Вся программа в целом)
2) Алгоритм кодирования см. Рисунок.2.5 Блок-схема № 2 (Кодирование)
3) Алгоритм декодирования см. Рисунок.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 // Стандартная директива потокового ввода/вывода
Операции ввода/вывода выполняются с помощью классов istream (потоковый ввод) и ostream (потоковый вывод). Третий класс, iostream, является производным от них и поддерживает двунаправленный ввод/вывод. Для удобства в библиотеке определены три стандартных объекта-потока:
· cin — объект класса istream, соответствующий стандартному вводу. В общем случае он позволяет читать данные с терминала пользователя;
· cout — объект класса ostream, соответствующий стандартному выводу. В общем случае он позволяет выводить данные на терминал пользователя;
· cerr — объект класса ostream, соответствующий стандартному выводу для ошибок. В этот поток мы направляем сообщения об ошибках программы.
Вывод осуществляется, как правило, с помощью перегруженного оператора сдвига влево (<<), а ввод — с помощью оператора сдвига вправо (>>):
Любая программа также должна содержать функции — основную (обязательно) и дополнительные (опционально). В языке С++ содержится два типа функций:
· Функции возвращающие значение;
· Функции, не возвращающие значений.
Для начала рассмотрим пример функции, которая не возвращает значений.
void /*имя функции*/ (/*параметры функции*/) // заголовок функции
Здесь код начинается с зарезервированного слова void — тип данных, который не хранит какие-либо данные. Этот тип данных показывает, что функция не возвращает никаких значений. void никак по-другому не используется и нужен в программе только для того, чтобы компилятор мог определить тип функции. После зарезервированного слова void пишется имя функции за которым ставятся две круглые скобочки, открывающаяся и закрывающаяся. Если функция будет передавать какие-то данные, то внутри круглых скобочек объявляются параметры функции, которые отделяются друг от друга запятыми. Вся эта строка называется заголовком функции, после которого в функции пишутся две фигурные скобочки — внутри которых будет находится алгоритм, называемый телом функции.
Это был пример дополнительной функции, которая значений не возвращает, так как тип ее данных — void.
Далее мы создаем две функции, для кодирования текста и для декодирования текста: base64_encode и base64_decode соответственно.
Разберем их по отдельности.
Листинг 2.
{
string ret;
int i = 0;
int j = 0;
unsigned char char_array3 [3];
unsigned char char_array4 [4];
…}
Здесь мы описываем переменные.
Класс String
Строки — это объекты, которые представляют
Собой последовательности символов. Стандартный строка класс обеспечивает поддержку таких объектов с интерфейсом, аналогичную стандартные контейнеры однако добавление функции, специально предназначенные для работы со строками символов.
В строка класс-это экземпляр basic_string шаблон класса, который использует char как тип персонажа, его значение по умолчанию char_traits и распределитель типов.
После этого действия, мы циклично модифицируем из 8 битного вида в 6 битный вид нашу строку. Начиная с конца
Листнг 3.
while (in_len—) {
char_array3 [i++] = * (bytes_to_encode++);
if (i == 3) {
char_array4 = (char_array3 & 0xfc) >> 2;
char_array4 = ((char_array3 & 0×03) << 4) + ((char_array3 & 0xf0) >> 4);
char_array4 = ((char_array3 & 0x0f) << 2) + ((char_array3 & 0xc0) >> 6);
char_array4 = char_array3 & 0x3f;
…}
<< - знак побитового смещения
& - знак побитового «и»
Как рассказано и показано в теории здесь специально используется побитовое умножение для проверки установки старших битов с последующим смещение.
Далее повторяется эта же операция, но при условии наличия еще необработанных байтов.
И в конце если не хватает байтов, тоесть их меньше 3, то мы просто заменяем в комбинации отсутствующие байты на знак «=» b дописываем в строку результат.
Листинг 4
while ((i++ < 3))
ret += '=';
}
Вторая функия base64_decode, ведет и состоит аналогично только что описанной, но с измененным порядком действий (в обратном) и поменянными входом и выходом программы местами.
Теперь рассмотрим заголовочный файл base64. h
В нем описан класс стринг
Листинг 6
#include // заголовочный файл подключающий возможности класса string
using namespace std; // подключаемое пространство имен std
string base64_encode (unsigned char const*, unsigned int len); // инициализация функции base64_encode
string base64_decode (string const& s); // инициализация функции base64_encode
Теперь рассмотрим файл test. cpp (Файл в котором задается). Так же как и в первом файле используются подключаемые модули:
Стандартная библиотека ввода/вывода и заголовочный файл «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 (s. c_str ()), s. length ());
string decoded = base64_decode (encoded);
cout << «encoded: «<< encoded << endl;
cout << «decoded: «<< decoded << endl;
return 0;
}
В этом коде мы присваиваем переменным string, то значение которое получил функции из файла kyrsov. cpp, при этов в функции мы передаем аргументы
После этого воспользовавшись командой вывода cout. Показываем результат на экран
И после возврщаем 0, командой return 0
Так же здесь присутствуют функции для работы с строковыми данными
s. c_str ()
Возвращает указатель на массив, который содержит null-terminated последовательность символов (т.е., C-string), представляющий текущее значение строка объекта. Этот массив включает в себя одну и ту же последовательность символов, составляющих стоимость строка объект плюс дополнительный завершающий null-символ ('') в конце.
s. length ()
Свойство Length возвращает число объектов Char в данном экземпляре, а не число знаков Юникода. Причина в том, что знак Юникода может быть представлен несколькими Char. Для работы с каждым знаком Юникода используйте класс System. Globalization: StringInfo вместо класса Char.
В некоторых языках, таких как C и C++, знак null указывает на конец строки. На платформе.net Framework знак null может быть внедрен в строку. Когда строка включает один или более знаков null, они могут находиться в любом месте строки. Например, в следующей строке подстроки" abc" и «def» разделены знаком null. Свойство Length возвращает значение 7, показывающее, что строка содержит шесть знаков алфавита и знак null.
2.3 Апробация приложения
В данном разделе находятся тестовые данные и отчет о работе приложения.
Скриншот № 1 (Пример работы1)
Скриншот № 2 (Пример работы2)
Так как выполнялся запуск программы на операционной системе Linux, то и компилирование и сборка происходит с помощью консоля.
1 команда. g++ - c kyrsov. cpp test. cpp
Команда благодаря ключу — с создает 2 отдельных объектных файла, заголовочный файл base64. h, разместим в том же каталоге, что и другие файлы, его мы подключили внутри программы.
2 команда. g++ kyrsov. o test. o — o result
Команда собирает вместе 2 объектных файла и создает файл запуск для нашей программы.
3 команда. /result
Эта команда запускает нашу программу, после чего мы видим результат на наших скриншотах
На апробации выяснилось, что программа рабочая, выводы верны, декодирование и кодирование прошли успешно
Заключение
В ходе данной курсовой работы были изучены различные аспекты языка программирования С++. Так же был разобран алгоритм кодирования декодирования формата BASE64 и после чего реализован.
Апробация прошла успешно, скриншоты это подтверждают.
Для себя же, я улучшил свои знания и владения языком С++. Конкретно, работа с классом типа string и функциями, разобрался в компиляции и сборке программы состоящей из нескольких файлов. Научился создавать собственные заголовочные файлы и включать их в программу.
Могу сделать окончательный вывод, данная курсовая работа повысила мое знания и я лучше стал разбираться в программировании, так же освоил алгоритм кодирования/декодирования формата BASE64.
Список используемой литературы
1. Холзнер С. Visual C++6: Учебный курс — СПб: Питер, 2001. — 576 с.
2. Андрей Александреску, Современное проектирование на С++ - СПб.: Вильямс, 2002. — 335с.
3. Брюс Эккель, Философия С++ - К.: Питер, 2004, — 575с.
4. Е. Л. Романов, Практикум по программированию на С++. СПб: БВХ-Петербург, 2004. — 425 с.
5. Страуструп Б. Программирование: принципы и практика использования C++, исправленное издание = Programming: Principles and Practice Using C++. — М.: «Вильямс», 2011. — С.1248. — ISBN 978−5-8459−1705−8
6. http://www.cppstudio.com/obuchenie_cpp
7. Р. Лафоре, Объектно-ориентированное программирование в С++. К.: Питер, 2004, — 920с.
8. http://brucha.ru/category/spp/
Приложения
Приложение 1. Программная реализация ультилиты кодирования декодирования формата Base64
1) kyrsov. cpp
#include «base64. h»
#include
using namespace std;
// Использование 64 ьитного алфавита base64
static const string base64_chars = «ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/» ;
// Проверка вводимых значений
static inline bool is_base64 (unsigned char c)
return (isalnum (c)
// Кодирум наш текст
string base64_encode (unsigned char const* bytes_to_encode, unsigned int in_len) {
string ret;
int i = 0;
int j = 0;
unsigned char char_array3 [3];
unsigned char char_array4 [4];
// Запускаем цикл в котором выбираем по 3 байта и модифицируем их, как бы из 8 битного байта в 6 битный байт
while (in_len—) {
char_array3 [i++] = * (bytes_to_encode++);
if (i == 3) {
char_array4 = (char_array3 & 0xfc) >> 2;
char_array4 = ((char_array3 & 0×03) << 4) + ((char_array3 & 0xf0) >> 4);
char_array4 = ((char_array3 & 0x0f) << 2) + ((char_array3 & 0xc0) >> 6);
char_array4 = char_array3 & 0x3f;
// То что получилось запишем в переменную ret
for (i = 0; (i <4); i++)
ret += base64_chars [char_array4 [i]];
i = 0;
}
}
// Продолжаем, если отправили не пустое сообщение
if (i)
{
for (j = i; j < 3; j++)
// лобавляем в конце ноль, что бы сделать сишную строку
char_array3 [j] = '';
char_array4 = (char_array3 & 0xfc) >> 2;
char_array4 = ((char_array3 & 0×03) << 4) + ((char_array3 & 0xf0) >> 4);
char_array4 = ((char_array3 & 0x0f) << 2) + ((char_array3 & 0xc0) >> 6);
char_array4 = char_array3 & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars [char_array4 [j]];
// Если байтов меньше 3, то вместо них записывается знак «=», сколько отсутствует столько и «=»
while ((i++ < 3))
ret += '=';
}
return ret;
}
string base64_decode (string const& encoded_string) {
int in_len = encoded_string. size ();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array4 [4], char_array3 [3];
string ret;
// берем наш закодированную строку, идем обратном порядке и смотрим наличи пустых байтов
while (in_len — && (encoded_string [in_]! = '=') && is_base64 (encoded_string [in_])) {
char_array4 [i++] = encoded_string [in_]; in_++;
// аналогичные действия в обратном порядке
if (i ==4) {
for (i = 0; i <4; i++)
char_array4 [i] = base64_chars. find (char_array4 [i]);
char_array3 = (char_array4 << 2) + ((char_array4 & 0×30) >> 4);
char_array3 = ((char_array4 & 0xf) << 4) + ((char_array4 & 0x3c) >> 2);
char_array3 = ((char_array4 & 0×3) << 6) + char_array4 [3];
for (i = 0; (i < 3); i++)
ret += char_array3 [i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array4 [j] = 0;
for (j = 0; j <4; j++)
char_array4 [j] = base64_chars. find (char_array4 [j]);
char_array3 = (char_array4 << 2) + ((char_array4 & 0×30) >> 4);
char_array3 = ((char_array4 & 0xf) << 4) + ((char_array4 & 0x3c) >> 2);
char_array3 = ((char_array4 & 0×3) << 6) + char_array4 [3];
for (j = 0; (j < i — 1); j++) ret += char_array3 [j];
}
return ret;
}
2) base64. h
#include
using namespace std;
string base64_encode (unsigned char const*, unsigned int len);
string base64_decode (string const& s);
3) test. cpp
#include «base64. h»
#include
using namespace std;
int main () {
const string s = «kot begit po doroge i myrchit» ;
string encoded = base64_encode (reinterpret_cast (s. c_str ()), s. length ());
string decoded = base64_decode (encoded);
cout << «encoded: «<< encoded << endl;
cout << «decoded: «<< decoded << endl;
return 0;
}
Программная реализация утилиты кодирования декодирования формата Base64