Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

7 семестр / Готовые отчеты / ММиВА. Лабораторная работа 3

.pdf
Скачиваний:
20
Добавлен:
23.12.2021
Размер:
452.93 Кб
Скачать

МИНИСТЕРСТВО ЦИФРОВОГО РАЗВИТИЯ,

СВЯЗИ И МАССОВЫХ КОММУНИКАЦИЙ РОССИЙСКОЙ ФЕДЕРАЦИИ Федеральное государственное бюджетное образовательное учреждение высшего образования «Санкт-Петербургский государственный университет телекоммуникаций им. проф. М. А. Бонч-Бруевича»

(СПбГУТ)

Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники

ЛАБОРАТОРНАЯ РАБОТА №3

по дисциплине «Математические методы и вычислительные алгоритмы современных систем связи»

студент гр. ИКПИ-84

_______________

Коваленко Л. А.

преподаватель каф. ПИиВТ

_______________

к.п.н., доцент Коробов С. А.

Санкт-Петербург

2021

ЦЕЛЬ РАБОТЫ

Изучение алгоритма кодирования/декодирования base64.

ПОСТАНОВКА ЗАДАЧИ

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

ХОД РАБОТЫ

Реализация кодировщика base64 на языке C приведена в таблице 1.

Таблица 1. Реализация кодировщика base64 на языке C

base64encode.c

// base64encode.c

#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h>

#define BYTES_TO_READ 9999 // Размер буфера чтения (9999 mod 3 = 0)

// Функция возвращает процессорное время процесса в секундах

double get_proc_time(void) { return (double)clock() / CLOCKS_PER_SEC; }

int main(int argc, const char *argv[])

{

//Если нужно измерить время работы, третий аргумент должен быть -t:

//./base64encode <filename> -t

int time_flag = 0;

//Первый аргумент: имя исполняемого файла

//Второй аргумент: имя файла с содержимым для кодирования base64

if (!(argc == 2 || (argc == 3 && (time_flag = strncmp(argv[2], "-t", 2) == 0))))

{

printf("%s <filename>\n", argv[0]); return 1;

}

// Если файл не существует

if (access(argv[1], F_OK) != 0)

{

printf("The file \"%s\" does not exist\n", argv[1]); return 2;

}

//Если файл нельзя открыть на чтение if (access(argv[1], R_OK) != 0)

{

printf("Insufficient permission to read the file \"%s\"\n", argv[1]); return 3;

}

//Попытка открытия файла

const char *filename = argv[1]; FILE *fp = fopen(filename, "rb"); if (!fp)

{

printf("File open error\n"); return 4;

}

//Кодирование алгоритмом base64

//1. Считываются максимум BYTES_TO_READ символов (BYTES_TO_READ % 3 == 0).

//2. Считанные символы кодируются.

//3. Результат кодирования выводится в поток stdout.

//4. Цикл продолжается до тех пор, пока не будут считаны все байты в файле.

2

char base64_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char input[BYTES_TO_READ], output[BYTES_TO_READ * 4 / 3 + 4];

size_t bytes_readed = 0; double start = get_proc_time();

while ((bytes_readed = fread(input, 1, BYTES_TO_READ, fp)) != 0)

{

size_t i = 0, t = 0, last = bytes_readed % 3, without_last = bytes_readed - last; while (i < without_last)

{

char first_byte = input[i++]; char second_byte = input[i++]; char third_byte = input[i++];

output[t++] = base64_map[first_byte >> 2];

output[t++] = base64_map[((first_byte << 4) | (second_byte >> 4)) & 63]; output[t++] = base64_map[((second_byte << 2) | (third_byte >> 6)) & 63]; output[t++] = base64_map[third_byte & 63];

}

if (last > 0)

{

char first_byte = input[i++];

output[t++] = base64_map[first_byte >> 2]; if (last == 1)

{

output[t++] = base64_map[(first_byte << 4) & 63]; output[t++] = '=';

}

else

{

char second_byte = input[i++];

output[t++] = base64_map[((first_byte << 4) | (second_byte >> 4)) & 63]; output[t++] = base64_map[(second_byte << 2) & 63];

}

output[t++] = '=';

}

output[t] = '\0'; if (!time_flag)

printf("%s", output);

}

double stop = get_proc_time(); if (time_flag)

printf("Time: %lf seconds\n", stop - start); return 0;

}

Реализация декодировщика base64 на языке C приведена в таблице 2.

Таблица 2. Реализация декодировщика base64 на языке C

base64decode.c

// base64decode.c

#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h>

#define BYTES_TO_READ 10000 // Размер буфера чтения (10000 mod 4 = 0)

// Функция возвращает процессорное время процесса в секундах

double get_proc_time(void) { return (double)clock() / CLOCKS_PER_SEC; }

int main(int argc, const char *argv[])

{

//Если нужно измерить время работы, третий аргумент должен быть -t:

//./base64decode <filename> -t

int time_flag = 0;

//Первый аргумент: имя исполняемого файла

//Второй аргумент: имя файла с содержимым для декодирования base64

if (!(argc == 2 || (argc == 3 && (time_flag = strncmp(argv[2], "-t", 2) == 0))))

{

printf("%s <filename>\n", argv[0]);

3

return 1;

}

// Если файл не существует

if (access(argv[1], F_OK) != 0)

{

printf("The file \"%s\" does not exist\n", argv[1]); return 2;

}

//Если файл нельзя открыть на чтение if (access(argv[1], R_OK) != 0)

{

printf("Insufficient permission to read the file \"%s\"\n", argv[1]); return 3;

}

//Попытка открытия файла

const char *filename = argv[1]; FILE *fp = fopen(filename, "rb"); if (!fp)

{

printf("File open error\n"); return 4;

}

//Декодирование алгоритмом base64

//1. Считываются максимум BYTES_TO_READ символов (BYTES_TO_READ % 4 == 0).

//2. Считанные символы декодируются.

//3. Результат декодирования выводится в поток stdout.

//4. Цикл продолжается до тех пор, пока не будут считаны все байты в файле.

char base64_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; char input[BYTES_TO_READ], output[BYTES_TO_READ * 3 / 4 + 1], four_bytes[4];

size_t bytes_readed = 0, map_size = sizeof(base64_map) / sizeof(base64_map[0]); double start = get_proc_time();

while ((bytes_readed = fread(input, 1, BYTES_TO_READ, fp)) != 0)

{

size_t i = 0, t = 0; while (i < bytes_readed)

{

for (size_t j = 0; i < bytes_readed && j < 4; ++j)

{

four_bytes[j] = input[i++];

char *pos = (char *)memchr(base64_map, four_bytes[j], map_size); if (pos != NULL)

four_bytes[j] = (char)(pos - base64_map);

else

{

printf("Error. Unknown symbol \"%c\".", four_bytes[j]); return 5;

}

}

output[t++] = (char)((four_bytes[0] << 2) | (four_bytes[1] >> 4)); if (four_bytes[2] != 64 /* '=' игнорируется */)

output[t++] = (char)((four_bytes[1] << 4) | (four_bytes[2] >> 2)); if (four_bytes[3] != 64 /* '=' игнорируется */)

output[t++] = (char)((four_bytes[2] << 6) | four_bytes[3]);

}

output[t] = '\0'; if (!time_flag)

printf("%s", output);

}

double stop = get_proc_time(); if (time_flag)

printf("Time: %lf seconds\n", stop - start); return 0;

}

4

Сборочный файл представлен в таблице 3.

Таблица 3. Сборочный файл

Makefile

.PHONY : clean CC = gcc

CFLAGS = -O0 -std=c11 -Wall -Waddress -Wextra -Werror \ -Wpedantic -Wfloat-equal -Waggregate-return \ -old-style-cast -Wshadow -Wundef -Wpointer-arith \ -Wcast-align -Wcast-qual -fsanitize=address \ -Wstrict-prototypes -Wstrict-overflow=5 \ -Wwrite-strings -Wformat=2 -pedantic-errors \ -Wswitch-default -Wswitch-enum -Wconversion \ -Wunreachable-code -Wredundant-decls -Wenum-compare \ -Wduplicated-branches -Wduplicated-cond -Wlogical-op \ -Wsign-conversion

SOURCES = base64encode.c base64decode.c EXECUTABLES = $(SOURCES:.c=)

all: $(SOURCES) $(EXECUTABLES)

.c:

$(CC) $(CFLAGS) $? -o $(?:.c=)

clean:

rm -rf $(EXECUTABLES)

Все используемые в программах заголовочные файлы и функции входят в стандарт POSIX.

Используемый далее в примерах кодирования/декодирования файл file.txt был сгенерирован Python-скриптом, который представлен в табл. 4.

Таблица 4. Python-скрипт генерации файла

file_gen.py

import string, random

s = string.ascii_letters + string.digits + '\n'

with open('file.txt', 'w') as fp: fp.write(''.join(random.choices(s, k=100_000_000)))

Сгенерированный файл состоит из 100.000.000 ascii-символов

(аналогично — байт) латинских букв, цифр и знака перевода строки.

MD5-файла: 6dbf3c3c73fd6a1826d139a053417fda.

Работа программ и их аналога в Linux «base64» представлена на рис. 1.

5

Рисунок 1. Работа программ и их аналога в Linux «base64»

1. base64encode использует первый аргумент в качестве имени файла

(file.txt). Кодирует содержимое файла и выводит результат в файл

out.txt.

2.Встроенная в Linux утилита base64 кодирует содержимое файла и выводит результат в файл out2.txt.

3.Контрольные суммы MD5 файлов out.txt и out2.txt совпадают.

4.base64decode использует первый аргумент в качестве имени файла

(out.txt). Декодирует содержимое файла и выводит результат в файл

decoded.txt.

5.Встроенная в Linux утилита base64 декодирует содержимое файла и выводит результат в файл decoded2.txt.

6.Контрольные суммы MD5 файлов file.txt, decoded.txt и

decoded2.txt совпадают.

7.Флаг -t после имени файла позволяет узнать, сколько времени потребовалось программе на кодирование/декодирование данных.

6

Ответы на контрольные вопросы приведены в таблице 5.

Таблица 5. Ответы на контрольные вопросы

Декодированный текст

Кодированный текст

Xz25

WHoyNQ==

01010111 01001000 01101111 01111001

01011000 01111010 00110010 00110101

01001110 01010001 00111101 00111101

 

Fh7k

Rmg3aw==

01010010 01101101 01100111 00110011

01000110 01101000 00110111 01101011

01100001 01110111 00111101 00111101

 

gRn4

Z1JuNA==

01011010 00110001 01001010 01110101

01100111 01010010 01101110 00110100

01001110 01000001 00111101 00111101

 

>Юx

Pt54

00111110 11011110 01111000

01010000 01110100 00110101 00110100

F=/

Rj0v

01000110 00111101 00101111

01010010 01101010 00110000 01110110

ʹ?

zbTM

11001101 10110100 11001100

01111010 01100010 01010100 01001101

ЗАКЛЮЧЕНИЕ

В результате выполнения лабораторной работы мы разработали два приложения для кодирования/декодирования алгоритмом base64 содержимого произвольного файла.

7