<commit_before>/*
 * Copyright (c) 2014 DeNA Co., Ltd.
 *
 * 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 <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "h2o.h"

void h2o_fatal(const char *msg)
{
    fprintf(stderr, "fatal:%s\n", msg);
    abort();
}

int h2o_lcstris_core(const char *target, const char *test, size_t test_len)
{
    for (; test_len != 0; --test_len)
        if (h2o_tolower(*target++) != *test++)
            return 0;
    return 1;
}

h2o_buf_t h2o_strdup(h2o_mempool_t *pool, const char *s, size_t slen)
{
    h2o_buf_t ret;

    if (slen == SIZE_MAX)
        slen = strlen(s);

    if (pool != NULL) {
        ret.base = h2o_mempool_alloc(pool, slen + 1);
    } else {
        ret.base = h2o_malloc(slen + 1);
    }
    memcpy(ret.base, s, slen);
    ret.base[slen] = '\0';
    ret.len = slen;
    return ret;
}

__attribute__((format (printf, 2, 3)))
h2o_buf_t h2o_sprintf(h2o_mempool_t *pool, const char *fmt, ...)
{
    char smallbuf[1024];
    va_list arg;
    int len;
    h2o_buf_t ret;

    ret.base = NULL;
    ret.len = 0;

    // determine the length (as well as fill-in the small buf)
    va_start(arg, fmt);
    len = vsnprintf(smallbuf, sizeof(smallbuf), fmt, arg);
    va_end(arg);
    if (len == -1)
        h2o_fatal("sprintf usage error");

    // allocate
    if (pool != NULL) {
        ret.base = h2o_mempool_alloc(pool, len + 1);
    } else {
        ret.base = h2o_malloc(len + 1);
    }
    ret.len = len;

    // copy from small buf or reprint
    if (len < sizeof(smallbuf)) {
            memcpy(ret.base, smallbuf, len + 1);
    } else {
            va_start(arg, fmt);
            vsnprintf(ret.base, len + 1, fmt, arg);
            va_end(arg);
    }

    return ret;
}

__attribute__((format (printf, 3, 4)))
size_t h2o_snprintf(char *buf, size_t bufsz, const char *fmt, ...)
{
    va_list arg;
    int len;

    va_start(arg, fmt);
    len = vsnprintf(buf, bufsz, fmt, arg);
    va_end(arg);
    if (len == -1)
        h2o_fatal("sprintf usage error");
    else if (len + 1 > bufsz)
        h2o_fatal("buffer too small");
    return len;
}

static uint32_t decode_base64url_quad(const char *src)
{
    const char *src_end = src + 4;
    uint32_t decoded = 0;

    while (1) {
        if ('A' <= *src && *src <= 'Z') {
            decoded |= *src - 'A';
        } else if ('a' <= *src && *src <= 'z') {
            decoded |= *src - 'a' + 26;
        } else if ('0' <= *src && *src <= '9') {
            decoded |= *src - '0' + 52;
        } else if (*src == '-') {
            decoded |= 62;
        } else if (*src == '_') {
            decoded |= 63;
#if 1 /* curl uses normal base64 */
        } else if (*src == '+') {
            decoded |= 62;
        } else if (*src == '/') {
            decoded |= 63;
#endif
        } else {
            return UINT32_MAX;
        }
        if (++src == src_end)
            break;
        decoded <<= 6;
    }

    return decoded;
}

h2o_buf_t h2o_decode_base64url(h2o_mempool_t *pool, const char *src, size_t len)
{
    h2o_buf_t decoded;
    uint32_t t;
    uint8_t* dst;
    char remaining_input[4];

    decoded.len = len * 3 / 4;
    decoded.base = h2o_mempool_alloc(pool, decoded.len);
    dst = (uint8_t*)decoded.base;

    while (len >= 4) {
        if ((t = decode_base64url_quad(src)) == UINT32_MAX)
            goto Error;
        *dst++ = t >> 16;
        *dst++ = t >> 8;
        *dst++ = t;
        src += 4;
        len -= 4;
    }
    switch (len) {
    case 0:
        break;
    case 1:
        goto Error;
    case 2:
        remaining_input[0] = *src++;
        remaining_input[1] = *src++;
        remaining_input[2] = 'A';
        remaining_input[3] = 'A';
        if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
            goto Error;
        *dst++ = t >> 16;
        break;
    case 3:
        remaining_input[0] = *src++;
        remaining_input[1] = *src++;
        remaining_input[2] = *src++;
        remaining_input[3] = 'A';
        if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
            goto Error;
        *dst++ = t >> 16;
        *dst++ = t >> 8;
        break;
    }

    assert((char*)dst - decoded.base == decoded.len);

    return decoded;

Error:
    return h2o_buf_init(NULL, 0);
}

void h2o_base64_encode(char *dst, const uint8_t *src, size_t len, int url_encoded)
{
    static const char *MAP =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";
    static const char *MAP_URL_ENCODED =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789-_";

    const char *map = url_encoded ? MAP_URL_ENCODED : MAP;
    uint32_t quad;

    for (; len >= 3; src += 3, len -= 3) {
        quad = ((uint32_t)src[0] << 16)
            | ((uint32_t)src[1] << 8)
            | src[2];
        *dst++ = map[quad >> 18];
        *dst++ = map[(quad >> 12) & 63];
        *dst++ = map[(quad >> 6) & 63];
        *dst++ = map[quad & 63];
    }
    if (len != 0) {<commit_msg>terminate the returned string for the ease of use (h2o_decode_base64url)<commit_after>/*
 * Copyright (c) 2014 DeNA Co., Ltd.
 *
 * 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 <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "h2o.h"

void h2o_fatal(const char *msg)
{
    fprintf(stderr, "fatal:%s\n", msg);
    abort();
}

int h2o_lcstris_core(const char *target, const char *test, size_t test_len)
{
    for (; test_len != 0; --test_len)
        if (h2o_tolower(*target++) != *test++)
            return 0;
    return 1;
}

h2o_buf_t h2o_strdup(h2o_mempool_t *pool, const char *s, size_t slen)
{
    h2o_buf_t ret;

    if (slen == SIZE_MAX)
        slen = strlen(s);

    if (pool != NULL) {
        ret.base = h2o_mempool_alloc(pool, slen + 1);
    } else {
        ret.base = h2o_malloc(slen + 1);
    }
    memcpy(ret.base, s, slen);
    ret.base[slen] = '\0';
    ret.len = slen;
    return ret;
}

__attribute__((format (printf, 2, 3)))
h2o_buf_t h2o_sprintf(h2o_mempool_t *pool, const char *fmt, ...)
{
    char smallbuf[1024];
    va_list arg;
    int len;
    h2o_buf_t ret;

    ret.base = NULL;
    ret.len = 0;

    // determine the length (as well as fill-in the small buf)
    va_start(arg, fmt);
    len = vsnprintf(smallbuf, sizeof(smallbuf), fmt, arg);
    va_end(arg);
    if (len == -1)
        h2o_fatal("sprintf usage error");

    // allocate
    if (pool != NULL) {
        ret.base = h2o_mempool_alloc(pool, len + 1);
    } else {
        ret.base = h2o_malloc(len + 1);
    }
    ret.len = len;

    // copy from small buf or reprint
    if (len < sizeof(smallbuf)) {
            memcpy(ret.base, smallbuf, len + 1);
    } else {
            va_start(arg, fmt);
            vsnprintf(ret.base, len + 1, fmt, arg);
            va_end(arg);
    }

    return ret;
}

__attribute__((format (printf, 3, 4)))
size_t h2o_snprintf(char *buf, size_t bufsz, const char *fmt, ...)
{
    va_list arg;
    int len;

    va_start(arg, fmt);
    len = vsnprintf(buf, bufsz, fmt, arg);
    va_end(arg);
    if (len == -1)
        h2o_fatal("sprintf usage error");
    else if (len + 1 > bufsz)
        h2o_fatal("buffer too small");
    return len;
}

static uint32_t decode_base64url_quad(const char *src)
{
    const char *src_end = src + 4;
    uint32_t decoded = 0;

    while (1) {
        if ('A' <= *src && *src <= 'Z') {
            decoded |= *src - 'A';
        } else if ('a' <= *src && *src <= 'z') {
            decoded |= *src - 'a' + 26;
        } else if ('0' <= *src && *src <= '9') {
            decoded |= *src - '0' + 52;
        } else if (*src == '-') {
            decoded |= 62;
        } else if (*src == '_') {
            decoded |= 63;
#if 1 /* curl uses normal base64 */
        } else if (*src == '+') {
            decoded |= 62;
        } else if (*src == '/') {
            decoded |= 63;
#endif
        } else {
            return UINT32_MAX;
        }
        if (++src == src_end)
            break;
        decoded <<= 6;
    }

    return decoded;
}

h2o_buf_t h2o_decode_base64url(h2o_mempool_t *pool, const char *src, size_t len)
{
    h2o_buf_t decoded;
    uint32_t t;
    uint8_t* dst;
    char remaining_input[4];

    decoded.len = len * 3 / 4;
    decoded.base = h2o_mempool_alloc(pool, decoded.len + 1);
    dst = (uint8_t*)decoded.base;

    while (len >= 4) {
        if ((t = decode_base64url_quad(src)) == UINT32_MAX)
            goto Error;
        *dst++ = t >> 16;
        *dst++ = t >> 8;
        *dst++ = t;
        src += 4;
        len -= 4;
    }
    switch (len) {
    case 0:
        break;
    case 1:
        goto Error;
    case 2:
        remaining_input[0] = *src++;
        remaining_input[1] = *src++;
        remaining_input[2] = 'A';
        remaining_input[3] = 'A';
        if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
            goto Error;
        *dst++ = t >> 16;
        break;
    case 3:
        remaining_input[0] = *src++;
        remaining_input[1] = *src++;
        remaining_input[2] = *src++;
        remaining_input[3] = 'A';
        if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
            goto Error;
        *dst++ = t >> 16;
        *dst++ = t >> 8;
        break;
    }

    assert((char*)dst - decoded.base == decoded.len);
    decoded.base[decoded.len] = '\0';

    return decoded;

Error:
    return h2o_buf_init(NULL, 0);
}

void h2o_base64_encode(char *dst, const uint8_t *src, size_t len, int url_encoded)
{
    static const char *MAP =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";
    static const char *MAP_URL_ENCODED =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789-_";

    const char *map = url_encoded ? MAP_URL_ENCODED : MAP;
    uint32_t quad;

    for (; len >= 3; src += 3, len -= 3) {
        quad = ((uint32_t)src[0] << 16)
            | ((uint32_t)src[1] << 8)
            | src[2];
        *dst++ = map[quad >> 18];
        *dst++ = map[(quad >> 12) & 63];
        *dst++ = map[(quad >> 6) & 63];
        *dst++ = map[quad & 63];
    }
    if (len != 0) {
{'fraction_non_alphanumeric': 0.1378026070763501, 'fraction_numerical': 0.029228402558497287, 'mean_word_length': 2.267724867724868, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2162267', 'n_tokens_mistral': 4635, 'n_tokens_neox': 4325, 'n_words': 1252}