├── test ├── x0 ├── 2x6f ├── 4a ├── x6f ├── abcde ├── foobar ├── abc ├── xall ├── bar ├── 128rand ├── 129x6f ├── 130rand ├── lorem └── z ├── Makefile ├── .gitignore ├── LICENSE ├── inc └── rle.h ├── src ├── rle.c └── main.c └── README.md /test/x0: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/2x6f: -------------------------------------------------------------------------------- 1 | oo -------------------------------------------------------------------------------- /test/4a: -------------------------------------------------------------------------------- 1 | AAAA -------------------------------------------------------------------------------- /test/x6f: -------------------------------------------------------------------------------- 1 | o -------------------------------------------------------------------------------- /test/abcde: -------------------------------------------------------------------------------- 1 | ABCDE -------------------------------------------------------------------------------- /test/foobar: -------------------------------------------------------------------------------- 1 | foobar -------------------------------------------------------------------------------- /test/abc: -------------------------------------------------------------------------------- 1 | ABAAACBBBBCCCCCCAAABABCCBCA -------------------------------------------------------------------------------- /test/xall: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChuOkupai/rle-compression/HEAD/test/xall -------------------------------------------------------------------------------- /test/bar: -------------------------------------------------------------------------------- 1 | bar 2 | bbar 3 | bbaar 4 | bbaarr 5 | bbbaarr 6 | bbbaaarr 7 | bbbaaarrr 8 | bbbbaaarrr 9 | bbbbaaaarrr 10 | bbbbaaaarrrr -------------------------------------------------------------------------------- /test/128rand: -------------------------------------------------------------------------------- 1 | 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567 -------------------------------------------------------------------------------- /test/129x6f: -------------------------------------------------------------------------------- 1 | ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooxyz -------------------------------------------------------------------------------- /test/130rand: -------------------------------------------------------------------------------- 1 | 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | CFLAGS := -Wall -Wextra -Werror -Ofast 3 | SRC := $(wildcard src/*.c) 4 | OBJ := $(SRC:%.c=%.o) 5 | BIN := rle 6 | BIN_PATH := /usr/local/bin 7 | 8 | $(BIN): $(OBJ) 9 | $(CC) $(CFLAGS) -I./inc $(OBJ) -o $@ 10 | 11 | clean: 12 | rm -f $(OBJ) $(BIN) 13 | 14 | install: $(BIN) 15 | install rle $(BIN_PATH) 16 | 17 | re: clean $(BIN) 18 | 19 | uninstall: 20 | rm -f $(BIN_PATH)/$(BIN) 21 | 22 | src/%.o: src/%.c inc/rle.h 23 | $(CC) $(CFLAGS) -I./inc -c $< -o $@ 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Adrien Soursou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/lorem: -------------------------------------------------------------------------------- 1 | 2 | 3 | __ _ __ __ _ __ __ __ __ ___ _ _ ___ __ 4 | / / ____ ________ ____ ___ (_)___ _______ ______ ___ ____/ /___ / /___ _____ _____(_) /_ ____ _____ ___ ___ / /_ _________ ____ ________ _____/ /____ / /___ _______ ____ _____/ (_)___ (_)_________(_)___ ____ _ ___ / (_) /_ 5 | / / / __ \/ ___/ _ \/ __ `__ \ / / __ \/ ___/ / / / __ `__ \ / __ / __ \/ / __ \/ ___/ / ___/ / __/ / __ `/ __ `__ \/ _ \/ __/ / ___/ __ \/ __ \/ ___/ _ \/ ___/ __/ _ \/ __/ / / / ___/ / __ `/ __ / / __ \/ / ___/ ___/ / __ \/ __ `/ / _ \/ / / __/ 6 | / /___/ /_/ / / / __/ / / / / / / / /_/ (__ ) /_/ / / / / / / / /_/ / /_/ / / /_/ / / (__ ) / /_ / /_/ / / / / / / __/ /_ / /__/ /_/ / / / (__ ) __/ /__/ /_/ __/ /_/ /_/ / / / /_/ / /_/ / / /_/ / (__ ) /__/ / / / / /_/ / / __/ / / /_ 7 | /_____/\____/_/ \___/_/ /_/ /_/ /_/ .___/____/\__,_/_/ /_/ /_/ \__,_/\____/_/\____/_/ /____/_/\__/ \__,_/_/ /_/ /_/\___/\__/ \___/\____/_/ /_/____/\___/\___/\__/\___/\__/\__,_/_/ \__,_/\__,_/_/ .___/_/____/\___/_/_/ /_/\__, / \___/_/_/\__/ 8 | /_/ /_/ /____/ 9 | 10 | -------------------------------------------------------------------------------- /inc/rle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Adrien Soursou 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef RLE_H 24 | # define RLE_H 25 | 26 | /* 27 | * Compress a file using the run-length encoding algorithm. 28 | * If successful, it returns 0. 29 | * Returns -1 on failure, and sets errno to indicate the error. 30 | */ 31 | int rle_compress(const char *source_path, const char *destination_path); 32 | 33 | /* 34 | * Decompress a file using the run-length encoding algorithm. 35 | * If successful, it returns 0. 36 | * Returns -1 on failure, and sets errno to indicate the error. 37 | * If errno is set to EBADMSG, the given file is corrupted. 38 | */ 39 | int rle_extract(const char *source_path, const char *destination_path); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /test/z: -------------------------------------------------------------------------------- 1 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 2 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 3 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 4 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 5 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 6 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 7 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 8 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 9 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 10 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 11 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 12 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 13 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 14 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 15 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 16 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 17 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 18 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 19 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 20 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 21 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 22 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 23 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 24 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 25 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 26 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 27 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 28 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 29 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 30 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 31 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 32 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 33 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 34 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 35 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 36 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 37 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 38 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 39 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 40 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 41 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 42 | zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 43 | -------------------------------------------------------------------------------- /src/rle.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int rle_compress(const char *src, const char *dst) 7 | { 8 | FILE *in, *out; 9 | uint8_t t[129]; 10 | int i, keep; 11 | 12 | // file verification 13 | if (!(in = fopen(src, "rb"))) 14 | return (-1); 15 | if (!(out = fopen(dst, "wb"))) 16 | { 17 | fclose(in); 18 | return (-1); 19 | } 20 | 21 | // algorithm 22 | t[0] = fgetc(in); 23 | while (!feof(in)) 24 | { 25 | t[1] = fgetc(in); 26 | if (t[0] != t[1]) // uncompressible sequence 27 | { 28 | i = 1; 29 | if (!feof(in)) 30 | do 31 | t[++i] = fgetc(in); 32 | while (!feof(in) && i < 128 && t[i] != t[i - 1]); 33 | if ((keep = t[i] == t[i - 1])) 34 | --i; 35 | if (fputc(i - 1, out) == EOF || 36 | fwrite(t, sizeof(uint8_t), i, out) < (unsigned)i) 37 | break ; // write error 38 | t[0] = t[i]; 39 | if (!keep) 40 | continue ; // size too large or EOF 41 | } 42 | // compressible sequence 43 | i = 2; 44 | do 45 | t[1] = fgetc(in); 46 | while (++i < 130 && t[0] == t[1]); 47 | if (fputc(i + 125, out) == EOF || 48 | fputc(t[0], out) == EOF) 49 | break ; // write error 50 | t[0] = t[1]; 51 | } 52 | 53 | // error handling 54 | i = ferror(in) || ferror(out); 55 | 56 | fclose(in); 57 | fclose(out); 58 | return (-i); 59 | } 60 | 61 | int rle_extract(const char *src, const char *dst) 62 | { 63 | FILE *in, *out; 64 | int i, j, max; 65 | 66 | // file verification 67 | if (!(in = fopen(src, "rb"))) 68 | return (-1); 69 | if (!(out = fopen(dst, "wb"))) 70 | { 71 | fclose(in); 72 | return (-1); 73 | } 74 | 75 | // algorithm 76 | j = 0; 77 | while ((i = fgetc(in)) != EOF && (j = fgetc(in)) != EOF) 78 | { 79 | max = i + (i < 128 ? 1 : -126); 80 | while (max--) 81 | if (fputc(j, out) == EOF || 82 | (i < 128 && max && (j = fgetc(in)) == EOF)) 83 | break ; // write error 84 | } 85 | 86 | // error handling 87 | if (j == EOF) 88 | errno = EBADMSG; // corrupted file 89 | i = errno || i != EOF || ferror(in) || ferror(out); 90 | 91 | fclose(in); 92 | fclose(out); 93 | return (-i); 94 | } 95 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "rle.h" 6 | 7 | #define HELP_MSG \ 8 | "Compress and extracts files using the RLE compression algorithm.\n\n" \ 9 | " -c compress SOURCE to DEST\n" \ 10 | " -x extract SOURCE to DEST\n" \ 11 | " --help display this help and exit\n" \ 12 | " --version output version information and exit\n" 13 | 14 | #define LICENSE_MSG \ 15 | "Copyright (c) 2020 Adrien Soursou\n" \ 16 | "License: MIT\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY " \ 17 | "KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES " \ 18 | "OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. " \ 19 | "IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM" \ 20 | ", DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT " \ 21 | "OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR " \ 22 | "THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nWritten by Adrien Soursou.\n" 23 | 24 | static int print_help(char *bin) 25 | { 26 | printf("Usage: %s [OPTION] SOURCE DEST\n", bin); 27 | printf(HELP_MSG); 28 | return (0); 29 | } 30 | 31 | static int print_version(char *bin) 32 | { 33 | printf("%s 1.1\n", bin); 34 | printf(LICENSE_MSG); 35 | return (0); 36 | } 37 | 38 | static int print_invalid(char *bin) 39 | { 40 | fprintf(stderr, "%s: invalid option\n", bin); 41 | fprintf(stderr, "Try '%s --help' for more information.\n", bin); 42 | return (-1); 43 | } 44 | 45 | int main(int ac, char **av) 46 | { 47 | *av = basename(*av); 48 | for (int i = 1; i < ac; i++) 49 | if (!strcmp(av[i], "--help")) 50 | return print_help(*av); 51 | else if (!strcmp(av[i], "--version")) 52 | return print_version(*av); 53 | if (ac != 4) 54 | return print_invalid(*av); 55 | if (!strcmp(av[1], "-c")) 56 | rle_compress(av[2], av[3]); 57 | else if (!strcmp(av[1], "-x")) 58 | rle_extract(av[2], av[3]); 59 | else 60 | return print_invalid(*av); 61 | if (errno) 62 | fprintf(stderr, "%s: %s\n", *av, strerror(errno)); 63 | return (-(errno != 0)); 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rle-compression 2 | 3 | Program to compress and extract files using the run-length encoding algorithm. 4 | 5 | **Important note :** 6 | 7 | This implementation is a modified version of the algorithm to allow a better compression ratio. 8 | 9 | Refer to the [Technical specifications](#technical-specifications) section for more information. 10 | 11 | # Documentation 12 | ## Supported OS 13 | 14 | This software is officially compatible on both Linux and Mac. 15 | 16 | ## Compile from source 17 | Use the following command: 18 | ```shell 19 | make 20 | ``` 21 | 22 | ## Install 23 | ```shell 24 | make install 25 | ``` 26 | 27 | ## Uninstall 28 | ```shell 29 | make uninstall 30 | ``` 31 | 32 | ## Usage 33 | ```shell 34 | rle [OPTION] SOURCE DEST 35 | ``` 36 | **Options list:** 37 | - **-c** 38 | compress SOURCE to DEST 39 | - **-x** 40 | extract SOURCE to DEST 41 | - **--help** 42 | display help and exit 43 | - **--version** 44 | output version information and exit 45 | 46 | ## Example 47 | To compress the file named *foobar.txt*, the command will be: 48 | ```shell 49 | rle -c foobar.txt foobar.rle 50 | ``` 51 | Now let's extract this file: 52 | ```shell 53 | rle -x foobar.rle foobar.old 54 | ``` 55 | *foobar.old* has the same content as *foobar.txt*. 56 | 57 | # Technical specifications 58 | ## Description 59 | The format used during compression is as follows: 60 | ```shell 61 | [128-255][byte] 62 | # Format of a compressed sequence 63 | # (first byte value - 126) give the compressed sequence length between 2 and 129 64 | # The following byte contain the value 65 | 66 | [0-127][byte 0][byte 1]...[byte n] 67 | # Format of a uncompressed sequence 68 | # (first byte value + 1) give the uncompressed sequence length between 1 and 128 69 | # The following n bytes contain the value 70 | ``` 71 | 72 | ## Examples 73 | ```shell 74 | # Exemple 1: "AAAA" which can be reduced to "4A" 75 | [130][A] 76 | # length = 130 - 126 = 4 77 | # byte value = A 78 | 79 | # Exemple 2: "ABCDE" which cannot be reduced 80 | [4][A][B][C][D][E] 81 | # length = 4 + 1 = 5 82 | # bytes value = [A, B, C, D, E] 83 | 84 | # Exemple 3: "foobar" 85 | [0][f][128][o][2][b][a][r] 86 | # or [1f 2o 1b 1a 1r] 87 | ``` 88 | 89 | # License 90 | 91 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 92 | --------------------------------------------------------------------------------