#include "segmentation.h"
#include <math.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
char
*create_bit_representation_string(
const
void
*object,
const
unsigned
int
size,
const
unsigned
int
skip_last_bits)
{
unsigned
int
i = 0;
const
unsigned
char
*byte;
unsigned
int
temp_size = size;
const
double
mask_filter =
pow
(2, skip_last_bits);
const
unsigned
int
skip_last_bytes = skip_last_bits / CHAR_BIT;
char
*result =
malloc
(
sizeof
(
char
) * size * CHAR_BIT - skip_last_bits + 1);
for
(byte = object; temp_size--; ++byte)
{
unsigned
char
mask;
for
(mask = 1 << (CHAR_BIT - 1); mask; mask >>= 1)
{
if
((temp_size < skip_last_bytes) || (temp_size == 0 && mask < mask_filter))
{
break
;
}
result[i++] = (
char
) (mask & *byte ?
'1'
:
'0'
);
}
}
result[i] =
'\0'
;
return
result;
}
unsigned
char
create_left_mask(
const
unsigned
int
bits)
{
unsigned
char
left_mask = 0;
unsigned
int
i;
for
(i = 0; i < bits; i++)
{
left_mask |= (1 << (CHAR_BIT - 1 - i));
}
return
left_mask;
}
unsigned
int
shift_left_char_array_n_bits(
void
*object,
const
unsigned
int
size,
const
unsigned
int
bits)
{
if
(bits == 0)
{
return
0;
}
if
(bits < 1 || bits > CHAR_BIT - 1)
{
fprintf
(stderr,
"%s: Bad value %u for 'bits', it should be [1,7]"
"\n\tIgnoring operation\n"
, __FUNCTION__, bits);
return
0;
}
const
unsigned
char
left_mask = create_left_mask(bits);
unsigned
char
*byte;
unsigned
int
temp_size = size;
for
(byte = object; temp_size--; ++byte)
{
unsigned
char
carry = 0;
if
(temp_size)
{
carry = byte[1] & left_mask;
carry >>= (CHAR_BIT - bits);
}
*byte <<= bits;
*byte |= carry;
}
return
bits;
}
const
unsigned
int
calculate_unused_bits(
const
unsigned
int
segment_bit_size)
{
return
(CHAR_BIT - (segment_bit_size % CHAR_BIT)) % CHAR_BIT;
}
element_t *create_element(
const
unsigned
char
buffer[],
const
unsigned
int
byte_size,
const
unsigned
int
unused_bits,
const
unsigned
int
bytes_skipped,
const
unsigned
char
left_mask)
{
element_t *element = (element_t *)
malloc
(
sizeof
(element_t));
element->segment =
malloc
(byte_size);
element->size = byte_size;
element->unused_bits = unused_bits;
memcpy
(element->segment, &(buffer[bytes_skipped]), byte_size);
element->segment[byte_size - 1] &= left_mask;
return
element;
}
node_t *segment(
const
unsigned
char
buffer[],
const
unsigned
int
buffer_bytes_size,
const
unsigned
int
segment_bit_size,
const
unsigned
int
first_segment_bit_size)
{
if
(buffer_bytes_size == 0)
{
fprintf
(stderr,
"%s: Bad value %u for 'buffer_bytes_size', it should be greater than 0"
"\n\tIgnoring operation\n"
, __FUNCTION__, buffer_bytes_size);
return
NULL;
}
if
(segment_bit_size == 0)
{
fprintf
(stderr,
"%s: Bad value %u for 'segment_bit_size', it should be greater than 0"
"\n\tIgnoring operation\n"
, __FUNCTION__, segment_bit_size);
return
NULL;
}
node_t *head = NULL;
const
double
char_bit = CHAR_BIT;
const
unsigned
int
first_segment_byte_size = (unsigned
int
)
ceil
(
first_segment_bit_size / char_bit);
if
(first_segment_byte_size > buffer_bytes_size)
{
append(&head, create_element(buffer, buffer_bytes_size, 0, 0, UCHAR_MAX));
return
head;
}
unsigned
char
*temp_buffer =
malloc
(buffer_bytes_size);
memcpy
(temp_buffer, buffer, buffer_bytes_size);
unsigned
int
bits_shifted = 0;
unsigned
int
bytes_skipped = 0;
if
(first_segment_bit_size > 0)
{
const
unsigned
int
first_segment_unused_bits = calculate_unused_bits(
first_segment_bit_size);
const
unsigned
int
first_segment_byte_size_without_incomplete_byte =
first_segment_bit_size / CHAR_BIT;
const
unsigned
int
first_segment_bits = CHAR_BIT - first_segment_unused_bits;
const
unsigned
char
left_mask = create_left_mask(first_segment_bits);
append(&head, create_element(temp_buffer, first_segment_byte_size,
first_segment_unused_bits, bytes_skipped, left_mask));
bytes_skipped += first_segment_byte_size_without_incomplete_byte;
if
(bytes_skipped == buffer_bytes_size)
{
free
(temp_buffer);
return
head;
}
if
(first_segment_bits > 0 && first_segment_bits < CHAR_BIT)
{
bits_shifted += shift_left_char_array_n_bits(&(temp_buffer[bytes_skipped]),
buffer_bytes_size - bytes_skipped -
(bits_shifted / CHAR_BIT),
first_segment_bits);
}
}
const
unsigned
int
segment_byte_size = (unsigned
int
)
ceil
(segment_bit_size / char_bit);
const
unsigned
int
buffer_bits_size =
(buffer_bytes_size - bytes_skipped) * CHAR_BIT - bits_shifted;
const
unsigned
int
segments_count = buffer_bits_size / segment_bit_size;
if
(segments_count == 0)
{
append(&head, create_element(temp_buffer, buffer_bytes_size - bytes_skipped, bits_shifted, bytes_skipped, UCHAR_MAX));
free
(temp_buffer);
return
head;
}
const
unsigned
int
segment_unused_bits = calculate_unused_bits(segment_bit_size);
const
unsigned
int
last_segment_bits = CHAR_BIT - segment_unused_bits;
const
unsigned
char
left_mask = create_left_mask(last_segment_bits);
const
unsigned
int
segment_byte_size_without_incomplete_byte = segment_bit_size / CHAR_BIT;
const
unsigned
int
extra_bits = buffer_bits_size % segment_bit_size;
unsigned
int
i;
for
(i = 0; i < segments_count; i++)
{
append(&head,
create_element(temp_buffer, segment_byte_size, segment_unused_bits, bytes_skipped,
left_mask));
bytes_skipped += segment_byte_size_without_incomplete_byte;
if
((segments_count > 1 || extra_bits > 0) &&
(last_segment_bits > 0 && last_segment_bits < CHAR_BIT))
{
bits_shifted += shift_left_char_array_n_bits(&(temp_buffer[bytes_skipped]),
buffer_bytes_size - bytes_skipped -
(bits_shifted / CHAR_BIT),
last_segment_bits);
}
}
if
(extra_bits)
{
const
unsigned
int
last_segment_bytes_size =
buffer_bytes_size - bytes_skipped - (bits_shifted / CHAR_BIT);
const
unsigned
int
unused_bytes_for_last_segment =
segment_byte_size - last_segment_bytes_size;
const
unsigned
int
last_segment_unused_bits =
segment_bit_size - (buffer_bits_size % segment_bit_size) + segment_unused_bits -
(unused_bytes_for_last_segment * CHAR_BIT);
append(&head, create_element(temp_buffer, last_segment_bytes_size,
last_segment_unused_bits, bytes_skipped, UCHAR_MAX));
}
free
(temp_buffer);
return
head;
}