buffer/apr_buffer.c (315 lines of code) (raw):
/* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "apr.h"
#include "apr_lib.h"
#if 0
#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
#endif
#include "apr_want.h"
#include "apr_buffer.h"
#include "apr_encode.h"
#include "apr_strings.h"
#define APR_BUFFER_MAX (APR_SIZE_MAX/2)
APU_DECLARE(apr_status_t) apr_buffer_mem_set(apr_buffer_t *buf,
void *mem, apr_size_t len)
{
if (len > APR_BUFFER_MAX) {
return APR_EINVAL;
}
buf->d.mem = mem;
buf->size = len;
buf->zero_terminated = 0;
return APR_SUCCESS;
}
APU_DECLARE(apr_status_t) apr_buffer_mem_create(apr_buffer_t **mb,
apr_pool_t *pool,
void *mem, apr_size_t len)
{
apr_buffer_t *buf;
if (len > APR_BUFFER_MAX) {
return APR_EINVAL;
}
buf = apr_palloc(pool, sizeof(apr_buffer_t));
if (buf) {
buf->d.mem = mem;
buf->size = len;
buf->zero_terminated = 0;
*mb = buf;
}
else {
return APR_ENOMEM;
}
return APR_SUCCESS;
}
APU_DECLARE(apr_status_t) apr_buffer_str_set(apr_buffer_t *buf,
char *str, apr_ssize_t len)
{
if (!str) {
buf->d.str = NULL;
buf->size = 0;
buf->zero_terminated = 0;
}
else if (len < 0) {
apr_size_t slen = strlen(str);
if (slen <= APR_BUFFER_MAX) {
buf->d.str = str;
buf->size = slen;
buf->zero_terminated = 1;
}
else {
return APR_EINVAL;
}
}
else {
if (str[len]) {
return APR_EINVAL;
}
buf->d.str = str;
buf->size = len;
buf->zero_terminated = 1;
}
return APR_SUCCESS;
}
APU_DECLARE(apr_status_t) apr_buffer_str_create(apr_buffer_t **sb,
apr_pool_t *pool,
char *str, apr_ssize_t len)
{
apr_buffer_t *buf;
apr_int64_t size;
apr_size_t slen;
unsigned int zero_terminated;
if (!str) {
str = NULL;
size = 0;
zero_terminated = 0;
}
if (APR_BUFFER_STRING == len) {
slen = strlen(str);
if (slen <= APR_BUFFER_MAX) {
size = slen;
zero_terminated = 1;
}
else {
return APR_EINVAL;
}
}
else if (str[len]) {
return APR_EINVAL;
}
else {
size = (apr_size_t)len;
}
buf = apr_palloc(pool, sizeof(apr_buffer_t));
if (buf) {
buf->d.str = str;
buf->size = size;
buf->zero_terminated = zero_terminated;
*sb = buf;
}
else {
return APR_ENOMEM;
}
return APR_SUCCESS;
}
APU_DECLARE(apr_status_t) apr_buffer_null_create(apr_buffer_t **nb,
apr_pool_t *pool)
{
apr_buffer_t *buf;
buf = apr_pcalloc(pool, sizeof(apr_buffer_t));
if (!buf) {
return APR_ENOMEM;
}
*nb = buf;
return APR_SUCCESS;
}
APU_DECLARE(apr_size_t) apr_buffer_len(const apr_buffer_t *buf)
{
return buf->size;
}
APU_DECLARE(apr_size_t) apr_buffer_allocated(const apr_buffer_t *buf)
{
return buf->size + buf->zero_terminated;
}
APU_DECLARE(int) apr_buffer_is_null(const apr_buffer_t *buf)
{
if (!buf->d.mem) {
return 1;
}
else {
return 0;
}
}
APU_DECLARE(int) apr_buffer_is_str(const apr_buffer_t *buf)
{
return buf->zero_terminated;
}
APU_DECLARE(char *) apr_buffer_str(const apr_buffer_t *buf)
{
if (buf->zero_terminated) {
return buf->d.str;
}
else {
return NULL;
}
}
APU_DECLARE(char *) apr_buffer_pstrdup(apr_pool_t *pool, const apr_buffer_t *buf)
{
return apr_pstrmemdup(pool, buf->d.str, buf->size);
}
APU_DECLARE(void *) apr_buffer_mem(const apr_buffer_t *buf, apr_size_t *size)
{
if (size) {
size[0] = apr_buffer_len(buf);
}
return buf->d.mem;
}
APU_DECLARE(void *) apr_buffer_pmemdup(apr_pool_t *pool, const apr_buffer_t *buf, apr_size_t *size)
{
apr_size_t len = apr_buffer_len(buf);
if (size) {
size[0] = len;
}
return apr_pmemdup(pool, buf->d.mem, len);
}
APU_DECLARE(apr_status_t) apr_buffer_arraydup(apr_buffer_t **out,
const apr_buffer_t *in,
apr_buffer_alloc alloc, void *ctx,
int nelts)
{
apr_buffer_t *dst = alloc(ctx, nelts * sizeof(apr_buffer_t));
const apr_buffer_t *src = in;
*out = dst;
if (!dst) {
return APR_ENOMEM;
}
int i;
for (i = 0; i < nelts; i++) {
/* absolute value is size of mem buffer including optional terminating zero */
apr_size_t size = src->size + src->zero_terminated;
void *mem = alloc(ctx, size);
if (!mem) {
return APR_ENOMEM;
}
memcpy(mem, src->d.mem, size);
dst->zero_terminated = src->zero_terminated;
dst->size = src->size;
dst->d.mem = mem;
src++;
dst++;
}
return APR_SUCCESS;
}
APU_DECLARE(apr_status_t) apr_buffer_dup(apr_buffer_t **out,
const apr_buffer_t *in,
apr_buffer_alloc alloc, void *ctx)
{
return apr_buffer_arraydup(out, in, alloc, ctx, 1);
}
APU_DECLARE(apr_buffer_t *) apr_buffer_cpy(apr_buffer_t *dst,
const apr_buffer_t *src,
apr_buffer_alloc alloc, void *ctx)
{
if (!src) {
dst->d.mem = NULL;
dst->size = 0;
dst->zero_terminated = 0;
}
else if (!alloc) {
dst->d.mem = src->d.mem;
dst->size = src->size;
dst->zero_terminated = src->zero_terminated;
}
else {
/* absolute value is size of mem buffer including optional terminating zero */
apr_size_t size = src->size + src->zero_terminated;
void *mem = alloc(ctx, size);
memcpy(mem, src->d.mem, size);
dst->zero_terminated = src->zero_terminated;
dst->size = src->size;
dst->d.mem = mem;
}
return dst;
}
APU_DECLARE(int) apr_buffer_cmp(const apr_buffer_t *src,
const apr_buffer_t *dst)
{
if (!src || !src->d.mem) {
return (!dst || !dst->d.mem) ? 0 : -1;
}
else {
if (!dst || !dst->d.mem) {
return 1;
}
else {
apr_size_t slen = apr_buffer_len(src);
apr_size_t dlen = apr_buffer_len(dst);
if (slen != dlen) {
return slen < dlen ? -1 : 1;
}
else {
return memcmp(src->d.mem, dst->d.mem, slen);
}
}
}
}
APU_DECLARE(char *) apr_buffer_pstrncat(apr_pool_t *p, const apr_buffer_t *buf,
int nelts, const char *sep, int flags,
apr_size_t *nbytes)
{
const apr_buffer_t *src = buf;
apr_size_t seplen = sep ? strlen(sep) : 0;
apr_size_t size = 0;
char *dst, *str;
int i;
for (i = 0; i < nelts; i++) {
if (i > 0) {
size += seplen;
}
if (src->zero_terminated) {
size += src->size;
}
else {
if (APR_BUFFER_PLAIN == flags) {
size += src->size;
}
else if (APR_BUFFER_BASE64 == flags) {
apr_size_t b64len;
if (APR_SUCCESS != apr_encode_base64(NULL, src->d.mem, src->size,
APR_ENCODE_NONE, &b64len)) {
return NULL;
}
size += b64len - 1;
}
}
src++;
}
if (nbytes) {
*nbytes = size;
}
str = dst = apr_palloc(p, size + 1);
src = buf;
for (i = 0; i < nelts; i++) {
if (i > 0 && sep) {
memcpy(dst, sep, seplen);
dst += seplen;
}
if (src->zero_terminated) {
memcpy(dst, src->d.str, src->size);
dst += src->size;
}
else {
if (APR_BUFFER_PLAIN == flags) {
memcpy(dst, src->d.mem, src->size);
dst += src->size;
}
else if (APR_BUFFER_BASE64 == flags) {
apr_size_t b64len;
if (APR_SUCCESS != apr_encode_base64(dst, src->d.mem, src->size,
APR_ENCODE_NONE, &b64len)) {
return NULL;
}
dst += b64len;
}
}
src++;
}
dst[0] = 0;
return str;
}