<commit_before>// ------------------------------------------------------------------------------------------------
#include "Misc/Player.hpp"
#include "Base/Color3.hpp"
#include "Core.hpp"

// ------------------------------------------------------------------------------------------------
#include <cstring>
#include <algorithm>

// ------------------------------------------------------------------------------------------------
namespace SqMod {

// ------------------------------------------------------------------------------------------------
static String CS_Skin_Names[] = {
"<NAME>",        "Cop",                   "SWAT",                  "FBI",                   "Army",
"Paramedic",             "Firefighter",           "Golf Guy #1",           "",                      "Bum Lady #1",
"Bum Lady #2",           "Punk #1",               "Lawyer",                "Spanish Lady #1",       "Spanish Lady #2",
"Cool Guy #1",           "Arabic Guy",            "Beach Lady #1",         "Beach Lady #2",         "Beach Guy #1",
"Beach Guy #2",          "Office Lady #1",        "Waitress #1",           "Food Lady",             "Prostitute #1",
"Bum Lady #3",           "Bum Guy #1",            "Garbageman #1",         "Taxi Driver #1",        "Haitian #1",
"Criminal #1",           "Hood Lady",             "Granny #1",             "Businessman #1",        "Church Guy",
"Club Lady",             "Church Lady",           "Pimp",                  "Beach Lady #3",         "Beach Guy #3",
"Beach Lady #4",         "Beach Guy #4",          "Businessman #2",        "Prostitute #2",         "Bum Lady #4",
"Bum Guy #2",            "Haitian #2",            "Construction Worker #1","Punk #2",               "Prostitute #3",
"Granny #2",             "Punk #3",               "Businessman #3",        "Spanish Lady #3",       "Spanish Lady #4",
"Cool Guy #2",           "Businessman #4",        "Beach Lady #5",         "Beach Guy #5",          "Beach Lady #6",
"Beach Guy #6",          "Construction Worker #2","Golf Guy #2",           "Golf Lady",             "Golf Guy #3",
"Beach Lady #7",         "Beach Guy #7",          "Office Lady #2",        "Businessman #5",        "Businessman #6",
"Prostitute #2",         "Bum Lady #4",           "Bum Guy #3",            "Spanish Guy",           "Taxi Driver #2",
"Gym Lady",              "Gym Guy",               "Skate Lady",            "Skate Guy",             "Shopper #1",
"Shopper #2",            "Tourist #1",            "Tourist #2",            "Cuban #1",              "Cuban #2",
"Haitian #3",            "Haitian #4",            "Shark #1",              "Shark #2",              "Diaz Guy #1",
"Diaz Guy #2",           "DBP Security #1",       "DBP Security #2",       "Biker #1",              "Biker #2",
"Vercetti Guy #1",       "Vercetti Guy #2",       "Undercover Cop #1",     "Undercover Cop #2",     "Undercover Cop #3",
"Undercover Cop #4",     "Undercover Cop #5",     "Undercover Cop #6",     "<NAME>",              "Cool Guy #3",
"Prostitute #3",         "Prostitute #4",         "Love Fist #1",          "<NAME>",         "<NAME>",
"Hilary",                "Love Fist #2",          "Phil",                  "<NAME>",          "Sonny",
"Lance",                 "Mercedes",              "Love Fist #3",          "<NAME>",            "Lance (Cop)",
"Lance",                 "Cortez",                "Love Fist #4",          "Columbian Guy #1",      "Hilary (Robber)",
"Mercedes",              "Cam",                   "<NAME>)",          "Phil (One Arm)",        "Phil (Robber)",
"Cool Guy #4",           "Pizza Man",             "Taxi Driver #1",        "Taxi Driver #2",        "Sailor #1",
"Sailor #2",             "Sailor #3",             "Chef",                  "Criminal #2",           "French Guy",
"Garbageman #2",         "Haitian #5",            "Waitress #2",           "Sonny Guy #1",          "Sonny Guy #2",
"Sonny Guy #3",          "Columbian Guy #2",      "Haitian #6",            "Beach Guy #8",          "Garbageman #3",
"Garbageman #4",         "Garbageman #5",         "Tranny",                "Thug #5",               "SpandEx Guy #1",
"SpandEx Guy #2",        "Stripper #1",           "Stripper #2",           "Stripper #3",           "Store Clerk",
""
};

// ------------------------------------------------------------------------------------------------
CCStr GetSkinName(Uint32 id)
{
    return (id > 159) ? _SC("") : CS_Skin_Names[id].c_str();
}

// ------------------------------------------------------------------------------------------------
void SetSkinName(Uint32 id, CCStr name)
{
    if (id <= 159)
        CS_Skin_Names[id].assign(name);
}

// ------------------------------------------------------------------------------------------------
Int32 GetSkinID(CCStr name)
{
    // Clone the string into an editable version
    String str(name);
    // Strip non alphanumeric characters from the name
    str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
    // Convert the string to lowercase
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    // See if we still have a valid name after the cleanup
    if(str.empty())
        return SQMOD_UNKNOWN;
    // Grab the actual length of the string
    Uint32 len = static_cast< Uint32 >(str.length());
    // Get the most significant characters used to identify a skin
    CharT a = str[0], b = 0, c = 0, d = str[len-1];
    // Look for deeper specifiers
    if (len >= 3)
    {
        b = str[1];
        c = str[2];
    }
    else if (len >= 2)
        b = str[1];
    // Search for a pattern in the name
    switch (a)
    {
        // [A]lex Srub, [A]rabic guy, [A]rmy
        case 'a':
            switch (b)
            {
                // [Al]ex [S]rub
                case 'l':
                case 's': return SQMOD_SKIN_ALEX_SRUB;
                // [A]rabic [g]uy
                case 'g': return SQMOD_SKIN_ARABIC_GUY;
                // [Ara]bic guy, [Arm]y
                case 'r':
                    if (c == 'a') return SQMOD_SKIN_ARABIC_GUY;
                    else if (c == 'm') return SQMOD_SKIN_ARMY;
            }
        // [B]each guy (#1|A)/(#2|B)/(#3|C)/(#4|D)/(#5|E)/(#6|F)/(#7|G)/(#8|H)
        // [B]each lady (#1|A)/(#2|B)/(#3|C)/(#4|D)/(#5|E)/(#6|F)/(#7|G)
        // [B]iker (#1|A)/(#2|B)
        // [B]um guy (#1|A)/(#2|B)/(#3|C)<commit_msg>Adjust range checks when converting skin name to identifier.<commit_after>// ------------------------------------------------------------------------------------------------
#include "Misc/Player.hpp"
#include "Base/Color3.hpp"
#include "Core.hpp"

// ------------------------------------------------------------------------------------------------
#include <cstring>
#include <algorithm>

// ------------------------------------------------------------------------------------------------
namespace SqMod {

// ------------------------------------------------------------------------------------------------
static String CS_Skin_Names[] = {
"<NAME>",        "Cop",                   "SWAT",                  "FBI",                   "Army",
"Paramedic",             "Firefighter",           "Golf Guy #1",           "",                      "Bum Lady #1",
"Bum Lady #2",           "Punk #1",               "Lawyer",                "Spanish Lady #1",       "Spanish Lady #2",
"Cool Guy #1",           "Arabic Guy",            "Beach Lady #1",         "Beach Lady #2",         "Beach Guy #1",
"Beach Guy #2",          "Office Lady #1",        "Waitress #1",           "Food Lady",             "Prostitute #1",
"Bum Lady #3",           "Bum Guy #1",            "Garbageman #1",         "Taxi Driver #1",        "Haitian #1",
"Criminal #1",           "Hood Lady",             "Granny #1",             "Businessman #1",        "Church Guy",
"Club Lady",             "Church Lady",           "Pimp",                  "Beach Lady #3",         "Beach Guy #3",
"Beach Lady #4",         "Beach Guy #4",          "Businessman #2",        "Prostitute #2",         "Bum Lady #4",
"Bum Guy #2",            "Haitian #2",            "Construction Worker #1","Punk #2",               "Prostitute #3",
"Granny #2",             "Punk #3",               "Businessman #3",        "Spanish Lady #3",       "Spanish Lady #4",
"Cool Guy #2",           "Businessman #4",        "Beach Lady #5",         "Beach Guy #5",          "Beach Lady #6",
"Beach Guy #6",          "Construction Worker #2","Golf Guy #2",           "Golf Lady",             "Golf Guy #3",
"Beach Lady #7",         "Beach Guy #7",          "Office Lady #2",        "Businessman #5",        "Businessman #6",
"Prostitute #2",         "Bum Lady #4",           "Bum Guy #3",            "Spanish Guy",           "Taxi Driver #2",
"Gym Lady",              "Gym Guy",               "Skate Lady",            "Skate Guy",             "Shopper #1",
"Shopper #2",            "Tourist #1",            "Tourist #2",            "Cuban #1",              "Cuban #2",
"Haitian #3",            "Haitian #4",            "Shark #1",              "Shark #2",              "Diaz Guy #1",
"Diaz Guy #2",           "DBP Security #1",       "DBP Security #2",       "Biker #1",              "Biker #2",
"Vercetti Guy #1",       "Vercetti Guy #2",       "Undercover Cop #1",     "Undercover Cop #2",     "Undercover Cop #3",
"Undercover Cop #4",     "Undercover Cop #5",     "Undercover Cop #6",     "<NAME>",              "Cool Guy #3",
"Prostitute #3",         "Prostitute #4",         "Love Fist #1",          "<NAME>",         "<NAME>",
"Hilary",                "Love Fist #2",          "Phil",                  "Rockstar Guy",          "Sonny",
"Lance",                 "Mercedes",              "Love Fist #3",          "<NAME>",            "Lance (Cop)",
"Lance",                 "Cortez",                "Love Fist #4",          "Columbian Guy #1",      "Hilary (Robber)",
"Mercedes",              "Cam",                   "Cam (Robber)",          "Phil (One Arm)",        "Phil (Robber)",
"Cool Guy #4",           "Pizza Man",             "Taxi Driver #1",        "Taxi Driver #2",        "Sailor #1",
"Sailor #2",             "Sailor #3",             "Chef",                  "Criminal #2",           "French Guy",
"Garbageman #2",         "Haitian #5",            "Waitress #2",           "Sonny Guy #1",          "Sonny Guy #2",
"Sonny Guy #3",          "Columbian Guy #2",      "Haitian #6",            "Beach Guy #8",          "Garbageman #3",
"Garbageman #4",         "Garbageman #5",         "Tranny",                "Thug #5",               "SpandEx Guy #1",
"SpandEx Guy #2",        "Stripper #1",           "Stripper #2",           "Stripper #3",           "Store Clerk",
""
};

// ------------------------------------------------------------------------------------------------
CCStr GetSkinName(Uint32 id)
{
    return (id > 159) ? _SC("") : CS_Skin_Names[id].c_str();
}

// ------------------------------------------------------------------------------------------------
void SetSkinName(Uint32 id, CCStr name)
{
    if (id <= 159)
    {
        CS_Skin_Names[id].assign(name);
    }
}

// ------------------------------------------------------------------------------------------------
Int32 GetSkinID(CCStr name)
{
    // Clone the string into an editable version
    String str(name);
    // Strip non alphanumeric characters from the name
    str.erase(std::remove_if(str.begin(), str.end(), std::not1(std::ptr_fun(::isalnum))), str.end());
    // Convert the string to lowercase
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    // See if we still have a valid name after the cleanup
    if(str.empty())
    {
        return SQMOD_UNKNOWN;
    }
    // Grab the actual length of the string
    const Uint32 len = static_cast< Uint32 >(str.length());
    // Get the most significant characters used to identify a skin
    CharT a = str[0], b = 0, c = 0, d = str[len-1];
    // Look for deeper specifiers
    if (len > 2)
    {
        b = str[1];
        c = str[2];
    }
    else if (len > 1)
    {
        b = str[1];
    }
    // Search for a pattern in the name
    switch (a)
    {
        // [A]lex Srub, [A]rabic guy, [A]rmy
        case 'a':
            switch (b)
            {
                // [Al]ex [S]rub
                case 'l':
                case 's': return SQMOD_SKIN_ALEX_SRUB;
                // [A]rabic [g]uy
                case 'g': return SQMOD_SKIN_ARABIC_GUY;
                // [Ara]bic guy, [Arm]y
                case 'r':
                    if (c == 'a') return SQMOD_SKIN_ARABIC_GUY;
                    else if (c == 'm') return SQMOD_SKIN_ARMY;
            }
        // [B]each guy (#1|A)/(#2|B)/(#3|C)/(#4|D)/(#5|E)/(#6|F)/(#7|G)/(#8|H)
        // [B]each lady (#1|A)/(#2|B)/(#3|C)/(#4|D)/(#5|E)/(#6|F)/(#7|G)
        // [B]iker (#1|A)/(#2|B)
        // [B]um guy (#1|A)/(#2|B)/(#3|C)
{'fraction_non_alphanumeric': 0.2591155934833204, 'fraction_numerical': 0.024980605120248255, 'mean_word_length': 1.1254740313272877, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5683608', 'n_tokens_mistral': 4030, 'n_tokens_neox': 3835, 'n_words': 1094}