mirror of
https://github.com/sigmasternchen/libsfuid
synced 2025-03-15 07:59:02 +00:00
Now it's a shared library.
This commit is contained in:
parent
b1dc633157
commit
0e511a94c3
5 changed files with 342 additions and 227 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -52,5 +52,4 @@ Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
|
||||||
# Executables
|
# Executables
|
||||||
F6jigYck4v
|
example
|
||||||
benchmark
|
|
||||||
|
|
23
Makefile
23
Makefile
|
@ -1,11 +1,22 @@
|
||||||
|
|
||||||
all: F6jigYck4v
|
all: libsfuid.so example
|
||||||
|
|
||||||
benchmark: main.c
|
libsfuid.so: lib/sfuid.o
|
||||||
gcc -lm -DBENCHMARK -o $@ $<
|
@echo Linking shared object...
|
||||||
|
@gcc -shared -o $@ $^
|
||||||
|
|
||||||
F6jigYck4v: main.c
|
example: example.o libsfuid.so
|
||||||
gcc -lm -o $@ $<
|
@echo Linking example program...
|
||||||
|
@gcc -L. -lsfuid -lm -o $@ $<
|
||||||
|
|
||||||
|
example.o: lib/sfuid.h
|
||||||
|
lib/sfuid.o: lib/sfuid.h
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
@echo Compiling $<...
|
||||||
|
@gcc -Wall -fPIC -c $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm F6jigYck4v
|
@rm *.o
|
||||||
|
@rm lib/*.o
|
||||||
|
@rm *.so example
|
||||||
|
|
118
example.c
Normal file
118
example.c
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "lib/sfuid.h"
|
||||||
|
|
||||||
|
#define error(...) fprintf(stderr, __VA_ARGS__)
|
||||||
|
|
||||||
|
void help(const char* name) {
|
||||||
|
printf("SYNOPSIS: %s [OPTIONS] INPUT\n\n", name);
|
||||||
|
printf("options: \n");
|
||||||
|
printf(" -e encode INPUT (default)\n");
|
||||||
|
printf(" -d decode INPUT\n");
|
||||||
|
printf(" -l LENGTH set the length (default: 10)\n");
|
||||||
|
printf(" -c CHARSET set the charset (default: a-zA-Z0-9)\n");
|
||||||
|
printf(" -o OFFSET set the offset (default: 5)\n");
|
||||||
|
printf(" -h show this help message\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
bool decodeMode = false;
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
char* endptr;
|
||||||
|
|
||||||
|
sfuid_settings_t settings = sfuid_default_settings;
|
||||||
|
|
||||||
|
while((opt = getopt(argc, argv, "o:c:l:dehy")) != -1) {
|
||||||
|
switch(opt) {
|
||||||
|
case 'o':
|
||||||
|
settings.offset = strtol(optarg, &endptr, 10);
|
||||||
|
if (*endptr != 0) {
|
||||||
|
error("Argument for -o has to be a number.\nTry -h to get help.\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
settings.length = strtol(optarg, &endptr, 10);
|
||||||
|
if (*endptr != 0) {
|
||||||
|
error("Argument of -l has to be a number.\nTry -h to get help.\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
settings.charset = optarg;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
decodeMode = false;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
decodeMode = true;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
help(argv[0]);
|
||||||
|
exit(0);
|
||||||
|
case 'y':
|
||||||
|
settings.charset = "0-9A-Za-z-_";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown option.\nTry -h to get help.\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind >= argc) {
|
||||||
|
error("Expected data after options.\nTry -h to get help.\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
tmp = sfuid_init(settings);
|
||||||
|
if (tmp != SFUID_ERROR_NONE) {
|
||||||
|
error("Error: %s\n", sfuid_error(tmp));
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decodeMode) {
|
||||||
|
const char* string = argv[optind];
|
||||||
|
|
||||||
|
uint64_t value;
|
||||||
|
|
||||||
|
tmp = sfuid_decode(string, &value);
|
||||||
|
if (tmp != SFUID_ERROR_NONE) {
|
||||||
|
error("Error: %s\n", sfuid_error(tmp));
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%" PRIu64 "\n", value);
|
||||||
|
} else {
|
||||||
|
uint64_t value = strtoull(argv[optind], &endptr, 10);
|
||||||
|
if (*endptr != 0) {
|
||||||
|
error("Value has to be a number for encoding.\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
if (value == ULLONG_MAX && errno == ERANGE) {
|
||||||
|
error("Value overflows the internal datatype.\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* string = malloc(settings.length);
|
||||||
|
|
||||||
|
tmp = sfuid_encode(value, string);
|
||||||
|
|
||||||
|
if (tmp != SFUID_ERROR_NONE) {
|
||||||
|
error("Error: %s\n", sfuid_error(tmp));
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s\n", string);
|
||||||
|
free(string);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,34 +4,50 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <limits.h>
|
#include "sfuid.h"
|
||||||
|
|
||||||
|
const sfuid_settings_t sfuid_default_settings = {
|
||||||
|
.length = 10,
|
||||||
|
.charset = "a-zA-Z0-9",
|
||||||
|
.offset = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
sfuid_settings_t settings;
|
||||||
|
bool settingsValid = false;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint64_t max;
|
||||||
|
uint64_t prime;
|
||||||
|
char* charset;
|
||||||
|
int inverseCharset[(1 << 7)];
|
||||||
|
} properties = {
|
||||||
|
.charset = NULL,
|
||||||
|
.inverseCharset = {-1}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef __uint128_t uint128_t;
|
typedef __uint128_t uint128_t;
|
||||||
typedef __int128_t int128_t;
|
typedef __int128_t int128_t;
|
||||||
|
|
||||||
const char* charset = "a-zA-Z0-9";
|
#ifdef DEBUG
|
||||||
int inverseCharset[(1 << 7)] = {-1};
|
#define verbose(...) printf(__VA_ARGS__);
|
||||||
unsigned int resultLength = 10;
|
#else
|
||||||
unsigned int offset = 5;
|
#define verbose(...)
|
||||||
bool verbose = false;
|
#endif
|
||||||
|
|
||||||
#define verbose(...) if (verbose) printf(__VA_ARGS__);
|
|
||||||
#define error(...) fprintf(stderr, __VA_ARGS__)
|
|
||||||
|
|
||||||
int convertToString(char* string, uint64_t number) {
|
int convertToString(char* string, uint64_t number) {
|
||||||
int charsetLength = strlen(charset);
|
int charsetLength = strlen(properties.charset);
|
||||||
|
|
||||||
int length = 0;
|
int length = 0;
|
||||||
do {
|
do {
|
||||||
string[length++] = charset[number % charsetLength];
|
string[length++] = properties.charset[number % charsetLength];
|
||||||
number /= charsetLength;
|
number /= charsetLength;
|
||||||
} while(number > 0);
|
} while(number > 0);
|
||||||
|
|
||||||
for(; length < resultLength; length++) {
|
for(; length < settings.length; length++) {
|
||||||
string[length] = charset[0];
|
string[length] = properties.charset[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < length / 2; i++) {
|
for(int i = 0; i < length / 2; i++) {
|
||||||
|
@ -42,27 +58,25 @@ int convertToString(char* string, uint64_t number) {
|
||||||
|
|
||||||
string[length] = '\0';
|
string[length] = '\0';
|
||||||
|
|
||||||
return length;
|
return SFUID_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t convertFromString(const char* string) {
|
int convertFromString(const char* string, uint64_t* result) {
|
||||||
uint64_t result = 0;
|
|
||||||
|
|
||||||
int stringLength = strlen(string);
|
int stringLength = strlen(string);
|
||||||
int charsetLength = strlen(charset);
|
int charsetLength = strlen(properties.charset);
|
||||||
|
|
||||||
|
*result = 0;
|
||||||
|
|
||||||
for (int i = 0; i < stringLength; i++) {
|
for (int i = 0; i < stringLength; i++) {
|
||||||
bool found = false;
|
int tmp = properties.inverseCharset[(int) string[i]];
|
||||||
int tmp = inverseCharset[string[i]];
|
|
||||||
if (tmp < 0) {
|
if (tmp < 0) {
|
||||||
error("Parsing error.\nUnexpected character '%c'.\n", string[i]);
|
return SFUID_ERROR_PARSING;
|
||||||
exit(3);
|
|
||||||
}
|
}
|
||||||
uint64_t val = ((uint64_t) pow(charsetLength, stringLength - i - 1));
|
uint64_t val = ((uint64_t) pow(charsetLength, stringLength - i - 1));
|
||||||
result += ((uint64_t) tmp) * val;
|
*result += ((uint64_t) tmp) * val;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return SFUID_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t primelist[] = {
|
uint64_t primelist[] = {
|
||||||
|
@ -137,7 +151,7 @@ uint64_t multiplicativeInverse(uint64_t prime, uint64_t maxValue) {
|
||||||
return x1;
|
return x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t decode(uint64_t value, uint64_t prime, uint64_t maxValue) {
|
int decode(uint64_t* value, uint64_t prime, uint64_t maxValue) {
|
||||||
/*
|
/*
|
||||||
* (x * p) mod m = v
|
* (x * p) mod m = v
|
||||||
* (x * p) == v (mod m)
|
* (x * p) == v (mod m)
|
||||||
|
@ -146,7 +160,7 @@ uint64_t decode(uint64_t value, uint64_t prime, uint64_t maxValue) {
|
||||||
* => p * i == i (mod m)
|
* => p * i == i (mod m)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint128_t tmp = value;
|
uint128_t tmp = *value;
|
||||||
|
|
||||||
uint64_t inverse = multiplicativeInverse(prime, maxValue);
|
uint64_t inverse = multiplicativeInverse(prime, maxValue);
|
||||||
|
|
||||||
|
@ -154,96 +168,9 @@ uint64_t decode(uint64_t value, uint64_t prime, uint64_t maxValue) {
|
||||||
|
|
||||||
tmp *= inverse;
|
tmp *= inverse;
|
||||||
tmp &= (maxValue);
|
tmp &= (maxValue);
|
||||||
|
*value = tmp;
|
||||||
|
|
||||||
return (uint64_t) tmp;
|
return SFUID_ERROR_NONE;
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct settings {
|
|
||||||
uint64_t max;
|
|
||||||
uint64_t prime;
|
|
||||||
} settings_t;
|
|
||||||
|
|
||||||
settings_t getSettings() {
|
|
||||||
verbose("charset length: %d\n", strlen(charset));
|
|
||||||
double maxValueDouble = pow(strlen(charset), resultLength);
|
|
||||||
uint64_t maxValue;
|
|
||||||
int maxBits;
|
|
||||||
|
|
||||||
if (maxValueDouble >= pow(2, 65)) {
|
|
||||||
verbose("Max value %.0lf > 2^64, caping to 64 bits.\n", maxValueDouble);
|
|
||||||
maxBits = 64;
|
|
||||||
} else {
|
|
||||||
maxValue = (uint64_t) maxValueDouble;
|
|
||||||
verbose("theoer max: %llu\n", maxValue);
|
|
||||||
maxBits = findMax(maxValue);
|
|
||||||
|
|
||||||
if (maxBits <= 0) {
|
|
||||||
error("Length or charset is too big. This should not have happend.\n");
|
|
||||||
exit(3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxBits == 64) {
|
|
||||||
/*
|
|
||||||
* we want to avoid undefined behaviour.
|
|
||||||
* so instead of using an underflow we'll
|
|
||||||
* make this one explicit.
|
|
||||||
*/
|
|
||||||
maxValue = UINT64_MAX;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
maxValue = 1ll << maxBits;
|
|
||||||
maxValue--;
|
|
||||||
}
|
|
||||||
|
|
||||||
verbose("used bits: %d\n", maxBits);
|
|
||||||
verbose("max: %llu\n", maxValue);
|
|
||||||
verbose("usage: %.1f%\n", (100.0 * maxValue / maxValueDouble));
|
|
||||||
|
|
||||||
uint64_t prime = findPrime(maxBits);
|
|
||||||
|
|
||||||
verbose("prime: %llu\n", prime);
|
|
||||||
|
|
||||||
return (settings_t) {.max = maxValue, .prime = prime};
|
|
||||||
}
|
|
||||||
|
|
||||||
void toString(char* string, uint64_t value, settings_t settings) {
|
|
||||||
#ifdef BENCHMARK
|
|
||||||
struct timespec before, after;
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &before);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
value = encode(value, settings.prime, settings.max);
|
|
||||||
verbose("encoded: %llu\n", value);
|
|
||||||
convertToString(string, value);
|
|
||||||
|
|
||||||
#ifdef BENCHMARK
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &after);
|
|
||||||
|
|
||||||
uint64_t diff = (int64_t)(after.tv_sec - before.tv_sec) * (int64_t) 1000000000UL + (int64_t)(after.tv_nsec - before.tv_nsec);
|
|
||||||
fprintf(stderr, "Time for conversion: %llu ns\n", diff);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t fromString(const char* string, settings_t settings) {
|
|
||||||
#ifdef BENCHMARK
|
|
||||||
struct timespec before, after;
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &before);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint64_t result = convertFromString(string);
|
|
||||||
verbose("encoded: %llu\n", result);
|
|
||||||
result = decode(result, settings.prime, settings.max);
|
|
||||||
|
|
||||||
#ifdef BENCHMARK
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &after);
|
|
||||||
|
|
||||||
uint64_t diff = (int64_t)(after.tv_sec - before.tv_sec) * (int64_t) 1000000000UL + (int64_t)(after.tv_nsec - before.tv_nsec);
|
|
||||||
fprintf(stderr, "Time for conversion: %llu ns\n", diff);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -264,14 +191,15 @@ struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void prepareCharset() {
|
void prepareCharset() {
|
||||||
verbose("prepareing charset\n");
|
verbose("prepareing charset\n");
|
||||||
|
|
||||||
int size = strlen(charset);
|
int size = strlen(settings.charset);
|
||||||
const char* tmp;
|
const char* tmp;
|
||||||
|
|
||||||
for(int i = 0; i < ((sizeof shortcuts) / (sizeof shortcuts[0])); i++) {
|
for(int i = 0; i < ((sizeof shortcuts) / (sizeof shortcuts[0])); i++) {
|
||||||
tmp = charset;
|
tmp = settings.charset;
|
||||||
while((tmp = strstr(tmp, shortcuts[i].needle)) != NULL) {
|
while((tmp = strstr(tmp, shortcuts[i].needle)) != NULL) {
|
||||||
tmp++;
|
tmp++;
|
||||||
size += strlen(shortcuts[i].replacement) - strlen(shortcuts[i].needle);
|
size += strlen(shortcuts[i].replacement) - strlen(shortcuts[i].needle);
|
||||||
|
@ -279,7 +207,7 @@ void prepareCharset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char* inflatedCharset = malloc(size + 1);
|
char* inflatedCharset = malloc(size + 1);
|
||||||
strcpy(inflatedCharset, charset);
|
strcpy(inflatedCharset, settings.charset);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
char* first = NULL;
|
char* first = NULL;
|
||||||
|
@ -303,114 +231,145 @@ void prepareCharset() {
|
||||||
|
|
||||||
//verbose("full charset: %s\n", inflatedCharset);
|
//verbose("full charset: %s\n", inflatedCharset);
|
||||||
|
|
||||||
charset = inflatedCharset;
|
if (properties.charset != NULL)
|
||||||
|
free(properties.charset);
|
||||||
|
|
||||||
|
properties.charset = inflatedCharset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepareInverseCharset() {
|
void prepareInverseCharset() {
|
||||||
for(int i = 0; i < strlen(charset); i++) {
|
for(int i = 0; i < 127; i++) {
|
||||||
inverseCharset[charset[i]] = i;
|
properties.inverseCharset[i] = -1;
|
||||||
|
}
|
||||||
|
for(int i = 0; i < strlen(properties.charset); i++) {
|
||||||
|
properties.inverseCharset[(int) properties.charset[i]] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void help(const char* name) {
|
int setProperties() {
|
||||||
printf("SYNOPSIS: %s [OPTIONS] INPUT\n\n", name);
|
|
||||||
printf("options: \n");
|
|
||||||
printf(" -e encode INPUT (default)\n");
|
|
||||||
printf(" -d decode INPUT\n");
|
|
||||||
printf(" -l LENGTH set the length (default: 10)\n");
|
|
||||||
printf(" -c CHARSET set the charset (default: a-zA-Z0-9)\n");
|
|
||||||
printf(" -o OFFSET set the offset (default: 5)\n");
|
|
||||||
printf(" -v enable verbose mode\n");
|
|
||||||
printf(" -h show this help message\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
bool decodeMode = false;
|
|
||||||
|
|
||||||
int opt;
|
|
||||||
char* endptr;
|
|
||||||
|
|
||||||
while((opt = getopt(argc, argv, "o:c:l:devhy")) != -1) {
|
|
||||||
switch(opt) {
|
|
||||||
case 'o':
|
|
||||||
offset = strtol(optarg, &endptr, 10);
|
|
||||||
if (*endptr != 0) {
|
|
||||||
error("Argument for -o has to be a number.\nTry -h to get help.\n");
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
resultLength = strtol(optarg, &endptr, 10);
|
|
||||||
if (*endptr != 0) {
|
|
||||||
error("Argument of -l has to be a number.\nTry -h to get help.\n");
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
charset = optarg;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
decodeMode = false;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
decodeMode = true;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
verbose = true;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
help(argv[0]);
|
|
||||||
exit(0);
|
|
||||||
case 'y':
|
|
||||||
charset = "0-9A-Za-z-_";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error("Unknown option.\nTry -h to get help.\n");
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind >= argc) {
|
|
||||||
error("Expected data after options.\nTry -h to get help.\n");
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
verbose("charset: %s\n", charset);
|
|
||||||
verbose("length: %d\n", resultLength);
|
|
||||||
verbose("offset: %d\n", offset);
|
|
||||||
|
|
||||||
prepareCharset();
|
prepareCharset();
|
||||||
|
prepareInverseCharset();
|
||||||
|
|
||||||
settings_t settings = getSettings();
|
verbose("charset length: %d\n", strlen(properties.charset));
|
||||||
|
double maxValueDouble = pow(strlen(properties.charset), settings.length);
|
||||||
|
uint64_t maxValue;
|
||||||
|
int maxBits;
|
||||||
|
|
||||||
if (decodeMode) {
|
if (maxValueDouble >= pow(2, 65)) {
|
||||||
prepareInverseCharset();
|
verbose("Max value %.0lf > 2^64, caping to 64 bits.\n", maxValueDouble);
|
||||||
verbose("decode mode\n");
|
maxBits = 64;
|
||||||
const char* string = argv[optind];
|
|
||||||
verbose("string: %s\n", string);
|
|
||||||
uint64_t value = fromString(string, settings);
|
|
||||||
value -= offset;
|
|
||||||
printf("%llu\n", value);
|
|
||||||
} else {
|
} else {
|
||||||
uint64_t value = strtoull(argv[optind], &endptr, 10);
|
maxValue = (uint64_t) maxValueDouble;
|
||||||
if (*endptr != 0) {
|
verbose("theoer max: %llu\n", maxValue);
|
||||||
error("Value has to be a number for encoding.\n");
|
maxBits = findMax(maxValue);
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
if (value == ULLONG_MAX && errno == ERANGE) {
|
|
||||||
error("Value overflows the internal datatype.\n");
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
value += offset;
|
|
||||||
if (value > settings.max) {
|
|
||||||
error("value is too big!\nThe maximum value for the current settings is %llu.\n", settings.max - offset);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
verbose("encode mode\n");
|
|
||||||
verbose("value: %llu\n", value)
|
|
||||||
char* string = malloc(resultLength);
|
|
||||||
toString(string, value, settings);
|
|
||||||
printf("%s\n", string);
|
|
||||||
free(string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (maxBits == 64) {
|
||||||
|
/*
|
||||||
|
* we want to avoid undefined behaviour.
|
||||||
|
* so instead of using an underflow we'll
|
||||||
|
* make this one explicit.
|
||||||
|
*/
|
||||||
|
maxValue = UINT64_MAX;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
maxValue = 1ll << maxBits;
|
||||||
|
maxValue--;
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose("used bits: %d\n", maxBits);
|
||||||
|
verbose("max: %llu\n", maxValue);
|
||||||
|
verbose("usage: %.1f%\n", (100.0 * maxValue / maxValueDouble));
|
||||||
|
|
||||||
|
uint64_t prime = findPrime(maxBits);
|
||||||
|
|
||||||
|
verbose("prime: %llu\n", prime);
|
||||||
|
|
||||||
|
properties.max = maxValue;
|
||||||
|
properties.prime = prime;
|
||||||
|
|
||||||
|
return SFUID_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int checkCharset() {
|
||||||
|
int tmp = strlen(properties.charset);
|
||||||
|
if (tmp <= 0)
|
||||||
|
return SFUID_ERROR_CHARSET;
|
||||||
|
for(int i = 0; i < tmp; i++) {
|
||||||
|
if (properties.charset[i] < 0 || properties.charset[i] > 127)
|
||||||
|
return SFUID_ERROR_CHARSET;
|
||||||
|
for(int j = i+1; j < tmp; j++) {
|
||||||
|
if (properties.charset[i] == properties.charset[j])
|
||||||
|
return SFUID_ERROR_CHARSET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SFUID_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sfuid_init(sfuid_settings_t _settings) {
|
||||||
|
settings = _settings;
|
||||||
|
settingsValid = false;
|
||||||
|
|
||||||
|
if (settings.length == 0) {
|
||||||
|
return SFUID_ERROR_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tmp = setProperties();
|
||||||
|
if (tmp != SFUID_ERROR_NONE)
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
tmp = checkCharset();
|
||||||
|
if (tmp != SFUID_ERROR_NONE)
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
settingsValid = true;
|
||||||
|
|
||||||
|
return SFUID_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sfuid_encode(uint64_t value, char* string) {
|
||||||
|
if (!settingsValid)
|
||||||
|
return SFUID_ERROR_SETTINGS_INVALID;
|
||||||
|
|
||||||
|
value += settings.offset;
|
||||||
|
|
||||||
|
if (value > properties.max)
|
||||||
|
return SFUID_ERROR_VALUE;
|
||||||
|
|
||||||
|
value = encode(value, properties.prime, properties.max);
|
||||||
|
int tmp = convertToString(string, value);
|
||||||
|
if (tmp != SFUID_ERROR_NONE)
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
return SFUID_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sfuid_decode(const char* string, uint64_t* value) {
|
||||||
|
int tmp = convertFromString(string, value);
|
||||||
|
if (tmp != SFUID_ERROR_NONE)
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
tmp = decode(value, properties.prime, properties.max);
|
||||||
|
if (tmp != SFUID_ERROR_NONE)
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
*value -= settings.offset;
|
||||||
|
|
||||||
|
return SFUID_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* errors[] = {
|
||||||
|
"No error.",
|
||||||
|
"Length parameter not valid.",
|
||||||
|
"Charset parameter not valid.",
|
||||||
|
"Error while parsing input.",
|
||||||
|
"Settings not valid.",
|
||||||
|
"Value not valid."
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* sfuid_error(int error) {
|
||||||
|
if (error < 0 || error >= ((sizeof errors) / sizeof errors[0])) {
|
||||||
|
return "Unknown error.";
|
||||||
|
}
|
||||||
|
return errors[error];
|
||||||
}
|
}
|
28
lib/sfuid.h
Normal file
28
lib/sfuid.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef SFUID_H
|
||||||
|
#define SFUID_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define SFUID_ERROR_NONE 0
|
||||||
|
#define SFUID_ERROR_LENGTH 1
|
||||||
|
#define SFUID_ERROR_CHARSET 2
|
||||||
|
#define SFUID_ERROR_PARSING 3
|
||||||
|
#define SFUID_ERROR_SETTINGS_INVALID 4
|
||||||
|
#define SFUID_ERROR_VALUE 5
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int length;
|
||||||
|
const char* charset;
|
||||||
|
uint64_t offset;
|
||||||
|
} sfuid_settings_t;
|
||||||
|
|
||||||
|
extern const sfuid_settings_t sfuid_default_settings;
|
||||||
|
|
||||||
|
int sfuid_init(sfuid_settings_t settings);
|
||||||
|
int sfuid_encode(uint64_t value, char* string);
|
||||||
|
int sfuid_decode(const char* string, uint64_t* value);
|
||||||
|
|
||||||
|
const char* sfuid_error(int error);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue