-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.c
160 lines (131 loc) · 4.15 KB
/
io.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include "io.h"
#include "code.h"
#include "defines.h"
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
static uint8_t write_bit_buffer[ BLOCK ] = { 0 };
static uint32_t write_bit_top = 0;
// Description:
// Reads a certain number of bytes into a buffer or until no more can be read.
//
// Parameters:
// int infile - The input file.
// uint8_t *buf - The buffer to read to.
// uint32_t nbytes - The max number of bytes to read.
//
// Returns:
// uint32_t - How many bytes were read.
uint32_t read_bytes( int infile, uint8_t *buf, uint32_t nbytes ) {
if ( nbytes == 0 ) {
return 0;
}
uint32_t bytes_read = 0;
uint32_t bytes_read_current_round = 0;
while ( ( bytes_read_current_round = read( infile, buf + bytes_read, nbytes - bytes_read ) ) > 0 ) {
bytes_read += bytes_read_current_round;
if ( bytes_read == nbytes ) { // Finished reading max number of bytes.
break;
}
}
return bytes_read;
}
// Description:
// Writes a certain number of bytes into a buffer or until no more can be written. Will
// write to outfile when the buffer is full.
//
// Parameters:
// int outfile - The output file.
// uint8_t *buf - The buffer to write to.
// uint32_t nbytes - The max number of bytes to write.
//
// Returns:
// uint32_t - How many bytes were written.
uint32_t write_bytes( int outfile, uint8_t *buf, uint32_t nbytes ) {
if ( nbytes == 0 ) {
return 0;
}
uint32_t bytes_wrote = 0;
uint32_t bytes_wrote_current_round = 0;
while ( ( bytes_wrote_current_round = write( outfile, buf + bytes_wrote, nbytes - bytes_wrote ) ) > 0 ) {
bytes_wrote += bytes_wrote_current_round;
if ( bytes_wrote == nbytes ) { // Finished writing max number of bytes.
break;
}
}
return bytes_wrote;
}
// Description:
// Reads a bit from a file with a read buffer.
//
// Parameters:
// int infile - The input file.
// uint8_t *bit - The pointer to the uint8_t to set the bit to.
//
// Returns:
// bool - Whether the bit was read successfully.
bool read_bit( int infile, uint8_t *bit ) {
static uint8_t read_bit_buffer[ BLOCK ] = { 0 }; // Read bit buffer.
static uint32_t read_bit_top = 0; // Next bit to read.
static uint32_t read_bit_buffer_size = 0; // Number of bytes read into buffer.
if ( read_bit_top == 0 ) { // Refill buffer.
read_bit_buffer_size = read_bytes( infile, read_bit_buffer, BLOCK );
}
if ( read_bit_buffer_size == 0 ) {
return false;
}
*bit = ( 1 & ( read_bit_buffer[ read_bit_top / 8 ] >> ( read_bit_top % 8 ) ) );
read_bit_top++;
if ( read_bit_top == read_bit_buffer_size * 8 ) { // Done with read bit buffer.
read_bit_top = 0;
}
return true;
}
// Description:
// Writes a code's bits to a file with a write buffer.
//
// Parameters:
// int outfile - The output file.
// Code *c - The code to write.
//
// Returns:
// uint64_t - Bytes actually written to file.
uint64_t write_code( int outfile, Code *c ) {
uint64_t bytes_written = 0;
for ( uint32_t i = 0; i < c->top; i++ ) { // Loop through all bits.
uint8_t bit = 1 & ( c->bytes[ i / 8 ] >> ( i % 8 ) ); // Get current bit.
if ( bit == 0 ) { // Clear bit.
write_bit_buffer[ write_bit_top / 8 ] &= ~( 1 << ( write_bit_top % 8 ) );
} else { // Set bit.
write_bit_buffer[ write_bit_top / 8 ] |= ( 1 << ( write_bit_top % 8 ) );
}
write_bit_top++;
if ( write_bit_top == BLOCK * 8 ) { // Write bit buffer full.
write_bytes( outfile, write_bit_buffer, BLOCK );
bytes_written += BLOCK;
write_bit_top = 0;
}
}
return bytes_written;
}
// Description:
// Finishes writing out the write bit buffer and flushes the buffer.
//
// Parameters:
// int outfile - The output file.
//
// Returns:
// uint64_t - Bytes written to file.
uint64_t flush_codes( int outfile ) {
uint64_t bytes_written = 0;
if ( write_bit_top % 8 == 0 ) { // Write buffer not on byte boundary.
write_bytes( outfile, write_bit_buffer, write_bit_top / 8 );
bytes_written += write_bit_top / 8;
} else { // Write buffer on byte boundary.
write_bit_buffer[ write_bit_top / 8 ] &= ( ( 1 << ( write_bit_top % 8 ) ) - 1 ); // Zero out garbage bits in the last byte.
write_bytes( outfile, write_bit_buffer, write_bit_top / 8 + 1 );
bytes_written += write_bit_top / 8 + 1;
}
write_bit_top = 0;
return bytes_written;
}