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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.