3 * Memory buffer operations.
5 * Copyright (c) 2005 Marko Kreen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #define STEP (16*1024)
50 mbuf_avail(MBuf
* mbuf
)
52 return mbuf
->data_end
- mbuf
->read_pos
;
56 mbuf_size(MBuf
* mbuf
)
58 return mbuf
->data_end
- mbuf
->data
;
62 mbuf_tell(MBuf
* mbuf
)
64 return mbuf
->read_pos
- mbuf
->data
;
68 mbuf_free(MBuf
* mbuf
)
72 memset(mbuf
->data
, 0, mbuf
->buf_end
- mbuf
->data
);
80 prepare_room(MBuf
* mbuf
, int block_len
)
85 if (mbuf
->data_end
+ block_len
<= mbuf
->buf_end
)
88 newlen
= (mbuf
->buf_end
- mbuf
->data
)
89 + ((block_len
+ STEP
+ STEP
- 1) & -STEP
);
91 newbuf
= px_realloc(mbuf
->data
, newlen
);
93 mbuf
->buf_end
= newbuf
+ newlen
;
94 mbuf
->data_end
= newbuf
+ (mbuf
->data_end
- mbuf
->data
);
95 mbuf
->read_pos
= newbuf
+ (mbuf
->read_pos
- mbuf
->data
);
102 mbuf_append(MBuf
* dst
, const uint8
*buf
, int len
)
106 px_debug("mbuf_append: no_write");
110 prepare_room(dst
, len
);
112 memcpy(dst
->data_end
, buf
, len
);
113 dst
->data_end
+= len
;
126 mbuf
= px_alloc(sizeof *mbuf
);
127 mbuf
->data
= px_alloc(len
);
128 mbuf
->buf_end
= mbuf
->data
+ len
;
129 mbuf
->data_end
= mbuf
->data
;
130 mbuf
->read_pos
= mbuf
->data
;
132 mbuf
->no_write
= false;
133 mbuf
->own_data
= true;
139 mbuf_create_from_data(const uint8
*data
, int len
)
143 mbuf
= px_alloc(sizeof *mbuf
);
144 mbuf
->data
= (uint8
*) data
;
145 mbuf
->buf_end
= mbuf
->data
+ len
;
146 mbuf
->data_end
= mbuf
->data
+ len
;
147 mbuf
->read_pos
= mbuf
->data
;
149 mbuf
->no_write
= true;
150 mbuf
->own_data
= false;
157 mbuf_grab(MBuf
* mbuf
, int len
, uint8
**data_p
)
159 if (len
> mbuf_avail(mbuf
))
160 len
= mbuf_avail(mbuf
);
162 mbuf
->no_write
= true;
164 *data_p
= mbuf
->read_pos
;
165 mbuf
->read_pos
+= len
;
170 mbuf_rewind(MBuf
* mbuf
)
172 mbuf
->read_pos
= mbuf
->data
;
177 mbuf_steal_data(MBuf
* mbuf
, uint8
**data_p
)
179 int len
= mbuf_size(mbuf
);
181 mbuf
->no_write
= true;
182 mbuf
->own_data
= false;
184 *data_p
= mbuf
->data
;
186 mbuf
->data
= mbuf
->data_end
= mbuf
->read_pos
= mbuf
->buf_end
= NULL
;
198 const PullFilterOps
*op
;
206 pullf_create(PullFilter
** pf_p
, const PullFilterOps
* op
, void *init_arg
, PullFilter
* src
)
212 if (op
->init
!= NULL
)
214 res
= op
->init(&priv
, init_arg
, src
);
224 pf
= px_alloc(sizeof(*pf
));
225 memset(pf
, 0, sizeof(*pf
));
232 pf
->buf
= px_alloc(pf
->buflen
);
245 pullf_free(PullFilter
* pf
)
248 pf
->op
->free(pf
->priv
);
252 memset(pf
->buf
, 0, pf
->buflen
);
256 memset(pf
, 0, sizeof(*pf
));
260 /* may return less data than asked, 0 means eof */
262 pullf_read(PullFilter
* pf
, int len
, uint8
**data_p
)
268 if (pf
->buflen
&& len
> pf
->buflen
)
270 res
= pf
->op
->pull(pf
->priv
, pf
->src
, len
, data_p
,
271 pf
->buf
, pf
->buflen
);
274 res
= pullf_read(pf
->src
, len
, data_p
);
279 pullf_read_max(PullFilter
* pf
, int len
, uint8
**data_p
, uint8
*tmpbuf
)
285 res
= pullf_read(pf
, len
, data_p
);
286 if (res
<= 0 || res
== len
)
289 /* read was shorter, use tmpbuf */
290 memcpy(tmpbuf
, *data_p
, res
);
297 res
= pullf_read(pf
, len
, &tmp
);
300 /* so the caller must clear only on success */
301 memset(tmpbuf
, 0, total
);
306 memcpy(tmpbuf
+ total
, tmp
, res
);
313 * caller wants exatly len bytes and dont bother with references
316 pullf_read_fixed(PullFilter
* src
, int len
, uint8
*dst
)
321 res
= pullf_read_max(src
, len
, &p
, dst
);
326 px_debug("pullf_read_fixed: need=%d got=%d", len
, res
);
327 return PXE_MBUF_SHORT_READ
;
338 pull_from_mbuf(void *arg
, PullFilter
* src
, int len
,
339 uint8
**data_p
, uint8
*buf
, int buflen
)
343 return mbuf_grab(mbuf
, len
, data_p
);
346 static const struct PullFilterOps mbuf_reader
= {
347 NULL
, pull_from_mbuf
, NULL
351 pullf_create_mbuf_reader(PullFilter
** mp_p
, MBuf
* src
)
353 return pullf_create(mp_p
, &mbuf_reader
, src
, NULL
);
364 const PushFilterOps
*op
;
372 pushf_create(PushFilter
** mp_p
, const PushFilterOps
* op
, void *init_arg
, PushFilter
* next
)
378 if (op
->init
!= NULL
)
380 res
= op
->init(next
, init_arg
, &priv
);
390 mp
= px_alloc(sizeof(*mp
));
391 memset(mp
, 0, sizeof(*mp
));
392 mp
->block_size
= res
;
396 if (mp
->block_size
> 0)
398 mp
->buf
= px_alloc(mp
->block_size
);
411 pushf_free(PushFilter
* mp
)
414 mp
->op
->free(mp
->priv
);
418 memset(mp
->buf
, 0, mp
->block_size
);
422 memset(mp
, 0, sizeof(*mp
));
427 pushf_free_all(PushFilter
* mp
)
440 wrap_process(PushFilter
* mp
, const uint8
*data
, int len
)
444 if (mp
->op
->push
!= NULL
)
445 res
= mp
->op
->push(mp
->next
, mp
->priv
, data
, len
);
447 res
= pushf_write(mp
->next
, data
, len
);
453 /* consumes all data, returns len on success */
455 pushf_write(PushFilter
* mp
, const uint8
*data
, int len
)
463 if (mp
->block_size
<= 0)
464 return wrap_process(mp
, data
, len
);
467 * try to empty buffer
469 need
= mp
->block_size
- mp
->pos
;
474 memcpy(mp
->buf
+ mp
->pos
, data
, len
);
478 memcpy(mp
->buf
+ mp
->pos
, data
, need
);
484 * buffer full, process
486 res
= wrap_process(mp
, mp
->buf
, mp
->block_size
);
492 * now process directly from data
496 if (len
> mp
->block_size
)
498 res
= wrap_process(mp
, data
, mp
->block_size
);
501 data
+= mp
->block_size
;
502 len
-= mp
->block_size
;
506 memcpy(mp
->buf
, data
, len
);
515 pushf_flush(PushFilter
* mp
)
521 if (mp
->block_size
> 0)
523 res
= wrap_process(mp
, mp
->buf
, mp
->pos
);
530 res
= mp
->op
->flush(mp
->next
, mp
->priv
);
545 push_into_mbuf(PushFilter
* next
, void *arg
, const uint8
*data
, int len
)
551 res
= mbuf_append(mbuf
, data
, len
);
552 return res
< 0 ? res
: 0;
555 static const struct PushFilterOps mbuf_filter
= {
556 NULL
, push_into_mbuf
, NULL
, NULL
560 pushf_create_mbuf_writer(PushFilter
** res
, MBuf
* dst
)
562 return pushf_create(res
, &mbuf_filter
, dst
, NULL
);