/*------------------------------------------------------------------
* strncpy_s.c / strcpy_s.c / strnlen_s.c
*
* October 2008, Bo Berry
*
* Copyright � 2008-2011 by Cisco Systems, Inc
* All rights reserved.

* safe_str_constraint.c
*
=============================
Safe String Library license:
=============================
MIT License

Copyright (c) 2014-2018 Intel Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================================================

Copyright (C) 2012, 2013 Cisco Systems
All rights reserved.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "EbString.h"

/* SAFE STRING LIBRARY */

static constraint_handler_t str_handler = NULL;

void
EbHevcInvoke_safe_str_constraint_handler(const char *msg,
void *ptr,
errno_t error)
{
    if (NULL != str_handler)
        str_handler(msg, ptr, error);
    else
        sl_default_handler(msg, ptr, error);
}

void EbHevcIgnore_handler_s(const char *msg, void *ptr, errno_t error)
{
    (void)msg;
    (void)ptr;
    (void)error;
    sldebug_printf("IGNORE CONSTRAINT HANDLER: (%u) %s\n", error,
        (msg) ? msg : "Null message");
    return;
}

errno_t
EbHevcStrncpy_ss(char *dest, rsize_t dmax, const char *src, rsize_t slen)
{
    rsize_t orig_dmax;
    char *orig_dest;
    const char *overlap_bumper;

    if (dest == NULL) {
        EbHevcInvoke_safe_str_constraint_handler("strncpy_ss: dest is null",
            NULL, ESNULLP);
        return RCNEGATE(ESNULLP);
    }

    if (dmax == 0) {
        EbHevcInvoke_safe_str_constraint_handler("strncpy_ss: dmax is 0",
            NULL, ESZEROL);
        return RCNEGATE(ESZEROL);
    }

    if (dmax > RSIZE_MAX_STR) {
        EbHevcInvoke_safe_str_constraint_handler("strncpy_ss: dmax exceeds max",
            NULL, ESLEMAX);
        return RCNEGATE(ESLEMAX);
    }

    /* hold base in case src was not copied */
    orig_dmax = dmax;
    orig_dest = dest;

    if (src == NULL) {
        EbHevcHandle_error(orig_dest, orig_dmax, (char*) ("strncpy_ss: "
            "src is null"),
            ESNULLP);
        return RCNEGATE(ESNULLP);
    }

    if (slen == 0) {
        EbHevcHandle_error(orig_dest, orig_dmax, (char*)("strncpy_ss: "
            "slen is zero"),
            ESZEROL);
        return RCNEGATE(ESZEROL);
    }

    if (slen > RSIZE_MAX_STR) {
        EbHevcHandle_error(orig_dest, orig_dmax, (char*)("strncpy_ss: "
            "slen exceeds max"),
            ESLEMAX);
        return RCNEGATE(ESLEMAX);
    }

    if (dest < src) {
        overlap_bumper = src;

        while (dmax > 0) {
            if (dest == overlap_bumper) {
                EbHevcHandle_error(orig_dest, orig_dmax, (char*)("strncpy_ss: "
                    "overlapping objects"),
                    ESOVRLP);
                return RCNEGATE(ESOVRLP);
            }

            if (slen == 0) {
                /*
                * Copying truncated to slen chars.  Note that the TR says to
                * copy slen chars plus the null char.  We null the slack.
                */
                *dest = '\0';
                return RCNEGATE(EOK);
            }

            *dest = *src;
            if (*dest == '\0')
                return RCNEGATE(EOK);
            dmax--;
            slen--;
            dest++;
            src++;
        }
    }
    else {
        overlap_bumper = dest;

        while (dmax > 0) {
            if (src == overlap_bumper) {
                EbHevcHandle_error(orig_dest, orig_dmax, (char*)( "strncpy_s: "
                    "overlapping objects"),
                    ESOVRLP);
                return RCNEGATE(ESOVRLP);
            }

            if (slen == 0) {
                /*
                * Copying truncated to slen chars.  Note that the TR says to
                * copy slen chars plus the null char.  We null the slack.
                */
                *dest = '\0';
                return RCNEGATE(EOK);
            }

            *dest = *src;
            if (*dest == '\0')
                return RCNEGATE(EOK);
            dmax--;
            slen--;
            dest++;
            src++;
        }
    }

    /*
    * the entire src was not copied, so zero the string
    */
    EbHevcHandle_error(orig_dest, orig_dmax, (char*)("strncpy_ss: not enough "
        "space for src"),
        ESNOSPC);
    return RCNEGATE(ESNOSPC);
}

errno_t
EbHevcStrcpy_ss(char *dest, rsize_t dmax, const char *src)
{
    rsize_t orig_dmax;
    char *orig_dest;
    const char *overlap_bumper;

    if (dest == NULL) {
        EbHevcInvoke_safe_str_constraint_handler((char*)("strcpy_ss: dest is null"),
            NULL, ESNULLP);
        return RCNEGATE(ESNULLP);
    }

    if (dmax == 0) {
        EbHevcInvoke_safe_str_constraint_handler((char*)("strcpy_ss: dmax is 0"),
            NULL, ESZEROL);
        return RCNEGATE(ESZEROL);
    }

    if (dmax > RSIZE_MAX_STR) {
        EbHevcInvoke_safe_str_constraint_handler((char*)("strcpy_ss: dmax exceeds max"),
            NULL, ESLEMAX);
        return RCNEGATE(ESLEMAX);
    }

    if (src == NULL) {
        *dest = '\0';
        EbHevcInvoke_safe_str_constraint_handler((char*)("strcpy_ss: src is null"),
            NULL, ESNULLP);
        return RCNEGATE(ESNULLP);
    }

    if (dest == src)
        return RCNEGATE(EOK);
    /* hold base of dest in case src was not copied */
    orig_dmax = dmax;
    orig_dest = dest;

    if (dest < src) {
        overlap_bumper = src;

        while (dmax > 0) {
            if (dest == overlap_bumper) {
                EbHevcHandle_error(orig_dest, orig_dmax, (char*)("strcpy_ss: "
                    "overlapping objects"),
                    ESOVRLP);
                return RCNEGATE(ESOVRLP);
            }

            *dest = *src;
            if (*dest == '\0')
                return RCNEGATE(EOK);
            dmax--;
            dest++;
            src++;
        }
    }
    else {
        overlap_bumper = dest;

        while (dmax > 0) {
            if (src == overlap_bumper) {
                EbHevcHandle_error(orig_dest, orig_dmax, (char*)("strcpy_ss: "
                    "overlapping objects"),
                    ESOVRLP);
                return RCNEGATE(ESOVRLP);
            }

            *dest = *src;
            if (*dest == '\0')
                return RCNEGATE(EOK);
            dmax--;
            dest++;
            src++;
        }
    }

    /*
    * the entire src must have been copied, if not reset dest
    * to null the string.
    */
    EbHevcHandle_error(orig_dest, orig_dmax, (char*)("strcpy_ss: not "
        "enough space for src"),
        ESNOSPC);
    return RCNEGATE(ESNOSPC);
}

rsize_t
EbHevcStrnlen_ss(const char *dest, rsize_t dmax)
{
    rsize_t count;

    if (dest == NULL)
        return RCNEGATE(0);
    if (dmax == 0) {
        EbHevcInvoke_safe_str_constraint_handler((char*)("strnlen_ss: dmax is 0"),
            NULL, ESZEROL);
        return RCNEGATE(0);
    }

    if (dmax > RSIZE_MAX_STR) {
        EbHevcInvoke_safe_str_constraint_handler((char*)("strnlen_ss: dmax exceeds max"),
            NULL, ESLEMAX);
        return RCNEGATE(0);
    }

    count = 0;
    while (*dest && dmax) {
        count++;
        dmax--;
        dest++;
    }

    return RCNEGATE(count);
}

/* SAFE STRING LIBRARY */
