Files
rathena/src/common/utils.c
Lemongrass3110 f0ab8d2a52 Overhauled and dropped packet db (#2263)
Adds support for a lot of missing clients and features almost all clients from 2016 and 2017
clientinfo.xml's version value will be ignored from now on
By setting PACKETVER the server will configure everything else on it's own from now on
Dropped is_clientver script command
And a lot more
2017-07-15 22:45:12 +02:00

407 lines
8.9 KiB
C

// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "cbasetypes.h"
#include "showmsg.h"
#include "socket.h"
#include "utils.h"
#include <stdlib.h>
#include <string.h>
#include <math.h> // floor()
#ifdef WIN32
#include "winapi.h"
#ifndef F_OK
#define F_OK 0x0
#endif /* F_OK */
#else
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#endif
/// Dumps given buffer into file pointed to by a handle.
void WriteDump(FILE* fp, const void* buffer, size_t length)
{
size_t i;
char hex[48+1], ascii[16+1];
fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n");
ascii[16] = 0;
for( i = 0; i < length; i++ )
{
char c = RBUFB(buffer,i);
ascii[i%16] = ISCNTRL(c) ? '.' : c;
sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i));
if( (i%16) == 15 )
{
fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii);
}
}
if( (i%16) != 0 )
{
ascii[i%16] = 0;
fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii);
}
}
/// Dumps given buffer on the console.
void ShowDump(const void* buffer, size_t length)
{
size_t i;
char hex[48+1], ascii[16+1];
ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n");
ascii[16] = 0;
for( i = 0; i < length; i++ )
{
char c = RBUFB(buffer,i);
ascii[i%16] = ISCNTRL(c) ? '.' : c;
sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i));
if( (i%16) == 15 )
{
ShowDebug("%03X %s %s\n", i/16, hex, ascii);
}
}
if( (i%16) != 0 )
{
ascii[i%16] = 0;
ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii);
}
}
#ifdef WIN32
static char* checkpath(char *path, const char *srcpath)
{ // just make sure the char*path is not const
char *p=path;
if(NULL!=path && NULL!=srcpath)
while(*srcpath) {
if (*srcpath=='/') {
*p++ = '\\';
srcpath++;
}
else
*p++ = *srcpath++;
}
*p = *srcpath; //EOS
return path;
}
void findfile(const char *p, const char *pat, void (func)(const char*))
{
WIN32_FIND_DATAA FindFileData;
HANDLE hFind;
char tmppath[MAX_PATH+1];
const char *path = (p ==NULL)? "." : p;
const char *pattern = (pat==NULL)? "" : pat;
checkpath(tmppath,path);
if( PATHSEP != tmppath[strlen(tmppath)-1])
strcat(tmppath, "\\*");
else
strcat(tmppath, "*");
hFind = FindFirstFileA(tmppath, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (strcmp(FindFileData.cFileName, ".") == 0)
continue;
if (strcmp(FindFileData.cFileName, "..") == 0)
continue;
sprintf(tmppath,"%s%c%s",path,PATHSEP,FindFileData.cFileName);
if (FindFileData.cFileName && strstr(FindFileData.cFileName, pattern)) {
func( tmppath );
}
if( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
findfile(tmppath, pat, func);
}
}while (FindNextFileA(hFind, &FindFileData) != 0);
FindClose(hFind);
}
return;
}
/**
* Check if the path is a directory or file
* @param filepath: Location of file
* @return 0 = Error
* 1 = Directory
* 2 = File
* 3 = File but doesn't exist
*/
int check_filepath(const char* filepath)
{
DWORD Attribute;
if (Attribute = GetFileAttributes(filepath)) {
if ((Attribute&INVALID_FILE_ATTRIBUTES) && GetLastError() == ERROR_FILE_NOT_FOUND) {
SetLastError(0);
return 3;
} else if (Attribute&FILE_ATTRIBUTE_DIRECTORY)
return 1;
else
return 2;
}
return 0;
}
#else
#define MAX_DIR_PATH 2048
/**
* Check if the path is a directory or file
* @param filepath: Location of file
* @return 0 = Error
* 1 = Directory
* 2 = File
* 3 = Neither a file or directory
*/
int check_filepath(const char* filepath)
{
struct stat s;
if (stat(filepath, &s) == 0) {
if (s.st_mode&S_IFDIR)
return 1;
else if (s.st_mode&S_IFREG)
return 2;
else
return 3;
}
return 0;
}
static char* checkpath(char *path, const char*srcpath)
{ // just make sure the char*path is not const
char *p=path;
if(NULL!=path && NULL!=srcpath)
while(*srcpath) {
if (*srcpath=='\\') {
*p++ = '/';
srcpath++;
}
else
*p++ = *srcpath++;
}
*p = *srcpath; //EOS
return path;
}
void findfile(const char *p, const char *pat, void (func)(const char*))
{
DIR* dir; // pointer to the scanned directory.
struct dirent* entry; // pointer to one directory entry.
struct stat dir_stat; // used by stat().
char tmppath[MAX_DIR_PATH+1];
char path[MAX_DIR_PATH+1]= ".";
const char *pattern = (pat==NULL)? "" : pat;
if(p!=NULL) strcpy(path,p);
// open the directory for reading
dir = opendir( checkpath(path, path) );
if (!dir) {
ShowError("Cannot read directory '%s'\n", path);
return;
}
// scan the directory, traversing each sub-directory
// matching the pattern for each file name.
while ((entry = readdir(dir))) {
// skip the "." and ".." entries.
if (strcmp(entry->d_name, ".") == 0)
continue;
if (strcmp(entry->d_name, "..") == 0)
continue;
sprintf(tmppath,"%s%c%s",path, PATHSEP, entry->d_name);
// check if the pattern matchs.
if (entry->d_name && strstr(entry->d_name, pattern)) {
func( tmppath );
}
// check if it is a directory.
if (stat(tmppath, &dir_stat) == -1) {
ShowError("stat error %s\n': ", tmppath);
continue;
}
// is this a directory?
if (S_ISDIR(dir_stat.st_mode)) {
// decent recursivly
findfile(tmppath, pat, func);
}
}//end while
closedir(dir);
}
#endif
bool exists(const char* filename)
{
return !access(filename, F_OK);
}
uint8 GetByte(uint32 val, int idx)
{
switch( idx )
{
case 0: return (uint8)( (val & 0x000000FF) );
case 1: return (uint8)( (val & 0x0000FF00) >> 0x08 );
case 2: return (uint8)( (val & 0x00FF0000) >> 0x10 );
case 3: return (uint8)( (val & 0xFF000000) >> 0x18 );
default:
#if defined(DEBUG)
ShowDebug("GetByte: invalid index (idx=%d)\n", idx);
#endif
return 0;
}
}
uint16 GetWord(uint32 val, int idx)
{
switch( idx )
{
case 0: return (uint16)( (val & 0x0000FFFF) );
case 1: return (uint16)( (val & 0xFFFF0000) >> 0x10 );
default:
#if defined(DEBUG)
ShowDebug("GetWord: invalid index (idx=%d)\n", idx);
#endif
return 0;
}
}
uint16 MakeWord(uint8 byte0, uint8 byte1)
{
return byte0 | (byte1 << 0x08);
}
uint32 MakeDWord(uint16 word0, uint16 word1)
{
return
( (uint32)(word0 ) )|
( (uint32)(word1 << 0x10) );
}
/*************************************
* Big-endian compatibility functions *
*************************************/
// Converts an int16 from current machine order to little-endian
int16 MakeShortLE(int16 val)
{
unsigned char buf[2];
buf[0] = (unsigned char)( (val & 0x00FF) );
buf[1] = (unsigned char)( (val & 0xFF00) >> 0x08 );
return *((int16*)buf);
}
// Converts an int32 from current machine order to little-endian
int32 MakeLongLE(int32 val)
{
unsigned char buf[4];
buf[0] = (unsigned char)( (val & 0x000000FF) );
buf[1] = (unsigned char)( (val & 0x0000FF00) >> 0x08 );
buf[2] = (unsigned char)( (val & 0x00FF0000) >> 0x10 );
buf[3] = (unsigned char)( (val & 0xFF000000) >> 0x18 );
return *((int32*)buf);
}
// Reads an uint16 in little-endian from the buffer
uint16 GetUShort(const unsigned char* buf)
{
return ( ((uint16)(buf[0])) )
|( ((uint16)(buf[1])) << 0x08 );
}
// Reads an uint32 in little-endian from the buffer
uint32 GetULong(const unsigned char* buf)
{
return ( ((uint32)(buf[0])) )
|( ((uint32)(buf[1])) << 0x08 )
|( ((uint32)(buf[2])) << 0x10 )
|( ((uint32)(buf[3])) << 0x18 );
}
// Reads an int32 in little-endian from the buffer
int32 GetLong(const unsigned char* buf)
{
return (int32)GetULong(buf);
}
// Reads a float (32 bits) from the buffer
float GetFloat(const unsigned char* buf)
{
uint32 val = GetULong(buf);
return *((float*)(void*)&val);
}
/// calculates the value of A / B, in percent (rounded down)
unsigned int get_percentage(const unsigned int A, const unsigned int B)
{
double result;
if( B == 0 )
{
ShowError("get_percentage(): divison by zero! (A=%u,B=%u)\n", A, B);
return ~0U;
}
result = 100 * ((double)A / (double)B);
if( result > UINT_MAX )
{
ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result);
return UINT_MAX;
}
return (unsigned int)floor(result);
}
/**
* Calculates the Levenshtein distance of two strings.
* @author http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C
*/
int levenshtein(const char *s1, const char *s2) {
unsigned int s1len, s2len, x, y, lastdiag, olddiag, i;
unsigned int *column;
s1len = strlen(s1);
s2len = strlen(s2);
column = malloc((s1len+1) * sizeof(unsigned int));
for (y = 1; y <= s1len; y++)
column[y] = y;
for (x = 1; x <= s2len; x++) {
column[0] = x;
for (y = 1, lastdiag = x-1; y <= s1len; y++) {
olddiag = column[y];
column[y] = min(min(column[y] + 1, column[y-1] + 1), lastdiag + (s1[y-1] == s2[x-1] ? 0 : 1));
lastdiag = olddiag;
}
}
i = column[s1len];
free(column);
return i;
}