<commit_before>// Copyright (c) 2012, 2017 <NAME>. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license details.

#include "dump.h"

#include <errno.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "cache8.h"
#include "odd.h"
#include "oj.h"
#include "trace.h"
#include "util.h"

// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
#define OJ_INFINITY (1.0 / 0.0)

#define MAX_DEPTH 1000

static const char inf_val[]  = INF_VAL;
static const char ninf_val[] = NINF_VAL;
static const char nan_val[]  = NAN_VAL;

typedef unsigned long ulong;

static size_t hibit_friendly_size(const uint8_t *str, size_t len);
static size_t xss_friendly_size(const uint8_t *str, size_t len);
static size_t ascii_friendly_size(const uint8_t *str, size_t len);

static const char hex_chars[17] = "0123456789abcdef";

// JSON standard except newlines are no escaped
static char newline_friendly_chars[256] = "\
66666666221622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111";

// JSON standard
static char hibit_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111";

// High bit set characters are always encoded as unicode. Worse case is 3
// bytes per character in the output. That makes this conservative.
static char ascii_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111116\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333";

// XSS safe mode
static char xss_friendly_chars[256] = "\
66666666222622666666666666666666\
11211161111111121111111111116161\
11111111111111111111111111112111\
11111111111111111111111111111116\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333";

// JSON XSS combo
static char hixss_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11611111111111111111111111111111";

// Rails XSS combo
static char rails_xss_friendly_chars[256] = "\
66666666222622666666666666666666\
11211161111111111111111111116161\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11611111111111111111111111111111";

// Rails HTML non-escape
static char rails_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111";

static void raise_strict(VALUE obj) {
    rb_raise(rb_eTypeError,
             "Failed to dump %s Object to JSON in strict mode.",
             rb_class2name(rb_obj_class(obj)));
}

inline static size_t calculate_string_size(const uint8_t *str, size_t len, const char * table) {
    size_t size = 0;
    size_t i    = len;

    for (; 3 < i; i -= 4) {
        size += table[*str++];
        size += table[*str++];
        size += table[*str++];
        size += table[*str++];
    }
    for (; 0 < i; i--) {
        size += table[*str++];
    }
    return size - len * (size_t)'0';
}

inline static size_t newline_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, newline_friendly_chars);
}

inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, hibit_friendly_chars);
}

inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, ascii_friendly_chars);
}

inline static size_t xss_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, xss_friendly_chars);
}

inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) {
    size_t size  = 0;
    size_t i     = len;
    bool   check = false;

    for (; 0 < i; str++, i--) {
        size += hixss_friendly_chars[*str];
        if (0 != (0x80 & *str)) {
            check = true;
        }
    }
    return size - len * (size_t)'0' + check;
}

inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
    long    size = 0;
    size_t  i    = len;
    uint8_t hi   = 0;

    for (; 0 < i; str++, i--) {
        size += rails_xss_friendly_chars[*str];
        hi |= *str & 0x80;
    }
    if (0 == hi) {
        return size - len * (size_t)'0';
    }
    return -(size - len * (size_t)'0');
}

inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
    size_t size = calculate_string_size(str, len, rails_friendly_chars);
    return size - len * (size_t)'0';
}

const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
    const char *str = NULL;

    if (AutoNan == opt) {
        switch (mode) {
        case CompatMode: opt = WordNan; break;
        case StrictMode: opt = RaiseNan; break;
        default: break;
        }
    }
    switch (opt) {
    case RaiseNan: raise_strict(obj); break;
    case WordNan:
        if (plus) {
            str   = "Infinity";
            *lenp = 8;<commit_msg>Fix string size calculation (#729)<commit_after>// Copyright (c) 2012, 2017 <NAME>. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license details.

#include "dump.h"

#include <errno.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "cache8.h"
#include "odd.h"
#include "oj.h"
#include "trace.h"
#include "util.h"

// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
#define OJ_INFINITY (1.0 / 0.0)

#define MAX_DEPTH 1000

static const char inf_val[]  = INF_VAL;
static const char ninf_val[] = NINF_VAL;
static const char nan_val[]  = NAN_VAL;

typedef unsigned long ulong;

static size_t hibit_friendly_size(const uint8_t *str, size_t len);
static size_t xss_friendly_size(const uint8_t *str, size_t len);
static size_t ascii_friendly_size(const uint8_t *str, size_t len);

static const char hex_chars[17] = "0123456789abcdef";

// JSON standard except newlines are no escaped
static char newline_friendly_chars[256] = "\
66666666221622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111";

// JSON standard
static char hibit_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111";

// High bit set characters are always encoded as unicode. Worse case is 3
// bytes per character in the output. That makes this conservative.
static char ascii_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111116\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333";

// XSS safe mode
static char xss_friendly_chars[256] = "\
66666666222622666666666666666666\
11211161111111121111111111116161\
11111111111111111111111111112111\
11111111111111111111111111111116\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333\
33333333333333333333333333333333";

// JSON XSS combo
static char hixss_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11611111111111111111111111111111";

// Rails XSS combo
static char rails_xss_friendly_chars[256] = "\
66666666222622666666666666666666\
11211161111111111111111111116161\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11611111111111111111111111111111";

// Rails HTML non-escape
static char rails_friendly_chars[256] = "\
66666666222622666666666666666666\
11211111111111111111111111111111\
11111111111111111111111111112111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111\
11111111111111111111111111111111";

static void raise_strict(VALUE obj) {
    rb_raise(rb_eTypeError,
             "Failed to dump %s Object to JSON in strict mode.",
             rb_class2name(rb_obj_class(obj)));
}

inline static size_t calculate_string_size(const uint8_t *str, size_t len, const char * table) {
    size_t size = 0;
    size_t i    = len;

    for (; 3 < i; i -= 4) {
        size += table[*str++];
        size += table[*str++];
        size += table[*str++];
        size += table[*str++];
    }
    for (; 0 < i; i--) {
        size += table[*str++];
    }
    return size - len * (size_t)'0';
}

inline static size_t newline_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, newline_friendly_chars);
}

inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, hibit_friendly_chars);
}

inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, ascii_friendly_chars);
}

inline static size_t xss_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, xss_friendly_chars);
}

inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) {
    size_t size  = 0;
    size_t i     = len;
    bool   check = false;

    for (; 0 < i; str++, i--) {
        size += hixss_friendly_chars[*str];
        if (0 != (0x80 & *str)) {
            check = true;
        }
    }
    return size - len * (size_t)'0' + check;
}

inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
    long    size = 0;
    size_t  i    = len;
    uint8_t hi   = 0;

    for (; 0 < i; str++, i--) {
        size += rails_xss_friendly_chars[*str];
        hi |= *str & 0x80;
    }
    if (0 == hi) {
        return size - len * (size_t)'0';
    }
    return -(size - len * (size_t)'0');
}

inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
    return calculate_string_size(str, len, rails_friendly_chars);
}

const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
    const char *str = NULL;

    if (AutoNan == opt) {
        switch (mode) {
        case CompatMode: opt = WordNan; break;
        case StrictMode: opt = RaiseNan; break;
        default: break;
        }
    }
    switch (opt) {
    case RaiseNan: raise_strict(obj); break;
    case WordNan:
        if (plus) {
            str   = "Infinity";
            *lenp = 8;
{'fraction_non_alphanumeric': 0.09093951309294737, 'fraction_numerical': 0.31456538107588056, 'mean_word_length': 4.46843549862763, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 128, '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': '5405231', 'n_tokens_mistral': 6826, 'n_tokens_neox': 3736, 'n_words': 956}