I am not very good at c at all. I have tried to capture the essense of what the C code does in C# using this wikipedia article. However my version is totally different and does not achive the same compression that the C code does. Therefore, I'd like to port the following code from C to C#. However, i do not need it to read/write to files.
I am not familiar with how file reading and writing works in C. Therefore all of the file related fluff confuses me. Also these lines are a little confusing: token = i - 1 | 0x80;
and length = (token & ~0x80) + 1;
/******************************************************************************
* LoadRLE / SaveRLE - Load and save binary data using RLE compression.
* Run-length tokens have a set MSB, while data tokens have a cleared
* MSB. The value of the token's remaining bits plus one indicates the
* length of the block. The minimum run length is three bytes, while
* the maximum is 128.
*
* data - Array holding data to load or save.
* size - Size of the data array.
* file - The file pointer to use.
* return - Total number of bytes read from or written to data[].
*/
size_t SaveRLE (unsigned char data[], size_t size, FILE *file)
{
unsigned char token;
unsigned int i;
size_t total = 0;
while(size)
{
/*This loop identifies blocks of repeating data:*/
i = 2;
while(i < size && i < 128 &&
data[i] == data[i - 1] && data[i - 1] == data[i - 2])
i++;
/*If repeating data was found, save it:*/
if(i > 2){
token = i - 1 | 0x80;
if(!fwrite(&token, 1, 1, file))
return total;
if(!fwrite(data, 1, 1, file))
return total;
data += i, size -= i, total += i;
}
/*This loop identifies blocks of non-repeating data:*/
i = 0;
while(i < size && i < 128 && (i + 2 > size ? 1 :
data[i] != data[i + 1] || data[i + 1] != data[i + 2]))
i++;
/*If non-repeating data was found, save it:*/
if(i){
token = i - 1;
if(!fwrite(&token, 1, 1, file))
return total;
if(fwrite(data, 1, i, file) != i)
return total;
data += i, size -= i, total += i;
}
}
return total;
}
size_t LoadRLE (unsigned char data[], size_t size, FILE *file)
{
unsigned char token;
unsigned int length;
size_t total = 0;
while(size && fread(&token, 1, 1, file)){
length = (token & ~0x80) + 1;
if (length > size)
return total;
if(token & 0x80){
if(!fread(&token, 1, 1, file开发者_运维问答))
return total;
memset(data, token, length);
}else{
if(fread(data, 1, length, file) != length)
return total;
}
data += length, size -= length, total += length;
}
return total;
}
Any help is greatly appreciated.
For your file question, I would strongly suggest consulting the C standard library documentation.
fread fwrite
token = i - 1 | 0x80;
i minus 1, | does a bitwise OR operation, in this case setting the 8th bit in token.
length = (token & ~0x80) + 1;
token & ~0x80
takes the NOT of 0x80 (all bits but the high bit) and does a bitwise AND (bit is set when both bits are set). In this case, it returns every but but the 8th bit.
As for what this means in your case, look at some articles about RLE.
/* 0 */
unsigned char token;
unsigned char data[];
FILE *file;
/* 1 */
if(!fwrite(&token, 1, 1, file))
return total;
/* 2 */
if(!fwrite(data, 1, 1, file))
return total;
/* 3 */
if(fwrite(data, 1, i, file) != i)
return total;
/* 4 */
if(!fread(&token, 1, 1, file))
return total;
/* 5 */
if(fread(data, 1, length, file) != length)
return total;
/* 6 */
while(size && fread(&token, 1, 1, file))
/* 7 */
data += i;
data[i];
/* 0 */
int token; // I'm using 'int' here to easier read single byte from Stream object, in your C code 'token' variable does not overflow so there will be no problem with that is has other type then 'byte'
byte[] data;
int data_pos = 0; // instead of moving 'data' pointer use additional index variable
Stream file; // some stream to read/write bytes
try {
/* 1 */
file.WriteByte((byte)token);
/* 2 */
file.Write(data, data_pos, 1);
/* 3 */
file.Write(data, data_pos, i);
/* 4 */
if ((token = file.ReadByte()) < 0)
return total;
/* 5 */
if (file.Read(data, data_pos, length) < length)
return total;
/* 6 */
while((size != 0) && ((token = file.ReadByte()) >= 0))
/* 7 */
data_pos += i;
data[data_pos + i];
} catch (IOException e) {
return total;
}
token = i - 1 | 0x80;
The |
symbol is a bitwise OR, so it is combining i - 1
with 0x80
(hex for 128). I will leave the research into bitwise operations to you.
length = (token & ~0x80) + 1;
The &
is a bitwise AND, while ~
negates the following value (flips the 1s and 0s). So that:
~1111000 = 00001111
Incidentally, all these operators are in C# and work in more or less the same way.
精彩评论