]>
git.gir.st - base1.git/blob - main.c
1 /* base1 en- and decoder with usage similar to GNU's base64.
2 (C) 2016 Tobias Girstmair, http://isticktoit.net/
3 Released under the GNU GPL v3. See LICENSE for details. */
15 #define DEFAULT_WRAP 72
17 #define COPYRIGHT "(C) 2016 Tobias Girstmair, GPLv3"
19 "Usage: %s [OPTION]... [FILE]\n"\
20 "Options: -d (decode), -i (ignore-garbage), -w COLS (wrap, default %d)"\
21 " -t (test) -v (version) -h (help)\n"
23 #define BASE ((1<<CHAR_BIT)) //2 ^ (bits of a byte)
28 int i
; /*ignore-garbage*/
33 size_t highestOneBitPosition(unsigned long long a
);
34 int multiplication_is_safe(unsigned long long a
, unsigned long long b
);
35 int addition_is_safe(unsigned long long a
, unsigned long long b
);
37 void do_encode (FILE* in
, FILE* out
, int wrap_column
, int test_only
);
38 void do_decode (FILE* in
, FILE* out
, int ignore_garbage
);
41 int main (int argc
, char** argv
) {
42 struct ops op
= {stdin
, 0, 0, DEFAULT_WRAP
, 0};
45 opterr
=0; /* suppress default error messages */
46 while ( (opt
= getopt(argc
, argv
, "diw:tvh")) != -1) {
48 case 'd': op
.d
= 1; break;
49 case 'i': op
.i
= 1; break;
50 case 'w': op
.w
= atoi (optarg
); break;
51 case 't': op
.t
= 1; break;
53 fprintf (stderr
, "base1 %s\n%s\n", VERSION
, COPYRIGHT
);
56 fprintf (stderr
, HELP_TEXT
, argv
[0], DEFAULT_WRAP
);
59 fprintf (stderr
, "unknown option '-%c'.\n", optopt
);
63 if (argc
-optind
> 1) {
64 fprintf (stderr
, "%s: extra operand '%s'. \n", argv
[0], argv
[argc
-1]);
66 } else if (optind
< argc
) {
67 if (strcmp (argv
[optind
], "-") != 0)
68 op
.f
= fopen (argv
[optind
], "rb");
72 do_decode (op
.f
, stdout
, op
.i
);
74 do_encode (op
.f
, stdout
, op
.w
, op
.t
);
77 if (op
.f
!= stdin
) fclose (op
.f
);
85 void do_encode (FILE* in
, FILE* out
, int wrap_column
, int test_only
) {
87 unsigned long long out_len
= 0;
89 for (int in_char
; (in_char
= getc(in
)) != EOF
; in_len
++) {
90 if (!multiplication_is_safe (out_len
, BASE
)){
95 if (!addition_is_safe (out_len
, in_char
)) {
103 printf ("Length of output:\t%llu\nMaximum value of ULL:\t%llu\n", out_len
, ULLONG_MAX
);
107 unsigned long long block_size
= 1;
109 for (int i
= 0; i
< in_len
; i
++) {
110 out_len
+= block_size
;
114 for (unsigned long long i
= 0; i
< out_len
; i
++)
115 fprintf (out
, "%s%c", wrap_column
&&!(i
%wrap_column
)&&i
?"\n":"", 'A');
116 //TODO: use faster function
119 void do_decode (FILE* in
, FILE* out
, int ignore_garbage
) {
120 unsigned long long in_len
= 0;
122 for (int in_char
; (in_char
= getc (in
)) != EOF
;) {
123 if (in_char
== ' ' || in_char
== '\n' || in_char
== '\t') {
125 } else if (in_char
== 'A') {
127 } else if (!ignore_garbage
) {
128 fprintf (stderr
, "Unrecognized glyph %c\n", in_char
);
131 // TODO: check for overflow!
135 unsigned long long block_size
= 1;
136 while (in_len
>= block_size
) {
137 in_len
-= block_size
;
143 char out_buf
[bin_len
];
144 for (int byte_num
= bin_len
-1; byte_num
>= 0; byte_num
--) {
145 b
= in_len
& (BASE
- 1);
146 out_buf
[byte_num
] = b
;
151 for (int i
= 0; i
< bin_len
; i
++) putc (out_buf
[i
], out
);
154 /* http://stackoverflow.com/a/199455 */
155 int addition_is_safe(unsigned long long a
, unsigned long long b
) {
156 size_t a_bits
=highestOneBitPosition(a
), b_bits
=highestOneBitPosition(b
);
157 return (a_bits
<64 && b_bits
<64);
160 int multiplication_is_safe(unsigned long long a
, unsigned long long b
) {
161 size_t a_bits
=highestOneBitPosition(a
), b_bits
=highestOneBitPosition(b
);
162 return (a_bits
+b_bits
<=64);
164 size_t highestOneBitPosition(unsigned long long a
) {