Below is my entire program. You can read what it does thanks to the comments and specifications in particular.
My question is: can it be improved? Would it be possible, for example, to avoid writing a fwrite()
inside each if
? Is there a good pattern that can be implemented somewhere in this code?
The entire program is base on this UTF8 model and also studies the case in which a bit occurs in the 32nd position.
#include <stdio.h>
#include <math.h>
#include <stdint.h>
double log(double a);
/*
* This program reads 4 byte codepoints (in BIG ENDIAN) from a file strictly called "input.data" and creates another file called "ENCODED.data" with the relative encoding in UTF8.
*
* In order to compile this file, in Unix, you need to add the -lm clause because the library math.h function log() requires it.
* For example: gcc encoding.c -o encoding -lm
*/
int main() {
unsigned char bufferCP[4]; //Buffer used to store the codepoints
unsigned char bufferOut[6]; //Buffer used to store the UTF8-encoded codepoints
FILE *ptr, *out;
ptr = fopen("input.data", "rb"); //r for read, b for bynary
out = fopen("ENCODED.data", "wb");
int elem = 0, bytesRead = 0;
unsigned char mask = 0x3F; //Mask used to keep bits interesting for analysis
uint32_t codepoint = 0; //A codepoint must be an unsigned 32 bit integer
//--------------------File-Reading--------------------
while ((elem = fgetc(ptr)) != EOF) {
//Stores the character in the buffer
bufferCP[bytesRead++] = (unsigned char) elem;
if (bytesRead == 4) { //A codepoint is ready to be managed
//Builds a codepoint from the buffer. Reads it in BIG ENDIAN.
for(int j=3; j>=0; j--) {
codepoint <<= 8;
codepoint |= bufferCP[j];
}
//Searches the position of the most significant bit
double logRes = (log(codepoint)/log(2)) + 1;
int bitPos = (int) logRes;
//--------------------UTF8-Encoding--------------------
if (bitPos <= 7) {
bufferOut[0] = (unsigned char) codepoint; //No need to manage this codepoint
fwrite(bufferOut, 1, 1, out);
} else if (bitPos <= 11) {
bufferOut[0] = (codepoint >> 6) | 0xC0;
bufferOut[1] = (codepoint & mask) | 0x80;
fwrite(bufferOut, 1, 2, out);
} else if (bitPos <= 16) {
bufferOut[0] = (codepoint >> 12) | 0xE0;
for(int i=1; i<3; i++)
bufferOut[i] = ((codepoint >> 6*(2-i)) & mask) | 0x80;
fwrite(bufferOut, 1, 3, out);
} else if (bitPos <= 21) {
bufferOut[0] = (codepoint >> 18) | 0xF0;
for(int i=1; i<4; i++)
bufferOut[i] = ((codepoint >> 6*(3-i)) & mask) | 0x80;
fwrite(bufferOut, 1, 4, out);
} else if (bitPos <= 26) {
bufferOut[0] = (codepoint >> 24) | 0xF8;
for(int i=1; i<5; i++)
bufferOut[i] = ((codepoint >> 6*(4-i)) & mask) | 0x80;
fwrite(bufferOut, 1, 5, out);
} else if (bitPos <= 32) {
if (bitPos == 32)
bufferOut[0] = (codepoint >> 30) | 0xFE; //UTF8-encoding first byte would be: 11111111?
else
bufferOut[0] = (codepoint >> 30) | 0xFC;
for(int i=1; i<6; i++)
bufferOut[i] = ((codepoint >> 6*(5-i)) & mask) | 0x80;
fwrite(bufferOut, 1, 6, out);
}
bytesRead = 0; //Variable reset
}
}
}
wchar_t
to UTF-8, quickly and easily. \$\endgroup\$