Re: svn commit: r1917047 - in /apr/apr/trunk: CHANGES buffer/ buffer/apr_buffer.c build.conf include/apr_buffer.h test/Makefile.in test/Makefile.win test/NWGNUaprtest test/abts_tests.h test/testbuffer.c test/testutil.h
Ruediger Pluem <[email protected]>
| Newsgroups | gmane.comp.apache.apr.devel |
|---|---|
| Message-ID | <[email protected]> |
On 4/16/24 10:54 PM, [email protected] wrote: > Author: minfrin > Date: Tue Apr 16 20:54:51 2024 > New Revision: 1917047 > > URL: http://svn.apache.org/viewvc?rev=1917047&view=rev > Log: > Add the apr_buffer API. > > An APR buffer is a structure that can contain a zero terminated string, or > a non zero terminated block of memory, and allow such structures to be > passed around and handled in a memory efficient way. > > We allow two buffers to be compared without duplicating strings. Memory > buffers can be converted to string buffers safely. The contents of buffers > can be copied into and out of other systems like caches using memory > allocation callbacks. > > Used by the new LDAP API, where string support has been deprecated in > favour of fixed sized buffers. > > Added: > apr/apr/trunk/buffer/ > apr/apr/trunk/buffer/apr_buffer.c (with props) > apr/apr/trunk/include/apr_buffer.h (with props) > apr/apr/trunk/test/testbuffer.c (with props) > Modified: > apr/apr/trunk/CHANGES > apr/apr/trunk/build.conf > apr/apr/trunk/test/Makefile.in > apr/apr/trunk/test/Makefile.win > apr/apr/trunk/test/NWGNUaprtest > apr/apr/trunk/test/abts_tests.h > apr/apr/trunk/test/testutil.h > > Modified: apr/apr/trunk/CHANGES > > Added: apr/apr/trunk/buffer/apr_buffer.c > URL: http://svn.apache.org/viewvc/apr/apr/trunk/buffer/apr_buffer.c?rev=1917047&view=auto > ============================================================================== > --- apr/apr/trunk/buffer/apr_buffer.c (added) > +++ apr/apr/trunk/buffer/apr_buffer.c Tue Apr 16 20:54:51 2024 > @@ -0,0 +1,408 @@ > +/* 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" > +#include "apr_private.h" > + > + > +APR_DECLARE(apr_status_t) apr_buffer_mem_set(apr_buffer_t *buf, > + void *mem, apr_size_t len) > +{ > + > + if (len > APR_INT64_MAX) { > + return APR_EINVAL; > + } > + > + buf->d.mem = mem; > + buf->size = len; > + > + return APR_SUCCESS; > +} > + > +APR_DECLARE(apr_buffer_t *) apr_buffer_mem_make(apr_pool_t *pool, > + void *mem, apr_size_t len) > +{ > + apr_buffer_t *buf; > + > + if (len > APR_INT64_MAX) { > + return NULL; > + } > + > + buf = apr_palloc(pool, sizeof(apr_buffer_t)); > + > + if (buf) { > + buf->d.mem = mem; > + buf->size = len; > + } > + > + return buf; > +} > + > +APR_DECLARE(apr_status_t) apr_buffer_str_set(apr_buffer_t *buf, > + char *str, apr_ssize_t len) > +{ > + > + if (len > APR_INT64_MAX) { > + return APR_EINVAL; > + } > + > + if (!str) { > + buf->d.str = NULL; > + buf->size = 0; > + } > + else if (len < 0) { > + apr_size_t slen = strlen(str); > + if (slen <= APR_INT64_MAX) { > + buf->d.str = str; > + buf->size = -(slen + 1); > + } > + else { > + buf->d.str = NULL; > + buf->size = 0; > + } > + } > + else { > + buf->d.str = str; > + buf->size = -(len + 1); > + } > + > + return APR_SUCCESS; > +} > + > +APR_DECLARE(apr_buffer_t *) apr_buffer_str_make(apr_pool_t *pool, > + char *str, apr_ssize_t len) > +{ > + apr_buffer_t *buf; > + apr_int64_t size; > + apr_size_t slen; > + > + if (!str) { > + str = NULL; > + size = 0; > + } > + if (APR_BUFFER_STRING == len && !str[0]) { > + size = len; > + } Is the above just a performance shortcut? > + else if (len < 0) { > + slen = strlen(str); > + if (slen <= APR_INT64_MAX) { > + size = -(slen + 1); > + } > + else { > + return NULL; > + } > + } > + else { > + size = -(len + 1); > + } > + > + buf = apr_palloc(pool, sizeof(apr_buffer_t)); > + > + if (buf) { > + buf->d.str = str; > + buf->size = size; > + } > + > + return buf; > +} > + > +APR_DECLARE(apr_buffer_t *) apr_buffer_null_make(apr_pool_t *pool) > +{ > + return apr_pcalloc(pool, sizeof(apr_buffer_t)); > +} > + > +APR_DECLARE(apr_size_t) apr_buffer_len(const apr_buffer_t *buf) > +{ > + if (buf->size < 0) { > + return (apr_size_t)((-buf->size) - 1); > + } > + else { > + return (apr_size_t)buf->size; > + } > +} > + > +APR_DECLARE(apr_size_t) apr_buffer_allocated(const apr_buffer_t *buf) > +{ > + if (buf->size < 0) { > + return (apr_size_t)((-buf->size)); > + } > + else { > + return (apr_size_t)buf->size; > + } > +} > + > +APR_DECLARE(int) apr_buffer_is_null(const apr_buffer_t *buf) > +{ > + if (!buf->d.mem) { > + return 1; > + } > + else { > + return 0; > + } > +} > + > +APR_DECLARE(int) apr_buffer_is_str(const apr_buffer_t *buf) > +{ > + if (buf->size < 0) { > + return 1; > + } > + else { > + return 0; > + } > +} > + > +APR_DECLARE(char *) apr_buffer_str(const apr_buffer_t *buf) > +{ > + if (buf->size < 0) { > + return buf->d.str; > + } > + else { > + return NULL; > + } > +} > + > +APR_DECLARE(char *) apr_buffer_pstrdup(apr_pool_t *pool, const apr_buffer_t *buf) > +{ > + if (buf->size < 0) { > + return apr_pstrmemdup(pool, buf->d.str, -(buf->size + 1)); > + } > + else { > + return apr_pstrmemdup(pool, buf->d.str, buf->size); > + } > +} > + > +APR_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; > +} > + > +APR_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); > +} > + > +APR_DECLARE(apr_buffer_t *) apr_buffer_arraydup(const apr_buffer_t *src, > + apr_buffer_alloc alloc, void *ctx, > + int nelts) > +{ > + apr_buffer_t *dst = alloc(ctx, nelts * sizeof(apr_buffer_t)); > + apr_buffer_t *d = dst; > + > + int i; > + for (i = 0; i < nelts; i++) { > + > + /* absolute value is size of mem buffer including optional terminating zero */ > + apr_int64_t size = src->size < 0 ? -src->size : src->size; > + > + void *mem = alloc(ctx, size); > + memcpy(mem, src->d.mem, size); > + > + dst->size = src->size; > + dst->d.mem = mem; > + > + src++; > + dst++; > + } > + > + return d; > +} > + > +APR_DECLARE(apr_buffer_t *) apr_buffer_dup(const apr_buffer_t *buf, > + apr_buffer_alloc alloc, void *ctx) > +{ > + return apr_buffer_arraydup(buf, alloc, ctx, 1); > +} > + > +APR_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; > + > + } > + else if (!alloc) { > + > + dst->d.mem = src->d.mem; > + dst->size = src->size; > + > + } > + else { > + > + /* absolute value is size of mem buffer including optional terminating zero */ > + apr_int64_t size = src->size < 0 ? -src->size : src->size; > + > + void *mem = alloc(ctx, size); > + memcpy(mem, src->d.mem, size); > + > + dst->size = src->size; > + dst->d.mem = mem; Wouldn't it make sense to put the above 5 lines into a macro or a static inline function to reuse it here and in apr_buffer_arraydup? > + > + } > + > + return dst; > +} > + > + > +APR_DECLARE(int) apr_buffer_cmp(const apr_buffer_t *src, > + const apr_buffer_t *dst) > +{ > + 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 if (src->d.mem == dst->d.mem) { > + /* identical data or both NULL */ > + return 0; > + } > + else if (!src->d.mem) { > + return -1; Can this case happen? We know that src->d.mem != dst->d.mem and if src->d.mem == NULL slen should be != dlen. > + } > + else if (!dst->d.mem) { > + return 1; See above. > + } > + else { > + return memcmp(src->d.mem, dst->d.mem, slen); > + } > +} > + > + > +APR_DECLARE(int) apr_buffer_ncmp(const apr_buffer_t *src, > + const apr_buffer_t *dst) > +{ > + if (!src || !src->d.mem) { > + if (!dst || !dst->d.mem) { > + return 0; > + } > + else { > + return -1; > + } > + } > + else { > + if (!dst || !dst->d.mem) { > + return 1; > + } > + else { > + return apr_buffer_cmp(src, dst); > + } > + } > +} > + > +APR_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->size < 0) { > + size += (-src->size) - 1; > + } > + else { > + if (APR_BUFFER_NONE == 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) { > + strncpy(dst, sep, seplen); > + dst += seplen; > + } > + > + if (src->size < 0) { > + strncpy(dst, src->d.str, (-src->size) - 1); Why can't we use memcpy here? Do we assume that src->d.str contains a \0 prior to (-src->size) - 1? > + dst += (-src->size) - 1; > + } > + else { > + if (APR_BUFFER_NONE == flags) { > + memcpy(dst, src->d.mem, 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; > +} > + > Regards Rüdiger