mirror of
https://github.com/holub/mame
synced 2025-05-17 19:24:59 +03:00
hashfile moved from MESS to emu section (needed for now in image support until softlist implementation is finished), this doesn't affect mame side (no whatsnew)
This commit is contained in:
parent
861db1eb49
commit
d2a7b5f332
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -604,6 +604,8 @@ src/emu/fileio.c svneol=native#text/plain
|
||||
src/emu/fileio.h svneol=native#text/plain
|
||||
src/emu/hash.c svneol=native#text/plain
|
||||
src/emu/hash.h svneol=native#text/plain
|
||||
src/emu/hashfile.c svneol=native#text/plain
|
||||
src/emu/hashfile.h svneol=native#text/plain
|
||||
src/emu/info.c svneol=native#text/plain
|
||||
src/emu/info.h svneol=native#text/plain
|
||||
src/emu/inptport.c svneol=native#text/plain
|
||||
|
@ -63,6 +63,7 @@ EMUOBJS = \
|
||||
$(EMUOBJ)/emupal.o \
|
||||
$(EMUOBJ)/fileio.o \
|
||||
$(EMUOBJ)/hash.o \
|
||||
$(EMUOBJ)/hashfile.o \
|
||||
$(EMUOBJ)/info.o \
|
||||
$(EMUOBJ)/input.o \
|
||||
$(EMUOBJ)/inputseq.o \
|
||||
|
591
src/emu/hashfile.c
Normal file
591
src/emu/hashfile.c
Normal file
@ -0,0 +1,591 @@
|
||||
/*********************************************************************
|
||||
|
||||
hashfile.c
|
||||
|
||||
Code for parsing hash info (*.hsi) files
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "hashfile.h"
|
||||
#include "pool.h"
|
||||
#include "expat.h"
|
||||
#include "emuopts.h"
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
struct _hash_file
|
||||
{
|
||||
mame_file *file;
|
||||
object_pool *pool;
|
||||
unsigned int functions[IO_COUNT];
|
||||
|
||||
hash_info **preloaded_hashes;
|
||||
int preloaded_hash_count;
|
||||
|
||||
void (*error_proc)(const char *message);
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum hash_parse_position
|
||||
{
|
||||
POS_ROOT,
|
||||
POS_MAIN,
|
||||
POS_HASH
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct hash_parse_state
|
||||
{
|
||||
XML_Parser parser;
|
||||
hash_file *hashfile;
|
||||
int done;
|
||||
|
||||
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const char *hash);
|
||||
void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi);
|
||||
void (*error_proc)(const char *message);
|
||||
void *param;
|
||||
|
||||
enum hash_parse_position pos;
|
||||
char **text_dest;
|
||||
hash_info *hi;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
static void *expat_malloc(size_t size);
|
||||
static void *expat_realloc(void *ptr, size_t size);
|
||||
static void expat_free(void *ptr);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CORE IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
parse_error
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void ATTR_PRINTF(2,3) parse_error(struct hash_parse_state *state, const char *fmt, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list va;
|
||||
|
||||
if (state->error_proc)
|
||||
{
|
||||
va_start(va, fmt);
|
||||
vsnprintf(buf, ARRAY_LENGTH(buf), fmt, va);
|
||||
va_end(va);
|
||||
(*state->error_proc)(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
unknown_tag
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void unknown_tag(struct hash_parse_state *state, const char *tagname)
|
||||
{
|
||||
parse_error(state, "[%lu:%lu]: Unknown tag: %s\n",
|
||||
XML_GetCurrentLineNumber(state->parser),
|
||||
XML_GetCurrentColumnNumber(state->parser),
|
||||
tagname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
unknown_attribute
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void unknown_attribute(struct hash_parse_state *state, const char *attrname)
|
||||
{
|
||||
parse_error(state, "[%lu:%lu]: Unknown attribute: %s\n",
|
||||
XML_GetCurrentLineNumber(state->parser),
|
||||
XML_GetCurrentColumnNumber(state->parser),
|
||||
attrname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
unknown_attribute_value
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void unknown_attribute_value(struct hash_parse_state *state,
|
||||
const char *attrname, const char *attrvalue)
|
||||
{
|
||||
parse_error(state, "[%lu:%lu]: Unknown attribute value: %s\n",
|
||||
XML_GetCurrentLineNumber(state->parser),
|
||||
XML_GetCurrentColumnNumber(state->parser),
|
||||
attrvalue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
start_handler
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void start_handler(void *data, const char *tagname, const char **attributes)
|
||||
{
|
||||
struct hash_parse_state *state = (struct hash_parse_state *) data;
|
||||
const char *name;
|
||||
hash_info *hi;
|
||||
char **text_dest;
|
||||
char hash_string[HASH_BUF_SIZE];
|
||||
unsigned int functions, all_functions;
|
||||
iodevice_t device;
|
||||
int i;
|
||||
|
||||
switch(state->pos)
|
||||
{
|
||||
case POS_ROOT:
|
||||
if (!strcmp(tagname, "hashfile"))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
unknown_tag(state, tagname);
|
||||
}
|
||||
break;
|
||||
|
||||
case POS_MAIN:
|
||||
if (!strcmp(tagname, "hash"))
|
||||
{
|
||||
// we are now examining a hash tag
|
||||
name = NULL;
|
||||
memset(hash_string, 0, sizeof(hash_string));
|
||||
all_functions = 0;
|
||||
device = IO_COUNT;
|
||||
|
||||
while(attributes[0])
|
||||
{
|
||||
functions = 0;
|
||||
if (!strcmp(attributes[0], "name"))
|
||||
{
|
||||
/* name attribute */
|
||||
name = attributes[1];
|
||||
}
|
||||
else if (!strcmp(attributes[0], "crc32"))
|
||||
{
|
||||
/* crc32 attribute */
|
||||
functions = HASH_CRC;
|
||||
}
|
||||
else if (!strcmp(attributes[0], "md5"))
|
||||
{
|
||||
/* md5 attribute */
|
||||
functions = HASH_MD5;
|
||||
}
|
||||
else if (!strcmp(attributes[0], "sha1"))
|
||||
{
|
||||
/* sha1 attribute */
|
||||
functions = HASH_SHA1;
|
||||
}
|
||||
else if (!strcmp(attributes[0], "type"))
|
||||
{
|
||||
/* type attribute */
|
||||
i = 0;//device_typeid(attributes[1]);
|
||||
if (i < 0)
|
||||
unknown_attribute_value(state, attributes[0], attributes[1]);
|
||||
else
|
||||
device = (iodevice_t) i;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unknown attribute */
|
||||
unknown_attribute(state, attributes[0]);
|
||||
}
|
||||
|
||||
if (functions)
|
||||
{
|
||||
hash_data_insert_printable_checksum(hash_string, functions, attributes[1]);
|
||||
all_functions |= functions;
|
||||
}
|
||||
|
||||
attributes += 2;
|
||||
}
|
||||
|
||||
if (device == IO_COUNT)
|
||||
{
|
||||
for (i = 0; i < IO_COUNT; i++)
|
||||
state->hashfile->functions[i] |= all_functions;
|
||||
}
|
||||
else
|
||||
state->hashfile->functions[device] |= all_functions;
|
||||
|
||||
/* do we use this hash? */
|
||||
if (!state->selector_proc || state->selector_proc(state->hashfile, state->param, name, hash_string))
|
||||
{
|
||||
hi = (hash_info*)pool_malloc_lib(state->hashfile->pool, sizeof(hash_info));
|
||||
if (!hi)
|
||||
return;
|
||||
memset(hi, 0, sizeof(*hi));
|
||||
|
||||
hi->longname = pool_strdup_lib(state->hashfile->pool, name);
|
||||
if (!hi->longname)
|
||||
return;
|
||||
|
||||
strcpy(hi->hash, hash_string);
|
||||
state->hi = hi;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unknown_tag(state, tagname);
|
||||
}
|
||||
break;
|
||||
|
||||
case POS_HASH:
|
||||
text_dest = NULL;
|
||||
|
||||
if (!strcmp(tagname, "year"))
|
||||
text_dest = (char **) &state->hi->year;
|
||||
else if (!strcmp(tagname, "manufacturer"))
|
||||
text_dest = (char **) &state->hi->manufacturer;
|
||||
else if (!strcmp(tagname, "status"))
|
||||
text_dest = (char **) &state->hi->playable;
|
||||
else if (!strcmp(tagname, "pcb"))
|
||||
text_dest = (char **) &state->hi->pcb;
|
||||
else if (!strcmp(tagname, "extrainfo"))
|
||||
text_dest = (char **) &state->hi->extrainfo;
|
||||
else
|
||||
unknown_tag(state, tagname);
|
||||
|
||||
if (text_dest && state->hi)
|
||||
state->text_dest = text_dest;
|
||||
break;
|
||||
}
|
||||
state->pos = (hash_parse_position) (state->pos + 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
end_handler
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void end_handler(void *data, const char *name)
|
||||
{
|
||||
struct hash_parse_state *state = (struct hash_parse_state *) data;
|
||||
state->text_dest = NULL;
|
||||
|
||||
state->pos = (hash_parse_position) (state->pos - 1);
|
||||
switch(state->pos)
|
||||
{
|
||||
case POS_ROOT:
|
||||
case POS_HASH:
|
||||
break;
|
||||
|
||||
case POS_MAIN:
|
||||
if (state->hi)
|
||||
{
|
||||
if (state->use_proc)
|
||||
(*state->use_proc)(state->hashfile, state->param, state->hi);
|
||||
state->hi = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
data_handler
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void data_handler(void *data, const XML_Char *s, int len)
|
||||
{
|
||||
struct hash_parse_state *state = (struct hash_parse_state *) data;
|
||||
int text_len;
|
||||
char *text;
|
||||
|
||||
if (state->text_dest)
|
||||
{
|
||||
text = *state->text_dest;
|
||||
|
||||
text_len = text ? strlen(text) : 0;
|
||||
text = (char*)pool_realloc_lib(state->hashfile->pool, text, text_len + len + 1);
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
memcpy(&text[text_len], s, len);
|
||||
text[text_len + len] = '\0';
|
||||
*state->text_dest = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
hashfile_parse
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void hashfile_parse(hash_file *hashfile,
|
||||
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const char *hash),
|
||||
void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi),
|
||||
void (*error_proc)(const char *message),
|
||||
void *param)
|
||||
{
|
||||
struct hash_parse_state state;
|
||||
char buf[1024];
|
||||
UINT32 len;
|
||||
XML_Memory_Handling_Suite memcallbacks;
|
||||
|
||||
mame_fseek(hashfile->file, 0, SEEK_SET);
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.hashfile = hashfile;
|
||||
state.selector_proc = selector_proc;
|
||||
state.use_proc = use_proc;
|
||||
state.error_proc = error_proc;
|
||||
state.param = param;
|
||||
|
||||
/* create the XML parser */
|
||||
memcallbacks.malloc_fcn = expat_malloc;
|
||||
memcallbacks.realloc_fcn = expat_realloc;
|
||||
memcallbacks.free_fcn = expat_free;
|
||||
state.parser = XML_ParserCreate_MM(NULL, &memcallbacks, NULL);
|
||||
if (!state.parser)
|
||||
goto done;
|
||||
|
||||
XML_SetUserData(state.parser, &state);
|
||||
XML_SetElementHandler(state.parser, start_handler, end_handler);
|
||||
XML_SetCharacterDataHandler(state.parser, data_handler);
|
||||
|
||||
while(!state.done)
|
||||
{
|
||||
len = mame_fread(hashfile->file, buf, sizeof(buf));
|
||||
state.done = mame_feof(hashfile->file);
|
||||
if (XML_Parse(state.parser, buf, len, state.done) == XML_STATUS_ERROR)
|
||||
{
|
||||
parse_error(&state, "[%lu:%lu]: %s\n",
|
||||
XML_GetCurrentLineNumber(state.parser),
|
||||
XML_GetCurrentColumnNumber(state.parser),
|
||||
XML_ErrorString(XML_GetErrorCode(state.parser)));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (state.parser)
|
||||
XML_ParserFree(state.parser);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
preload_use_proc
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void preload_use_proc(hash_file *hashfile, void *param, hash_info *hi)
|
||||
{
|
||||
hash_info **new_preloaded_hashes;
|
||||
|
||||
new_preloaded_hashes = (hash_info **)pool_realloc_lib(hashfile->pool, hashfile->preloaded_hashes,
|
||||
(hashfile->preloaded_hash_count + 1) * sizeof(*new_preloaded_hashes));
|
||||
if (!new_preloaded_hashes)
|
||||
return;
|
||||
|
||||
hashfile->preloaded_hashes = new_preloaded_hashes;
|
||||
hashfile->preloaded_hashes[hashfile->preloaded_hash_count++] = hi;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
hashfile_open_options
|
||||
-------------------------------------------------*/
|
||||
|
||||
hash_file *hashfile_open_options(core_options *opts, const char *sysname, int is_preload,
|
||||
void (*error_proc)(const char *message))
|
||||
{
|
||||
file_error filerr;
|
||||
astring *fname;
|
||||
hash_file *hashfile = NULL;
|
||||
object_pool *pool = NULL;
|
||||
|
||||
/* create a pool for this hash file */
|
||||
pool = pool_alloc_lib(error_proc);
|
||||
if (!pool)
|
||||
goto error;
|
||||
|
||||
/* allocate space for this hash file */
|
||||
hashfile = (hash_file *) pool_malloc_lib(pool, sizeof(*hashfile));
|
||||
if (!hashfile)
|
||||
goto error;
|
||||
|
||||
/* set up the hashfile structure */
|
||||
memset(hashfile, 0, sizeof(*hashfile));
|
||||
hashfile->pool = pool;
|
||||
hashfile->error_proc = error_proc;
|
||||
|
||||
/* open a file */
|
||||
fname = astring_assemble_2(astring_alloc(), sysname, ".hsi");
|
||||
filerr = mame_fopen_options(opts, SEARCHPATH_HASH, astring_c(fname), OPEN_FLAG_READ, &hashfile->file);
|
||||
astring_free(fname);
|
||||
|
||||
if (filerr != FILERR_NONE)
|
||||
goto error;
|
||||
|
||||
if (is_preload)
|
||||
hashfile_parse(hashfile, NULL, preload_use_proc, hashfile->error_proc, NULL);
|
||||
|
||||
return hashfile;
|
||||
|
||||
error:
|
||||
if (hashfile != NULL)
|
||||
hashfile_close(hashfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
hashfile_open
|
||||
-------------------------------------------------*/
|
||||
|
||||
hash_file *hashfile_open(const char *sysname, int is_preload,
|
||||
void (*error_proc)(const char *message))
|
||||
{
|
||||
return hashfile_open_options(mame_options(), sysname, is_preload, error_proc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
hashfile_close
|
||||
-------------------------------------------------*/
|
||||
|
||||
void hashfile_close(hash_file *hashfile)
|
||||
{
|
||||
if (hashfile->file)
|
||||
mame_fclose(hashfile->file);
|
||||
pool_free_lib(hashfile->pool);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
singular_selector_proc
|
||||
-------------------------------------------------*/
|
||||
|
||||
struct hashlookup_params
|
||||
{
|
||||
const char *hash;
|
||||
hash_info *hi;
|
||||
};
|
||||
|
||||
static int singular_selector_proc(hash_file *hashfile, void *param, const char *name, const char *hash)
|
||||
{
|
||||
struct hashlookup_params *hlparams = (struct hashlookup_params *) param;
|
||||
return hash_data_is_equal(hash, hlparams->hash,
|
||||
hash_data_used_functions(hash)) == 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
singular_use_proc
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void singular_use_proc(hash_file *hashfile, void *param, hash_info *hi)
|
||||
{
|
||||
struct hashlookup_params *hlparams = (struct hashlookup_params *) param;
|
||||
hlparams->hi = hi;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
hashfile_lookup
|
||||
-------------------------------------------------*/
|
||||
|
||||
const hash_info *hashfile_lookup(hash_file *hashfile, const char *hash)
|
||||
{
|
||||
struct hashlookup_params param;
|
||||
int i;
|
||||
|
||||
param.hash = hash;
|
||||
param.hi = NULL;
|
||||
|
||||
for (i = 0; i < hashfile->preloaded_hash_count; i++)
|
||||
{
|
||||
if (singular_selector_proc(hashfile, ¶m, NULL, hashfile->preloaded_hashes[i]->hash))
|
||||
return hashfile->preloaded_hashes[i];
|
||||
}
|
||||
|
||||
hashfile_parse(hashfile, singular_selector_proc, singular_use_proc,
|
||||
hashfile->error_proc, (void *) ¶m);
|
||||
return param.hi;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
hashfile_functions_used
|
||||
-------------------------------------------------*/
|
||||
|
||||
unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype)
|
||||
{
|
||||
assert(devtype >= 0);
|
||||
assert(devtype < IO_COUNT);
|
||||
return hashfile->functions[devtype];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
hashfile_verify
|
||||
-------------------------------------------------*/
|
||||
|
||||
int hashfile_verify(const char *sysname, void (*my_error_proc)(const char *message))
|
||||
{
|
||||
hash_file *hashfile;
|
||||
|
||||
hashfile = hashfile_open(sysname, FALSE, my_error_proc);
|
||||
if (!hashfile)
|
||||
return -1;
|
||||
|
||||
hashfile_parse(hashfile, NULL, NULL, my_error_proc, NULL);
|
||||
hashfile_close(hashfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
EXPAT INTERFACES
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
expat_malloc/expat_realloc/expat_free -
|
||||
wrappers for memory allocation functions so
|
||||
that they pass through out memory tracking
|
||||
systems
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void *expat_malloc(size_t size)
|
||||
{
|
||||
return global_alloc_array_clear(UINT8,size);
|
||||
}
|
||||
|
||||
static void *expat_realloc(void *ptr, size_t size)
|
||||
{
|
||||
if (ptr) global_free(ptr);
|
||||
return global_alloc_array_clear(UINT8,size);
|
||||
}
|
||||
|
||||
static void expat_free(void *ptr)
|
||||
{
|
||||
global_free(ptr);
|
||||
}
|
62
src/emu/hashfile.h
Normal file
62
src/emu/hashfile.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*********************************************************************
|
||||
|
||||
hashfile.h
|
||||
|
||||
Code for parsing hash info (*.hsi) files
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __HASHFILE_H__
|
||||
#define __HASHFILE_H__
|
||||
|
||||
#include "emu.h"
|
||||
#include "hash.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct _hash_info hash_info;
|
||||
struct _hash_info
|
||||
{
|
||||
char hash[HASH_BUF_SIZE];
|
||||
const char *longname;
|
||||
const char *manufacturer;
|
||||
const char *year;
|
||||
const char *playable;
|
||||
const char *pcb;
|
||||
const char *extrainfo;
|
||||
};
|
||||
|
||||
typedef struct _hash_file hash_file;
|
||||
|
||||
typedef void (*hashfile_error_func)(const char *message);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* opens a hash file; if is_preload is non-zero, the entire file is preloaded */
|
||||
hash_file *hashfile_open(const char *sysname, int is_preload, hashfile_error_func error_proc);
|
||||
|
||||
/* opens a hash file; if is_preload is non-zero, the entire file is preloaded */
|
||||
hash_file *hashfile_open_options(core_options *opts, const char *sysname, int is_preload,
|
||||
hashfile_error_func error_proc);
|
||||
|
||||
/* closes a hash file and associated resources */
|
||||
void hashfile_close(hash_file *hashfile);
|
||||
|
||||
/* looks up information in a hash file */
|
||||
const hash_info *hashfile_lookup(hash_file *hashfile, const char *hash);
|
||||
|
||||
/* performs a syntax check on a hash file */
|
||||
int hashfile_verify(const char *sysname, void (*error_proc)(const char *message));
|
||||
|
||||
/* returns the functions used in this hash file */
|
||||
unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype);
|
||||
|
||||
|
||||
#endif /* __HASHFILE_H__ */
|
Loading…
Reference in New Issue
Block a user