5 #include <schroedinger/schro.h>
16 void operator++(SyncState
& s
) { s
= (SyncState
)(s
+1); }
18 struct SchroSyncState
{
22 std::list
<SchroBuffer
*> bufs
;
25 static const char* syncstate_to_str
[] = {
26 "NOT_SYNCED", "GOT_1PCP", "TRY_SYNC", "SYNCED", "SYNCED_INCOMPLETEDU"
29 typedef std::list
<SchroBuffer
*> BS
;
31 /* search @bufs@, starting at @offset@ to (sum (map length bufs))-10
32 * for a parse_code_prefix.
34 * The -10 is to avoid situations where a match would be found, but
35 * there isn't a complete parse_code_prefix in the bufferlist.
37 bool schro_buflist_find_parseinfo(BS
& bufs
, int& offset
)
39 BS::iterator it
= bufs
.begin();
43 BS::iterator last
= bufs
.end();
46 /* find starting buffer and offset into it */
47 while (idx
>= (*it
)->length
) {
49 idx_offset
+= (*it
)->length
;
54 int endskip
= (it
== last
) ? 10 : 0;
55 unsigned char* pos
= (unsigned char*) memmem((*it
)->data
+ idx
, (*it
)->length
- idx
- endskip
, "BBCD", 4);
57 /* found in this buffer */
58 offset
= idx_offset
+ pos
- (*it
)->data
;
65 /* deal with finding prefix that spans two buffers */
66 /* part (1) look in this buffer */
68 for (i
= 0; i
< 3; i
++) {
70 for (int j
= 0; j
< 3-i
; j
++) {
71 if ("BBCD"[j
] != *((*it
)->data
+ (*it
)->length
- 3 + i
)) {
80 idx_offset
+= (*it
)->length
;
83 /* part (2) look in the next buffer */
84 for (int j
= 0; j
< 1+i
; j
++) {
85 if ("BBCD"[3-i
+j
] != *((*it
)->data
+ j
)) {
86 offset
= idx_offset
+ j
;
90 } while (it
!= bufs
.end());
95 schro_buflist_length(BS
& bufs
)
98 for (BS::iterator it
= bufs
.begin(); it
!= bufs
.end(); ++it
)
104 schro_buflist_new_subbuffer(BS
& bufs
, int offset
, int len
)
106 BS::iterator it
= bufs
.begin();
109 /* find starting buffer and offset into it */
110 while (idx
>= (*it
)->length
) {
111 idx
-= (*it
)->length
;
115 if (idx
+ len
<= (*it
)->length
) {
116 /* the found du is wholy in one buffer, form a subbuffer */
117 return schro_buffer_new_subbuffer(*it
, idx
, len
);
120 /* otherwise, aggregate to form a new buffer */
121 SchroBuffer
*b
= schro_buffer_new_and_alloc(len
);
123 for (; it
!= bufs
.end(); ++it
, idx
= 0) {
124 int blen
= (*it
)->length
- idx
;
125 int sublen
= len
< blen
? len
: blen
;
126 memcpy(b
->data
+ offset
, (*it
)->data
+ idx
, sublen
);
133 schro_buffer_unref(b
);
138 int32_t next_parse_offset
;
139 int32_t prev_parse_offset
;
143 bool schro_buflist_unpack_parseinfo(ParseInfo
* pi
, BS
& bufs
, int offset
)
148 BS::iterator it
= bufs
.begin();
151 /* find starting buffer and offset into it */
152 while (idx
>= (*it
)->length
) {
153 idx
-= (*it
)->length
;
157 const unsigned char* pu
= (*it
)->data
+ idx
;
159 if ((*it
)->length
- idx
> 13) {
161 if (pu
[0] != 'B' || pu
[1] != 'B' || pu
[2] != 'C' || pu
[3] != 'D')
164 pi
->parse_code
= pu
[4];
165 pi
->next_parse_offset
= pu
[5] << 24 | pu
[6] << 16 | pu
[7] << 8 | pu
[8];
166 pi
->prev_parse_offset
= pu
[9] << 24 | pu
[10] << 16 | pu
[11] << 8 | pu
[12];
171 memset(pi
, 0, sizeof(ParseInfo
));
172 for (int i
= 0; i
< 13; i
++) {
173 if (it
== bufs
.end())
177 case 0: case 1: case 2: case 3:
178 if (pu
[i
] != "BBCD"[i
])
182 pi
->parse_code
= pu
[4];
184 case 5: case 6: case 7: case 8:
185 pi
->next_parse_offset
|= pu
[i
] << ((8-i
)*8);
187 case 9: case 10: case 11: case 12:
188 pi
->prev_parse_offset
|= pu
[i
] << ((12-i
)*8);
192 if (idx
+ i
+ 1 == (*it
)->length
) {
195 pu
= (*it
)->data
- i
-1;
198 /* slowpath complete */
203 schro_parse_getnextdu(SchroSyncState
* s
, SchroBuffer
* b
)
206 s
->bufs
.push_back(b
);
208 if (schro_buflist_length(s
->bufs
) == 0)
215 case NOT_SYNCED
: /* -> GOT_1PCP */
216 case GOT_1PCP
: /* -> TRY_SYNC */
217 /* the only reason we care about 1PCP, is to stop reading
218 * a random stream filling up buf_list forever. (assuming
219 * that no 'BBCD' emulation occurs */
220 /* XXX, not handled yet */
221 if (schro_buflist_length(s
->bufs
) - s
->offset
<= 1)
222 /* there must be at least one byte avaliable in bufs */
225 if (schro_buflist_find_parseinfo(s
->bufs
, s
->offset
))
228 case TRY_SYNC
: { /* -> (SYNCED | GOT_1PCP) */
230 bool a
= schro_buflist_unpack_parseinfo(&pu1
, s
->bufs
, s
->offset
);
231 bool b
= schro_buflist_unpack_parseinfo(&pu
, s
->bufs
, s
->offset
- pu1
.prev_parse_offset
);
232 if (!a
|| !b
|| (pu1
.prev_parse_offset
!= pu
.next_parse_offset
)) {
236 s
->last_npo
= pu
.next_parse_offset
;
240 case SYNCED
: { /* -> (SYNCED | GOT_1PCP) */
241 bool a
= schro_buflist_unpack_parseinfo(&pu
, s
->bufs
, s
->offset
);
242 if (!a
|| (s
->last_npo
!= pu
.prev_parse_offset
)) {
246 s
->offset
+= pu
.next_parse_offset
;
247 s
->last_npo
= pu
.next_parse_offset
;
251 case SYNCED_INCOMPLETEDU
:
253 schro_buflist_unpack_parseinfo(&pu
, s
->bufs
, s
->offset
- s
->last_npo
);
254 s
->state
= SYNCED
; /* try again */
257 } while (SYNCED
!= s
->state
);
259 if (SYNCED
!= s
->state
)
262 /* synced, extract a data unit */
264 du
= schro_buflist_new_subbuffer(s
->bufs
265 ,s
->offset
- pu
.next_parse_offset
266 ,pu
.next_parse_offset
);
268 s
->state
= SYNCED_INCOMPLETEDU
;
273 fprintf(stderr
, "got: (from offset:%d len:%d\n"
274 " %02x %02x %02x %02x\n %02x\n"
275 " %02x %02x %02x %02x\n %02x %02x %02x %02x\n"
276 ,s
->offset
- pu
.next_parse_offset
, pu
.next_parse_offset
277 ,du
->data
[0], du
->data
[1], du
->data
[2], du
->data
[3]
279 ,du
->data
[5], du
->data
[6], du
->data
[7], du
->data
[8]
280 ,du
->data
[9], du
->data
[10], du
->data
[11], du
->data
[12]
284 /* see if offset is > any buffers in buf */
285 for (BS::iterator it
= s
->bufs
.begin(); it
!= s
->bufs
.end();) {
286 if ((*it
)->length
> s
->offset
)
288 s
->offset
-= (*it
)->length
;
291 schro_buffer_unref(b
);