Base24: Skillnad mellan sidversioner

Från Täpp-Anders
Hoppa till navigeringHoppa till sök
Skapade sidan med '= Bakgrund = Base24 är inte en standardkodning och den är lite mer komplex än de som baseras på ett jämt antal oktetter som base32 samt base64 men det har en fördel också, vi använder bara stora bokstäver A-X. = Implementation = = C = <pre> #include <stdio.h> #include <string.h> #include <stdlib.h> // BASE24 kodningstabell (A-X) static const char base24_table[] = "ABCDEFGHIJKLMNOPQRSTUVWX"; // Funktion för BASE24 kodning char* base24_encode(const...'
 
Ingen redigeringssammanfattning
 
(3 mellanliggande sidversioner av samma användare visas inte)
Rad 1: Rad 1:
[[category:c]]
[[category:programmering]]
[[category:algoritmer]]
= Bakgrund =  
= Bakgrund =  


Rad 4: Rad 8:


= Implementation =
= Implementation =
= C =
<pre>
<pre>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
 
const char ALPHABET[] = "BCDFGHJKMNPQRTVWXY2346789";
#define BASE 24
#define MAX_LINE 70
#define CHARS_PER_BLOCK 6 // 6 tecken för data täcker 24 bitar (24^6 > 2^24)
 
int get_index(char c) {
    for (int i = 0; i < BASE; i++) if (ALPHABET[i] == c) return i;
    return -1;
}


// BASE24 kodningstabell (A-X)
void encode_block(const uint8_t *in, int len, char *out_buf) {
static const char base24_table[] = "ABCDEFGHIJKLMNOPQRSTUVWX";
    uint32_t val = 0;
    // Packa indata till en 24-bitars integer
    if (len >= 1) val |= ((uint32_t)in[0] << 16);
    if (len >= 2) val |= ((uint32_t)in[1] << 8);
    if (len >= 3) val |= ((uint32_t)in[2]);


// Funktion för BASE24 kodning
     out_buf[0] = ALPHABET[len]; // Header: längd
char* base24_encode(const unsigned char* input, size_t length) {
    // Beräkna antal output-tecken: ungefär 8 bitar per 4.585 bitar (log2(24))
     size_t output_length = (length * 8 + 4) / 5; // Ungefärlig uppskattning
    char* encoded = malloc(output_length + 1);
    if (encoded == NULL) return NULL;
      
      
     unsigned long long buffer = 0;
     // Konvertera val till bas 24 över 6 tecken (position 1 till 6)
     int bits_left = 0;
     uint32_t temp = val;
    size_t j = 0;
     for (int i = CHARS_PER_BLOCK; i >= 1; i--) {
   
         out_buf[i] = ALPHABET[temp % BASE];
     for (size_t i = 0; i < length; i++) {
         temp /= BASE;
         buffer = (buffer << 8) | input[i];
        bits_left += 8;
          
        while (bits_left >= 5) {
            int shift = bits_left - 5;
            unsigned char value = (buffer >> shift) & 0x1F; // Ta 5 bitar
            if (value >= 24) value = 23; // Begränsa till 0-23
            encoded[j++] = base24_table[value];
            bits_left -= 5;
            buffer &= (1ULL << bits_left) - 1; // Rensa använda bitar
        }
     }
     }
   
}
     // Hantera resterande bitar
 
     if (bits_left > 0) {
int decode_block(const char *in_buf, uint8_t *out_three) {
        buffer <<= (5 - bits_left);
     int len = get_index(in_buf[0]);
         unsigned char value = (buffer & 0x1F);
     if (len < 0 || len > 3) return -1;
         if (value >= 24) value = 23;
 
         encoded[j++] = base24_table[value];
    uint32_t val = 0;
    for (int i = 1; i <= CHARS_PER_BLOCK; i++) {
         int idx = get_index(in_buf[i]);
         if (idx == -1) return -1;
         // Vi bygger värdet baserat på positionell vikt
        val = val * BASE + idx;
     }
     }
    if (len >= 1) out_three[0] = (uint8_t)((val >> 16) & 0xFF);
    if (len >= 2) out_three[1] = (uint8_t)((val >> 8) & 0xFF);
    if (len >= 3) out_three[2] = (uint8_t)(val & 0xFF);
      
      
    encoded[j] = '\0';
     return len;
     return encoded;
}
}


// Funktion för BASE24 avkodning
void encode_stream() {
unsigned char* base24_decode(const char* input, size_t* output_length) {
     printf("--- BEGIN BASE24 ENCODED DATA ---\n");
     size_t input_length = strlen(input);
     uint8_t in[3];
      
     char out[CHARS_PER_BLOCK + 1];
     // Skapa lookup-tabell
    int bytes_read, line_pos = 0;
    unsigned char decode_table[256] = {0};
     while ((bytes_read = fread(in, 1, 3, stdin)) > 0) {
     for (int i = 0; i < 24; i++) {
        encode_block(in, bytes_read, out);
        decode_table[(unsigned char)base24_table[i]] = i;
        for (int i = 0; i < CHARS_PER_BLOCK + 1; i++) {
            putchar(out[i]);
            if (++line_pos >= MAX_LINE) {
                putchar('\n');
                line_pos = 0;
            }
        }
     }
     }
      
     if (line_pos > 0) putchar('\n');
     unsigned long long buffer = 0;
     printf("--- END BASE24 ENCODED DATA ---\n");
     int bits_left = 0;
}
     size_t decoded_size = (input_length * 5 + 7) / 8; // Uppskattad maxstorlek
 
     unsigned char* decoded = malloc(decoded_size);
void decode_stream() {
    if (decoded == NULL) return NULL;
     int ch, count = 0;
    size_t j = 0;
     char block[CHARS_PER_BLOCK + 1];
   
    uint8_t out[3];
    for (size_t i = 0; i < input_length; i++) {
 
        unsigned char value = decode_table[(unsigned char)input[i]];
     while ((ch = getchar()) != EOF) {
         buffer = (buffer << 5) | value;
        if (ch == '-' || ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t') {
         bits_left += 5;
            if (ch == '-') while ((ch = getchar()) != '\n' && ch != EOF);
          
            continue;
        while (bits_left >= 8) {
         }
             int shift = bits_left - 8;
         block[count++] = (char)ch;
             decoded[j++] = (buffer >> shift) & 0xFF;
         if (count == CHARS_PER_BLOCK + 1) {
             bits_left -= 8;
             int decoded = decode_block(block, out);
            buffer &= (1ULL << bits_left) - 1;
             if (decoded > 0) fwrite(out, 1, decoded, stdout);
             count = 0;
         }
         }
     }
     }
   
    *output_length = j;
    return decoded;
}
}


// Testprogram
void run_test_case(const char *name, uint8_t *orig, int len) {
int main() {
     printf("Testar: %s (%d bytes)\n", name, len);
     const char* original = "Hello World!";
    size_t input_length = strlen(original);
      
      
     // Kodning
     int num_blocks = (len + 2) / 3;
     char* encoded = base24_encode((const unsigned char*)original, input_length);
     char *encoded = malloc(num_blocks * (CHARS_PER_BLOCK + 1));
     if (!encoded) {
    for (int i = 0; i < num_blocks; i++) {
         printf("Kodningsfel\n");
        int chunk = (len - i * 3 > 3) ? 3 : (len - i * 3);
         return 1;
        encode_block(&orig[i * 3], chunk, &encoded[i * (CHARS_PER_BLOCK + 1)]);
    }
 
    uint8_t *reconstructed = malloc(num_blocks * 3);
    int total_decoded = 0;
     for (int i = 0; i < num_blocks; i++) {
         int res = decode_block(&encoded[i * (CHARS_PER_BLOCK + 1)], &reconstructed[total_decoded]);
         if (res > 0) total_decoded += res;
     }
     }
   
 
     // Avkodning
     if (total_decoded == len && memcmp(orig, reconstructed, len) == 0) {
    size_t decoded_length;
         printf(" [PASS] Data matchar perfekt.\n");
    unsigned char* decoded = base24_decode(encoded, &decoded_length);
    } else {
    if (!decoded) {
         printf("  [FAIL] Korruption! Längd: %d/%d\n", total_decoded, len);
         printf("Avkodningsfel\n");
         free(encoded);
        return 1;
     }
     }
   
 
    // Skriv ut resultat
    printf("Original: %s\n", original);
    printf("BASE24: %s\n", encoded);
    printf("Decoded: %.*s\n", (int)decoded_length, decoded);
   
    // Frigör minne
     free(encoded);
     free(encoded);
     free(decoded);
     free(reconstructed);
      
}
 
void run_tests() {
    printf("BASE24 SJÄLVTEST - FINAL VERSION\n================================\n");
    uint8_t test1[13];
     for(int i=0; i<13; i++) test1[i] = (uint8_t)(rand() % 256);
    run_test_case("13 bytes slumpdata (inkl. höga bitvärden)", test1, 13);
 
    uint8_t test2[12] = {0};
    run_test_case("12 bytes nollor", test2, 12);
 
    uint8_t test3[] = "Klockrent, Täpp-Anders!";
    run_test_case("Sträng med UTF-8", test3, strlen((char*)test3));
}
 
int main(int argc, char *argv[]) {
    if (argc < 2) return 1;
    if (strcmp(argv[1], "--test") == 0) run_tests();
    else if (strcmp(argv[1], "--encode") == 0 || strcmp(argv[1], "-e") == 0) encode_stream();
    else if (strcmp(argv[1], "--decode") == 0 || strcmp(argv[1], "-d") == 0) decode_stream();
     return 0;
     return 0;
}
}
</pre>
</pre>

Nuvarande version från 24 april 2026 kl. 14.36


Bakgrund

Base24 är inte en standardkodning och den är lite mer komplex än de som baseras på ett jämt antal oktetter som base32 samt base64 men det har en fördel också, vi använder bara stora bokstäver A-X.

Implementation

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

const char ALPHABET[] = "BCDFGHJKMNPQRTVWXY2346789";
#define BASE 24
#define MAX_LINE 70
#define CHARS_PER_BLOCK 6 // 6 tecken för data täcker 24 bitar (24^6 > 2^24)

int get_index(char c) {
    for (int i = 0; i < BASE; i++) if (ALPHABET[i] == c) return i;
    return -1;
}

void encode_block(const uint8_t *in, int len, char *out_buf) {
    uint32_t val = 0;
    // Packa indata till en 24-bitars integer
    if (len >= 1) val |= ((uint32_t)in[0] << 16);
    if (len >= 2) val |= ((uint32_t)in[1] << 8);
    if (len >= 3) val |= ((uint32_t)in[2]);

    out_buf[0] = ALPHABET[len]; // Header: längd
    
    // Konvertera val till bas 24 över 6 tecken (position 1 till 6)
    uint32_t temp = val;
    for (int i = CHARS_PER_BLOCK; i >= 1; i--) {
        out_buf[i] = ALPHABET[temp % BASE];
        temp /= BASE;
    }
}

int decode_block(const char *in_buf, uint8_t *out_three) {
    int len = get_index(in_buf[0]);
    if (len < 0 || len > 3) return -1;

    uint32_t val = 0;
    for (int i = 1; i <= CHARS_PER_BLOCK; i++) {
        int idx = get_index(in_buf[i]);
        if (idx == -1) return -1;
        // Vi bygger värdet baserat på positionell vikt
        val = val * BASE + idx;
    }

    if (len >= 1) out_three[0] = (uint8_t)((val >> 16) & 0xFF);
    if (len >= 2) out_three[1] = (uint8_t)((val >> 8) & 0xFF);
    if (len >= 3) out_three[2] = (uint8_t)(val & 0xFF);
    
    return len;
}

void encode_stream() {
    printf("--- BEGIN BASE24 ENCODED DATA ---\n");
    uint8_t in[3];
    char out[CHARS_PER_BLOCK + 1];
    int bytes_read, line_pos = 0;
    while ((bytes_read = fread(in, 1, 3, stdin)) > 0) {
        encode_block(in, bytes_read, out);
        for (int i = 0; i < CHARS_PER_BLOCK + 1; i++) {
            putchar(out[i]);
            if (++line_pos >= MAX_LINE) {
                putchar('\n');
                line_pos = 0;
            }
        }
    }
    if (line_pos > 0) putchar('\n');
    printf("--- END BASE24 ENCODED DATA ---\n");
}

void decode_stream() {
    int ch, count = 0;
    char block[CHARS_PER_BLOCK + 1];
    uint8_t out[3];

    while ((ch = getchar()) != EOF) {
        if (ch == '-' || ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t') {
            if (ch == '-') while ((ch = getchar()) != '\n' && ch != EOF);
            continue;
        }
        block[count++] = (char)ch;
        if (count == CHARS_PER_BLOCK + 1) {
            int decoded = decode_block(block, out);
            if (decoded > 0) fwrite(out, 1, decoded, stdout);
            count = 0;
        }
    }
}

void run_test_case(const char *name, uint8_t *orig, int len) {
    printf("Testar: %s (%d bytes)\n", name, len);
    
    int num_blocks = (len + 2) / 3;
    char *encoded = malloc(num_blocks * (CHARS_PER_BLOCK + 1));
    for (int i = 0; i < num_blocks; i++) {
        int chunk = (len - i * 3 > 3) ? 3 : (len - i * 3);
        encode_block(&orig[i * 3], chunk, &encoded[i * (CHARS_PER_BLOCK + 1)]);
    }

    uint8_t *reconstructed = malloc(num_blocks * 3);
    int total_decoded = 0;
    for (int i = 0; i < num_blocks; i++) {
        int res = decode_block(&encoded[i * (CHARS_PER_BLOCK + 1)], &reconstructed[total_decoded]);
        if (res > 0) total_decoded += res;
    }

    if (total_decoded == len && memcmp(orig, reconstructed, len) == 0) {
        printf("  [PASS] Data matchar perfekt.\n");
    } else {
        printf("  [FAIL] Korruption! Längd: %d/%d\n", total_decoded, len);
    }

    free(encoded);
    free(reconstructed);
}

void run_tests() {
    printf("BASE24 SJÄLVTEST - FINAL VERSION\n================================\n");
    uint8_t test1[13];
    for(int i=0; i<13; i++) test1[i] = (uint8_t)(rand() % 256);
    run_test_case("13 bytes slumpdata (inkl. höga bitvärden)", test1, 13);

    uint8_t test2[12] = {0};
    run_test_case("12 bytes nollor", test2, 12);

    uint8_t test3[] = "Klockrent, Täpp-Anders!";
    run_test_case("Sträng med UTF-8", test3, strlen((char*)test3));
}

int main(int argc, char *argv[]) {
    if (argc < 2) return 1;
    if (strcmp(argv[1], "--test") == 0) run_tests();
    else if (strcmp(argv[1], "--encode") == 0 || strcmp(argv[1], "-e") == 0) encode_stream();
    else if (strcmp(argv[1], "--decode") == 0 || strcmp(argv[1], "-d") == 0) decode_stream();
    return 0;
}