#include #include #include #include #define WINDOW_SIZE 4096 #define LOOKAHEAD_BUFFER_SIZE 18 typedef struct { uint16_t offset; uint8_t length; uint8_t next_char; } LZ77Triple; int lz77_compress(const char *input_filename, const char *output_filename) { // Open the input file in binary read mode FILE *input_file = fopen(input_filename, "rb"); if (!input_file) { perror("Error opening input file"); return -1; } // Open the output file in binary write mode FILE *output_file = fopen(output_filename, "wb"); if (!output_file) { perror("Error opening output file"); fclose(input_file); return -2; } uint8_t *window = (uint8_t *)malloc(WINDOW_SIZE + LOOKAHEAD_BUFFER_SIZE); if (!window) { perror("Memory allocation failed"); fclose(input_file); fclose(output_file); return -3; } size_t window_start = 0; size_t lookahead_start = 0; size_t bytes_read; // Initialize the window with data from the input file bytes_read = fread(window + WINDOW_SIZE, 1, LOOKAHEAD_BUFFER_SIZE, input_file); while (bytes_read > 0) { size_t best_match_offset = 0; size_t best_match_length = 0; // Search for the best match within the sliding window for (size_t i = window_start; i < WINDOW_SIZE + lookahead_start; i++) { size_t match_length = 0; while (match_length < bytes_read && window[i + match_length] == window[WINDOW_SIZE + match_length]) { match_length++; if (match_length >= LOOKAHEAD_BUFFER_SIZE) { break; } } if (match_length > best_match_length) { best_match_length = match_length; best_match_offset = WINDOW_SIZE + lookahead_start - i; } } // Create a triple and write it to the output file LZ77Triple triple; triple.offset = (uint16_t)best_match_offset; triple.length = (uint8_t)best_match_length; triple.next_char = window[WINDOW_SIZE + best_match_length]; // Write the triple to the output file fwrite(&triple, sizeof(LZ77Triple), 1, output_file); // Slide the window window_start = (window_start + best_match_length + 1) % WINDOW_SIZE; lookahead_start = (lookahead_start + best_match_length + 1) % LOOKAHEAD_BUFFER_SIZE; // Read new byte into the lookahead buffer bytes_read = fread(window + WINDOW_SIZE, 1, LOOKAHEAD_BUFFER_SIZE - lookahead_start, input_file); } // Cleanup and close files fclose(input_file); fclose(output_file); free(window); return 0; } int lz77_decompress(const char *input_filename, const char *output_filename) { FILE *input = fopen(input_filename, "rb"); FILE *output = fopen(output_filename, "wb"); if (!input || !output) { if (input) fclose(input); if (output) fclose(output); return -1; // Помилка відкриття файлу } size_t buffer_size = 4096; // Максимальний розмір вікна unsigned char *window = malloc(buffer_size); size_t window_size = 0; // Розмір заповненої частини вікна size_t window_pos = 0; // Поточна позиція в межах вікна if (!window) { fclose(input); fclose(output); return -1; // Помилка пам'яті } while (!feof(input)) { unsigned char flag; if (fread(&flag, 1, 1, input) != 1) break; for (int i = 0; i < 8 && !feof(input); i++) { if (flag & (1 << i)) { // Літеральний символ unsigned char literal; if (fread(&literal, 1, 1, input) != 1) break; fputc(literal, output); // Додати символ у вікно window[window_pos] = literal; window_pos = (window_pos + 1) % buffer_size; if (window_size < buffer_size) window_size++; } else { // Посилання unsigned short offset_length; if (fread(&offset_length, 2, 1, input) != 1) break; size_t offset = offset_length >> 4; size_t length = (offset_length & 0xF) + 3; for (size_t j = 0; j < length; j++) { unsigned char byte = window[(window_pos - offset + buffer_size) % buffer_size]; fputc(byte, output); // Додати байт у вікно window[window_pos] = byte; window_pos = (window_pos + 1) % buffer_size; if (window_size < buffer_size) window_size++; } } } } free(window); fclose(input); fclose(output); return 0; // Успішна декомпресія } void rle_compress(const char *input_filename, const char *output_filename) { FILE *input_file = fopen(input_filename, "rb"); if (!input_file) { perror("Error opening input file"); return; } FILE *output_file = fopen(output_filename, "wb"); if (!output_file) { perror("Error opening output file"); fclose(input_file); return; } uint8_t current_byte, previous_byte; uint8_t count = 1; if (fread(&previous_byte, 1, 1, input_file) != 1) { printf("Input file is empty or read error occurred.\n"); fclose(input_file); fclose(output_file); return; } while (fread(¤t_byte, 1, 1, input_file) == 1) { if (current_byte == previous_byte && count < 255) { count++; } else { fwrite(&previous_byte, 1, 1, output_file); fwrite(&count, 1, 1, output_file); printf("Writing byte: %c with count: %d\n", previous_byte, count); previous_byte = current_byte; count = 1; } } fwrite(&previous_byte, 1, 1, output_file); fwrite(&count, 1, 1, output_file); printf("Writing byte: %c with count: %d\n", previous_byte, count); fclose(input_file); fclose(output_file); } int rle_decompress(const char *input_filename, const char *output_filename) { // Open the input file in binary read mode FILE *input_file = fopen(input_filename, "rb"); if (!input_file) { perror("Error opening input file"); return -1; } // Open the output file in binary write mode FILE *output_file = fopen(output_filename, "wb"); if (!output_file) { perror("Error opening output file"); fclose(input_file); return -2; } uint8_t byte; uint8_t count; size_t decompressed_size = 0; // Read [byte, count] pairs from the input file while (fread(&byte, 1, 1, input_file) == 1) { if (fread(&count, 1, 1, input_file) != 1) { // Handle malformed input file fprintf(stderr, "Error: Malformed input file\n"); fclose(input_file); fclose(output_file); return -3; } // Write 'count' occurrences of 'byte' to the output file for (uint8_t i = 0; i < count; i++) { if (fwrite(&byte, 1, 1, output_file) != 1) { perror("Error writing to output file"); fclose(input_file); fclose(output_file); return -4; } decompressed_size++; } } // Clean up and close files fclose(input_file); fclose(output_file); return (int)decompressed_size; }