/* Copyright 2006 Joachim Zobel . * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "frag_buffer.h" /* * The fragment. */ typedef struct { apr_size_t len ; const char *str ; } frag_t; /* * frag_create */ frag_buffer_t *frag_create(apr_pool_t *p) { return apr_array_make(p, 20, sizeof(frag_t)) ; } /* * frag_write */ void frag_write(frag_buffer_t *frag_buf, const char *str, apr_size_t len) { frag_t *f = apr_array_push(frag_buf) ; f->str = str ; f->len = len ; } /* * frag_write_enc */ apr_size_t frag_write_enc(frag_buffer_t *frag_buf, const char *str) { const char *pos = str ; apr_size_t len = 0 ; apr_size_t rv = 0 ; while (*pos) { len = strcspn(pos, "<>&\"") ; rv += len ; frag_write(frag_buf, pos, len) ; pos += len ; switch (*pos) { case '<': frag_write(frag_buf, "<", 4); rv+= 4; break ; case '>': frag_write(frag_buf, ">", 4); rv+= 4; break ; case '&': frag_write(frag_buf, "&", 5); rv+= 5; break ; case '"': frag_write(frag_buf, """, 6); rv+= 6; break ; case '\0': pos-- ; /* pre undo ++ */ break ; } pos++ ; } return rv ; } /* * frag_write_dec */ apr_size_t frag_write_dec(frag_buffer_t *frag_buf, const char *str) { const char *pos = str ; const char *new_pos= NULL ; apr_size_t len = 0 ; apr_size_t rv = 0 ; while (pos && *pos) { // search the next entity new_pos = strchr(pos, '&') ; if (new_pos) { len = new_pos - pos ; rv += len ; frag_write(frag_buf, pos, len) ; switch (new_pos[1]) { case 'l': if (strncmp(new_pos, "<", 4) == 0) { new_pos += 4; frag_write(frag_buf, "<", 1); rv+= 1; } break ; case 'g': if (strncmp(new_pos, ">", 4) == 0) { new_pos += 4; frag_write(frag_buf, ">", 1); rv+= 1; } break ; case 'a': if (strncmp(new_pos, "&", 5) == 0) { new_pos += 5; frag_write(frag_buf, "&", 1); rv+= 1; } break ; case 'q': if (strncmp(new_pos, """, 6) == 0) { new_pos += 6; frag_write(frag_buf, "\"", 1); rv+= 1; } break ; default: break; } } else { len = strlen(pos) ; rv += len ; frag_write(frag_buf, pos, len) ; } pos = new_pos ; } return rv ; } /* * frag_clean */ void frag_clean(frag_buffer_t *frag_buf) { frag_buf->nelts = 0; } /* * frag_to_buffer */ apr_off_t frag_to_buffer(frag_buffer_t *frag_buf, apr_off_t offset, char *buf, apr_size_t avail) { const frag_t *frag = (void *)frag_buf->elts ; const frag_t *end = frag + frag_buf->nelts ; apr_off_t off_loc = offset ; apr_size_t avl_loc = avail ; apr_size_t needed = 0 ; for (; fraglen) { /* start writing */ if (frag->len - off_loc < avl_loc) { /* write the fragment */ memcpy(buf, frag->str+off_loc, frag->len - off_loc) ; buf += frag->len - off_loc ; /* and subtract it from the available space */ avl_loc -= frag->len - off_loc ; } else { /* not enough space left */ if (avl_loc > 0) { memcpy(buf, frag->str+off_loc, avl_loc) ; buf += avl_loc ; } /* add up what is still needed */ needed += frag->len - avl_loc ; avl_loc = 0 ; } off_loc = 0 ; } else { /* skip */ off_loc -= frag->len ; } } return avl_loc - needed ; } /* * frag_length */ apr_off_t frag_length(frag_buffer_t *frag_buf) { return -frag_to_buffer(frag_buf, 0, NULL, 0) ; }