1 #include "newpacket.hpp"
13 void handle_input_error(FILE* rcs
)
16 throw std::runtime_error("Error reading input stream");
18 throw std::runtime_error("Unexpected end of file reading input stream");
20 throw std::runtime_error("Unexpected short read reading input stream");
23 bool read_input(FILE* rcs
, unsigned char* buffer
, size_t amount
, int blank_ok
)
25 int r
= fread(buffer
, 1, amount
, rcs
);
28 if(r
== 0 && blank_ok
)
30 handle_input_error(rcs
);
31 return false; //Notreached.
34 channel
& lookup_channel(std::vector
<channel
>& chantab
, uint16_t chan
)
37 std::runtime_error("lookup_channel: Illegal channel 0xFFFF");
38 for(std::vector
<channel
>::iterator i
= chantab
.begin(); i
!= chantab
.end(); ++i
)
39 if(i
->c_channel
== chan
)
41 std::stringstream str
;
42 str
<< "lookup_channel: Channel " << chan
<< " not found";
43 throw std::runtime_error(str
.str());
46 #define CHANNEL_BITMASK_SIZE ((65536 + MIN_CHAR_BIT - 1) / MIN_CHAR_BIT)
48 void check_segment_table(const std::vector
<channel
>& table
)
50 unsigned char channelbits
[CHANNEL_BITMASK_SIZE
];
52 throw std::runtime_error("check_segment_table: Zero channels in segment not allowed");
53 if(table
.size() > 0xFFFF)
54 throw std::runtime_error("check_segment_table: Too many channels in segment (max 65535)");
55 for(size_t i
= 0; i
< CHANNEL_BITMASK_SIZE
; i
++)
57 for(std::vector
<channel
>::const_iterator i
= table
.begin(); i
!= table
.end(); ++i
) {
58 uint16_t num
= i
->c_channel
;
60 throw std::runtime_error("Fatal: check_segment_table: Illegal channel 0xFFFF");
61 if(channelbits
[num
/ MIN_CHAR_BIT
] & (1 << (num
% MIN_CHAR_BIT
))) {
62 std::stringstream str
;
63 str
<< "check_segment_table: Duplicate channel " << num
;
64 throw std::runtime_error(str
.str());
66 channelbits
[num
/ MIN_CHAR_BIT
] |= (1 << (num
% MIN_CHAR_BIT
));
67 if(i
->c_channel_name
.length() > 0xFFFF) {
68 std::stringstream str
;
69 str
<< "check_segment_Table: Channel name too long (" << i
->c_channel_name
.length()
70 << " bytes, max 65535)";
71 throw std::runtime_error(str
.str());
76 #define CHAN_MAXNAME 65535
78 void read_segment_table_entry(read_channel
& rc
, FILE* rc_stream
, channel
& chan
)
80 unsigned char hdr
[6 + CHAN_MAXNAME
];
81 read_input(rc_stream
, hdr
, 6, 0);
82 size_t namelen
= ((uint16_t)hdr
[4] << 8) | (uint16_t)hdr
[5];
83 read_input(rc_stream
, hdr
+ 6, namelen
, 0);
84 chan
.c_channel
= ((uint16_t)hdr
[0] << 8) | (uint16_t)hdr
[1];
85 chan
.c_type
= ((uint16_t)hdr
[2] << 8) | (uint16_t)hdr
[3];
86 chan
.c_channel_name
.resize(namelen
);
87 for(size_t i
= 0; i
< namelen
; i
++)
88 chan
.c_channel_name
[i
] = hdr
[6 + i
];
89 chan
.c_channel_perm
= rc
.number_for_channel(chan
.c_channel_name
);
92 void read_segment_table(std::vector
<channel
>& chantab
, FILE* rc_stream
, read_channel
& rc
)
97 read_input(rc_stream
, x
, 2, 0);
98 uint16_t chans
= ((uint16_t)x
[0] << 8) | (uint16_t)x
[1];
100 throw std::runtime_error("read_segment_table: 0 channel segments not allowed");
102 chantab
.resize(chans
);
103 for(i
= 0; i
< chans
; i
++)
104 read_segment_table_entry(rc
, rc_stream
, chantab
[i
]);
105 check_segment_table(chantab
);
109 #define SPECIAL_TIMESKIP 0
110 #define SPECIAL_TIMESKIP_STR "\xFF\xFF\xFF\xFF"
111 #define SPECIAL_NEWSEGMENT 1
112 #define SPECIAL_NEWSEGMENT_STR "JPCRRMULTIDUMP"
119 {SPECIAL_TIMESKIP
, SPECIAL_TIMESKIP_STR
},
120 {SPECIAL_NEWSEGMENT
, SPECIAL_NEWSEGMENT_STR
},
124 #define MAXSPECIALLEN 4096
126 static int read_special(FILE* rcs
)
128 char buf
[MAXSPECIALLEN
];
129 size_t readcount
= 0;
132 read_input(rcs
, &ch
, 1, 0);
133 buf
[readcount
++] = (char)ch
;
134 struct special_entry
* e
= specials
;
137 if(readcount
< strlen(e
->se_spec
) && !strncmp(buf
, e
->se_spec
, readcount
))
139 if(readcount
== strlen(e
->se_spec
) && !strncmp(buf
, e
->se_spec
, readcount
))
146 throw std::runtime_error("read_special: Bad special");
150 read_channel::~read_channel()
155 read_channel::read_channel(const std::string
& filename
)
157 rc_stream
= fopen(filename
.c_str(), "rb");
159 std::stringstream str
;
160 str
<< "read_channel: Can't open '" << filename
<< "' for reading";
161 throw std::runtime_error(str
.str());
163 rc_last_timestamp
= 0;
165 rc_segmenttable_coming
= false;
166 rc_next_permchan
= 0;
169 uint32_t read_channel::number_for_channel(const std::string
& name
)
171 if(rc_permchans
.count(name
))
172 return rc_permchans
[name
];
173 return rc_permchans
[name
] = rc_next_permchan
++;
176 struct packet
* read_channel::read()
178 struct packet
* ret
= NULL
;
179 unsigned char packetheader
[7];
181 if(rc_segmenttable_coming
) {
182 //This is the segment channel table.
183 read_segment_table(rc_channels
, rc_stream
, *this);
184 rc_segmenttable_coming
= 0;
191 //Read the channel number.
192 if(!read_input(rc_stream
, packetheader
, 2, 1)) {
194 return NULL
; //Stream ends.
196 if(packetheader
[0] == 0xFF && packetheader
[1] == 0xFF) {
198 int specialtype
= read_special(rc_stream
);
199 if(specialtype
== SPECIAL_TIMESKIP
)
200 rc_last_timestamp
+= 0xFFFFFFFFU
;
201 else if(specialtype
== SPECIAL_NEWSEGMENT
)
202 rc_segmenttable_coming
= 1;
204 //If we don't have channel table nor channel table won't be next, then the magic is bad (not
206 if(!rc_channels
.size() && !rc_segmenttable_coming
)
207 throw std::runtime_error("read_channel: Bad magic");
209 //The first element must be of special type (segment start).
210 if(!rc_channels
.size())
211 throw std::runtime_error("read_channel: Bad magic");
212 uint16_t chan
= ((uint16_t)packetheader
[0] << 8) | (uint16_t)packetheader
[1];
213 struct channel
& c
= lookup_channel(rc_channels
, chan
);
214 //Read next 5 bytes of header (that far is safe).
215 read_input(rc_stream
, packetheader
+ 2, 5, 0);
222 read_input(rc_stream
, &tmp
, 1, 0);
223 if(((size_t)0 - 1) / 128 <= payload
)
224 throw std::runtime_error("read_channel: Packet payload too large");
225 payload
= 128 * payload
+ (tmp
& 0x7F);
228 ret
->rp_payload
.resize(payload
);
229 read_input(rc_stream
, &ret
->rp_payload
[0], payload
, 0);
230 ret
->rp_channel
= chan
;
231 ret
->rp_channel_perm
= c
.c_channel_perm
;
232 ret
->rp_major
= c
.c_type
;
233 ret
->rp_minor
= packetheader
[6];
234 uint32_t timedelta
= ((uint32_t)packetheader
[2] << 24) | ((uint32_t)packetheader
[3] << 16) |
235 ((uint32_t)packetheader
[4] << 8) | ((uint32_t)packetheader
[5]);
236 ret
->rp_timestamp
= (rc_last_timestamp
+= timedelta
);
237 ret
->rp_channel_name
= c
.c_channel_name
;
244 //Try again if return value would be NULL.
252 write_channel::write_channel(const std::string
& filename
)
254 wc_stream
= fopen(filename
.c_str(), "wb");
256 std::stringstream str
;
257 str
<< "write_channel: Can't open '" << filename
<< "' for writing";
258 throw std::runtime_error(str
.str());
260 wc_last_timestamp
= 0;
263 write_channel::~write_channel()
268 void write_channel::start_segment(const std::vector
<channel
>& channels
)
270 unsigned char x
[] = {0xFF, 0xFF, 'J', 'P', 'C', 'R', 'R', 'M', 'U', 'L', 'T', 'I', 'D', 'U', 'M', 'P'};
271 unsigned char chanbuf
[6 + 65535]; //Any channel entry fits in this.
273 check_segment_table(channels
);
275 //Write new segment start.
276 if(fwrite(x
, 16, 1, wc_stream
) < 1)
277 throw std::runtime_error("write_channel: Error writing output stream");
279 //Write new segment channel table.
280 chanbuf
[0] = (unsigned char)(channels
.size() >> 8);
281 chanbuf
[1] = (unsigned char)(channels
.size());
282 if(fwrite(chanbuf
, 2, 1, wc_stream
) < 1)
283 throw std::runtime_error("write_channel: Error writing output stream (channel count)");
285 for(std::vector
<channel
>::const_iterator i
= channels
.begin(); i
!= channels
.end(); ++i
) {
288 chanbuf
[0] = (unsigned char)(i
->c_channel
>> 8);
289 chanbuf
[1] = (unsigned char)(i
->c_channel
);
290 chanbuf
[2] = (unsigned char)(i
->c_type
>> 8);
291 chanbuf
[3] = (unsigned char)(i
->c_type
);
292 chanbuf
[4] = (unsigned char)(i
->c_channel_name
.length() >> 8);
293 chanbuf
[5] = (unsigned char)(i
->c_channel_name
.length());
294 for(size_t j
= 0; j
< i
->c_channel_name
.length(); j
++)
295 chanbuf
[6 + j
] = i
->c_channel_name
[j
];
296 len
= 6 + i
->c_channel_name
.length();
297 if(fwrite(chanbuf
, len
, 1, wc_stream
) < 1)
298 throw std::runtime_error("write_channel: Error writing output stream (channel entry)");
300 wc_channels
= channels
;
303 void write_channel::write(struct packet
& p
)
305 unsigned char packetheaders
[17];
306 if(!wc_channels
.size())
307 throw std::runtime_error("write_channel: Attempt to write outside segment");
308 if(p
.rp_timestamp
< wc_last_timestamp
) {
309 std::stringstream str
;
310 str
<< "write_channel: Non-monotonic timestream (" << p
.rp_timestamp
<< "<" << wc_last_timestamp
312 throw std::runtime_error(str
.str());
314 uint64_t deltatime
= p
.rp_timestamp
- wc_last_timestamp
;
315 while(deltatime
> 0xFFFFFFFFULL
) {
317 packetheaders
[0] = 0xFF;
318 packetheaders
[1] = 0xFF;
319 packetheaders
[2] = 0xFF;
320 packetheaders
[3] = 0xFF;
321 packetheaders
[4] = 0xFF;
322 packetheaders
[5] = 0xFF;
323 if(fwrite(packetheaders
, 6, 1, wc_stream
) < 1)
324 throw std::runtime_error("write_channel: Error writing output stream (delay)");
325 deltatime
-= 0xFFFFFFFFU
;
327 lookup_channel(wc_channels
, p
.rp_channel
);
328 size_t hdrlen
= 7, counter
;
329 uint64_t tmplen
= p
.rp_payload
.size();
331 //Compose the actual headers.
332 packetheaders
[0] = (unsigned char)(p
.rp_channel
>> 8);
333 packetheaders
[1] = (unsigned char)(p
.rp_channel
);
334 packetheaders
[2] = (unsigned char)(deltatime
>> 24);
335 packetheaders
[3] = (unsigned char)(deltatime
>> 16);
336 packetheaders
[4] = (unsigned char)(deltatime
>> 8);
337 packetheaders
[5] = (unsigned char)(deltatime
);
338 packetheaders
[6] = (unsigned char)(p
.rp_minor
);
340 for(counter
= 9; counter
<= 9; counter
--) {
341 unsigned shift
= 7 * counter
;
342 unsigned char bias
= shift
? 0x80 : 0x00;
343 if(tmplen
>= (1ULL << shift
) || !shift
|| wflag
) {
344 packetheaders
[hdrlen
++] = bias
+ ((tmplen
>> shift
) & 0x7F);
345 tmplen
&= ((1ULL << shift
) - 1);
350 if(hdrlen
&& fwrite(packetheaders
, hdrlen
, 1, wc_stream
) < 1)
351 throw std::runtime_error("write_channel: Error writing output stream (packet headers)");
352 //Write the actual payload.
353 if(p
.rp_payload
.size() && fwrite(&p
.rp_payload
[0], p
.rp_payload
.size(), 1, wc_stream
) < 1)
354 throw std::runtime_error("write_channel: Error writing output stream (payload)");
355 wc_last_timestamp
= p
.rp_timestamp
;