135 lines
3.6 KiB
C++
135 lines
3.6 KiB
C++
|
|
#include "eyd_bitwriter.hh"
|
|
|
|
#define DEBUG 0
|
|
namespace EydLib {
|
|
/*
|
|
* int _group_pos;
|
|
int _fd;
|
|
*/
|
|
|
|
BitWriter::BitWriter(int size, int buffer_size = 1024){
|
|
// tous les groupes de bits seront de la taille donnée
|
|
this->_bitgroup_size = size;
|
|
this->_wanted_buffer_size = buffer_size;
|
|
this->_write_buffer = new char[this->_wanted_buffer_size];
|
|
this->_file_desc = -1;
|
|
this->_ready = false;
|
|
}
|
|
|
|
BitWriter::~BitWriter(){
|
|
delete(this->_write_buffer);
|
|
}
|
|
|
|
void BitWriter::open(std::string filename){
|
|
this->_file_desc = ::open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
if (this->_file_desc < 0){
|
|
throw eBitWriterBadFileDescriptor();
|
|
}
|
|
|
|
this->_real_buffer_size_in_bits = 0;
|
|
this->_current_bit_position = 0;
|
|
this->_ready = true;
|
|
}
|
|
|
|
ssize_t BitWriter::writeDirect(void *buf, size_t count){
|
|
return ::write(this->_file_desc, buf, count);
|
|
}
|
|
|
|
|
|
void BitWriter::setBitAt(int position, bool value){
|
|
// on attrappe la bonne case du tableau
|
|
// on shift dans le bon sens
|
|
// on retourne la valeur du bit.
|
|
int size_of_char = 8 * sizeof(char);
|
|
int i;
|
|
int index_of_char = position / size_of_char;
|
|
int shift_of_char = position % size_of_char;
|
|
|
|
char writer;
|
|
pDEBUG("BitWriter::setBitAt","pos %d - size %d\n", position, this->_real_buffer_size_in_bits );
|
|
|
|
if (position >= this->_real_buffer_size_in_bits){
|
|
throw eBitWriterOutOfBound();
|
|
} else {
|
|
unsigned char mask_fill;
|
|
unsigned char mask_hole;
|
|
for (i=0; i < size_of_char; i++){
|
|
mask_fill = (mask_fill << 1) | 1;
|
|
if (shift_of_char == i){
|
|
mask_hole = (mask_hole << 1) | 0;
|
|
} else {
|
|
mask_hole = (mask_hole << 1) | 1;
|
|
}
|
|
}
|
|
writer = this->_write_buffer[index_of_char];
|
|
if (value){
|
|
writer = ((writer ^ mask_fill) & mask_hole) ^ mask_fill;
|
|
} else {
|
|
writer = writer & mask_hole;
|
|
}
|
|
this->_write_buffer[index_of_char] = writer;
|
|
}
|
|
}
|
|
|
|
void BitWriter::flush(){
|
|
int nb_chars;
|
|
int size_of_char = 8 * sizeof(char);
|
|
int right_bit_len;
|
|
//nb_chars = ((this->_real_buffer_size_in_bits) / size_of_char);
|
|
// au pire on fait un write de trop
|
|
// donc la derniere "bonne valeur" se situe à
|
|
right_bit_len = this->_real_buffer_size_in_bits;
|
|
nb_chars = (right_bit_len / size_of_char);
|
|
|
|
// sauf qu'il reste de quoi finir un octet
|
|
if (nb_chars > this->_wanted_buffer_size) {
|
|
nb_chars = this->_wanted_buffer_size;
|
|
}
|
|
|
|
if ((this->_real_buffer_size_in_bits - 1) > this->_bitgroup_size) {
|
|
// on flush seulement si on a écrit + de 1 bitgroup dans le nouveau
|
|
// buffer
|
|
pDEBUG("BitWriter::flush","buffer() -> write()\n");
|
|
pDEBUG("BitWriter::flush","WRITE_BUFFER(%d chars) = %s\n",nb_chars, this->_write_buffer);
|
|
|
|
::write(this->_file_desc, this->_write_buffer, nb_chars);
|
|
}
|
|
this->_current_bit_position = 0;
|
|
this->_real_buffer_size_in_bits=1;
|
|
}
|
|
|
|
void BitWriter::write(BitGroup data){
|
|
int i;
|
|
bool bitValue;
|
|
int size_of_char = 8 * sizeof(char);
|
|
|
|
if (this->_file_desc < 0){
|
|
throw eBitWriterBadFileDescriptor();
|
|
}
|
|
|
|
for (i=0; i < this->_bitgroup_size; i++){
|
|
if (i < data.size()){
|
|
bitValue = data.getBitAt(i);
|
|
this->_real_buffer_size_in_bits += 1;
|
|
if (this->_real_buffer_size_in_bits > (this->_wanted_buffer_size * size_of_char)){
|
|
this->flush();
|
|
}
|
|
this->setBitAt(this->_current_bit_position, bitValue);
|
|
this->_current_bit_position += 1;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void BitWriter::close(){
|
|
// on vide le dernier buffer jusqu'a la position réelle...
|
|
pDEBUG("BitWriter::close","Remaining %d\n",this->_real_buffer_size_in_bits);
|
|
this->flush();
|
|
::close(this->_file_desc);
|
|
}
|
|
|
|
}
|
|
#undef DEBUG
|