Merge pull request #118774 from Chubercik/minizip-1.3.2
minizip: Update to 1.3.2
This commit is contained in:
+1
-1
@@ -446,7 +446,7 @@ License: BSD-3-clause
|
||||
|
||||
Files: thirdparty/minizip/*
|
||||
Comment: MiniZip
|
||||
Copyright: 1998-2010, Gilles Vollant
|
||||
Copyright: 1998-2026, Gilles Vollant
|
||||
2007-2008, Even Rouault
|
||||
2009-2010, Mathias Svensson
|
||||
License: Zlib
|
||||
|
||||
Vendored
+1
-1
@@ -771,7 +771,7 @@ Files extracted from upstream source:
|
||||
## minizip
|
||||
|
||||
- Upstream: https://github.com/madler/zlib
|
||||
- Version: 1.3.1.2 (570720b0c24f9686c33f35a1b3165c1f568b96be, 2025)
|
||||
- Version: 1.3.2 (da607da739fa6047df13e66a2af6b8bec7c2a498, 2026)
|
||||
- License: zlib
|
||||
|
||||
Files extracted from the upstream source:
|
||||
|
||||
+5
-10
@@ -1,8 +1,8 @@
|
||||
MiniZip - Copyright (c) 1998-2010 - by Gilles Vollant - version 1.1 64 bits from Mathias Svensson
|
||||
MiniZip - Copyright (c) 1998-2026 - by Gilles Vollant - version 1.1 64 bits from Mathias Svensson
|
||||
|
||||
Introduction
|
||||
---------------------
|
||||
MiniZip 1.1 is built from MiniZip 1.0 by Gilles Vollant ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
MiniZip 1.1 is built from MiniZip 1.0 by Gilles Vollant ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
When adding ZIP64 support into minizip it would result into risk of breaking compatibility with minizip 1.0.
|
||||
All possible work was done for compatibility.
|
||||
@@ -11,7 +11,7 @@ All possible work was done for compatibility.
|
||||
Background
|
||||
---------------------
|
||||
When adding ZIP64 support Mathias Svensson found that Even Rouault have added ZIP64
|
||||
support for unzip.c into minizip for a open source project called gdal ( http://www.gdal.org/ )
|
||||
support for unzip.c into minizip for a open source project called gdal ( https://www.gdal.org/ )
|
||||
|
||||
That was used as a starting point. And after that ZIP64 support was added to zip.c
|
||||
some refactoring and code cleanup was also done.
|
||||
@@ -36,14 +36,9 @@ Credits
|
||||
Mathias Svensson - ZIP64 zip support
|
||||
Mathias Svensson - BZip Compression method support in zip
|
||||
|
||||
Resources
|
||||
Resource
|
||||
|
||||
ZipLayout http://result42.com/projects/ZipFileLayout
|
||||
Command line tool for Windows that shows the layout and information of the headers in a zip archive.
|
||||
Used when debugging and validating the creation of zip files using MiniZip64
|
||||
|
||||
|
||||
ZIP App Note http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||
ZIP App Note https://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||
Zip File specification
|
||||
|
||||
|
||||
|
||||
Vendored
+4
-7
@@ -1,9 +1,6 @@
|
||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
Copyright (C) 1998-2026 Gilles Vollant
|
||||
|
||||
This code is a modified version of crypting code in Infozip distribution
|
||||
|
||||
@@ -23,7 +20,7 @@
|
||||
This code support the "Traditional PKWARE Encryption".
|
||||
|
||||
The new AES encryption added on Zip format by Winzip (see the page
|
||||
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
https://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
Encryption is not supported.
|
||||
*/
|
||||
|
||||
@@ -50,7 +47,7 @@ static int update_keys(unsigned long* pkeys, const z_crc_t* pcrc_32_tab, int c)
|
||||
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
|
||||
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
|
||||
{
|
||||
register int keyshift = (int)((*(pkeys+1)) >> 24);
|
||||
int keyshift = (int)((*(pkeys+1)) >> 24);
|
||||
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
|
||||
}
|
||||
return c;
|
||||
@@ -106,7 +103,7 @@ static unsigned crypthead(const char* passwd, /* password string */
|
||||
*/
|
||||
if (++calls == 1)
|
||||
{
|
||||
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
|
||||
srand((unsigned)time(NULL) ^ ZCR_SEED2);
|
||||
}
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
|
||||
Vendored
+4
-4
@@ -1,10 +1,10 @@
|
||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications for Zip64 support
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
|
||||
#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) || (defined(__ANDROID_API__) && __ANDROID_API__ < 24)
|
||||
/* In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions */
|
||||
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello(stream)
|
||||
|
||||
Vendored
+4
-4
@@ -1,10 +1,10 @@
|
||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications for Zip64 support
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef ZLIBIOAPI64_H
|
||||
#define ZLIBIOAPI64_H
|
||||
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) && (!(defined(__ANDROID_API__) || __ANDROID_API__ >= 24))
|
||||
|
||||
/* Linux needs this to support file operation on files larger then 4+GB */
|
||||
/* But might need better if/def to select just the platforms that needs them.*/
|
||||
|
||||
Vendored
+9
-4
@@ -1,5 +1,5 @@
|
||||
/* skipset.h -- set operations using a skiplist
|
||||
// Copyright (C) 2024 Mark Adler
|
||||
// Copyright (C) 2024-2026 Mark Adler
|
||||
// See MiniZip_info.txt for the license.
|
||||
|
||||
// This implements a skiplist set, i.e. just keys, no data, with ~O(log n) time
|
||||
@@ -84,6 +84,11 @@ void set_seed(set_rand_t *gen, ui64_t seed, ui64_t seq) {
|
||||
gen->inc = (seq << 1) | 1;
|
||||
gen->state = (seed + gen->inc) * 6364136223846793005ULL + gen->inc;
|
||||
}
|
||||
/* Start a unique random number sequence using bits from noise sources. */
|
||||
void set_uniq(set_rand_t *gen, const void *ptr) {
|
||||
set_seed(gen, ((ui64_t)(ptrdiff_t)ptr << 32) ^
|
||||
((ui64_t)time(NULL) << 12) ^ clock(), 0);
|
||||
}
|
||||
/* Return 32 random bits, advancing the state *gen. */
|
||||
ui32_t set_rand(set_rand_t *gen) {
|
||||
ui64_t state = gen->state;
|
||||
@@ -184,7 +189,8 @@ void set_grow(set_t *set, set_node_t *node, int want, int fill) {
|
||||
int more = node->size ? node->size : 1;
|
||||
while (more < want)
|
||||
more <<= 1;
|
||||
node->right = set_alloc(set, node->right, more * sizeof(set_node_t *));
|
||||
node->right = set_alloc(set, node->right,
|
||||
(size_t)more * sizeof(set_node_t *));
|
||||
node->size = (i16_t)more;
|
||||
}
|
||||
int i;
|
||||
@@ -232,8 +238,7 @@ void set_start(set_t *set) {
|
||||
set_grow(set, set->head, 1, 1); /* one link back to head for an empty set */
|
||||
*(unsigned char *)&set->head->key = 137; /* set id */
|
||||
set->depth = 0;
|
||||
set_seed(&set->gen, ((ui64_t)(ptrdiff_t)set << 32) ^
|
||||
((ui64_t)time(NULL) << 12) ^ clock(), 0);
|
||||
set_uniq(&set->gen, set);
|
||||
set->ran = 1;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+8
-5
@@ -1,14 +1,13 @@
|
||||
/* unzip.c -- IO for uncompress .zip files using zlib
|
||||
Version 1.1, February 14h, 2010
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications of Unzip for Zip64
|
||||
Copyright (C) 2007-2008 Even Rouault
|
||||
|
||||
Modifications for Zip64 support on both zip and unzip
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
@@ -68,6 +67,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef ZLIB_DLL
|
||||
# undef ZLIB_DLL
|
||||
#endif
|
||||
#include "zlib.h"
|
||||
#include "unzip.h"
|
||||
|
||||
@@ -111,7 +113,7 @@
|
||||
|
||||
|
||||
const char unz_copyright[] =
|
||||
" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
|
||||
" unzip 1.01 Copyright 1998-2004 Gilles Vollant - https://www.winimage.com/zLibDll/minizip.html";
|
||||
|
||||
/* unz_file_info64_internal contain internal info about a file in zipfile*/
|
||||
typedef struct unz_file_info64_internal_s
|
||||
@@ -684,6 +686,7 @@ extern unzFile ZEXPORT unzOpen2_64(const void *path,
|
||||
{
|
||||
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
|
||||
zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
|
||||
zlib_filefunc64_32_def_fill.zopen32_file = NULL;
|
||||
zlib_filefunc64_32_def_fill.ztell32_file = NULL;
|
||||
zlib_filefunc64_32_def_fill.zseek32_file = NULL;
|
||||
return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);
|
||||
|
||||
Vendored
+5
-4
@@ -1,14 +1,13 @@
|
||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.1, February 14h, 2010
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications of Unzip for Zip64
|
||||
Copyright (C) 2007-2008 Even Rouault
|
||||
|
||||
Modifications for Zip64 support on both zip and unzip
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
@@ -70,6 +69,8 @@ typedef unzFile__ *unzFile;
|
||||
typedef voidp unzFile;
|
||||
#endif
|
||||
|
||||
extern const char unz_copyright[];
|
||||
|
||||
|
||||
#define UNZ_OK (0)
|
||||
#define UNZ_END_OF_LIST_OF_FILE (-100)
|
||||
|
||||
Vendored
+59
-12
@@ -1,11 +1,10 @@
|
||||
/* zip.c -- IO on .zip files using zlib
|
||||
Version 1.1, February 14h, 2010
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications for Zip64 support
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
@@ -29,6 +28,9 @@
|
||||
#ifndef ZLIB_CONST
|
||||
# define ZLIB_CONST
|
||||
#endif
|
||||
#ifdef ZLIB_DLL
|
||||
# undef ZLIB_DLL
|
||||
#endif
|
||||
#include "zlib.h"
|
||||
#include "zip.h"
|
||||
|
||||
@@ -93,7 +95,7 @@
|
||||
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
|
||||
#endif
|
||||
#endif
|
||||
const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
|
||||
const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - https://www.winimage.com/zLibDll/minizip.html";
|
||||
|
||||
|
||||
#define SIZEDATA_INDATABLOCK (4096-(4*4))
|
||||
@@ -337,7 +339,7 @@ local int block_get(block_t *block) {
|
||||
return -1;
|
||||
/* Update left in case more was filled in since we were last here. */
|
||||
block->left = block->node->filled_in_this_block -
|
||||
(block->next - block->node->data);
|
||||
(size_t)(block->next - block->node->data);
|
||||
if (block->left != 0)
|
||||
/* There was indeed more data appended in the current datablock. */
|
||||
break;
|
||||
@@ -357,8 +359,9 @@ local int block_get(block_t *block) {
|
||||
/* Return a 16-bit unsigned little-endian value from block, or a negative value
|
||||
// if the end is reached. */
|
||||
local long block_get2(block_t *block) {
|
||||
long got = block_get(block);
|
||||
return got | ((unsigned long)block_get(block) << 8);
|
||||
int low = block_get(block);
|
||||
int high = block_get(block);
|
||||
return low < 0 || high < 0 ? -1 : low | ((long)high << 8);
|
||||
}
|
||||
|
||||
/* Read up to len bytes from block into buf. Return the number of bytes read. */
|
||||
@@ -420,9 +423,9 @@ local char *block_central_name(block_t *block, set_t *set) {
|
||||
/* Go through the remaining fixed-length portion of the record,
|
||||
// extracting the lengths of the three variable-length fields. */
|
||||
block_skip(block, 24);
|
||||
unsigned flen = block_get2(block); /* file name length */
|
||||
unsigned xlen = block_get2(block); /* extra field length */
|
||||
unsigned clen = block_get2(block); /* comment field length */
|
||||
unsigned flen = (unsigned)block_get2(block); /* file name length */
|
||||
unsigned xlen = (unsigned)block_get2(block); /* extra length */
|
||||
unsigned clen = (unsigned)block_get2(block); /* comment length */
|
||||
if (block_skip(block, 12) == -1)
|
||||
/* Premature end of the record. */
|
||||
break;
|
||||
@@ -500,7 +503,7 @@ extern int ZEXPORT zipAlreadyThere(zipFile file, char const *name) {
|
||||
/* Return true if name is in the central directory. */
|
||||
size_t len = strlen(name);
|
||||
char *copy = set_alloc(&zip->set, NULL, len + 1);
|
||||
strcpy(copy, name);
|
||||
memcpy(copy, name, len + 1);
|
||||
int found = set_found(&zip->set, copy);
|
||||
set_free(&zip->set, copy);
|
||||
return found;
|
||||
@@ -1141,6 +1144,7 @@ extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc*
|
||||
{
|
||||
zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
|
||||
zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
|
||||
zlib_filefunc64_32_def_fill.zopen32_file = NULL;
|
||||
zlib_filefunc64_32_def_fill.ztell32_file = NULL;
|
||||
zlib_filefunc64_32_def_fill.zseek32_file = NULL;
|
||||
return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
|
||||
@@ -1247,6 +1251,46 @@ local int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt s
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Return the length of the UTF-8 code at str[0..len-1] in [1..4], or negative
|
||||
if there is no valid UTF-8 code there. If negative, it is minus the number
|
||||
of bytes examined in order to determine it was bad. Or if minus the return
|
||||
code is one less than len, then at least one more byte than provided would
|
||||
be needed to complete the code. */
|
||||
local int utf8len(unsigned char const *str, size_t len) {
|
||||
return
|
||||
len == 0 ? -1 : /* empty input */
|
||||
str[0] < 0x80 ? 1 : /* good one-byte */
|
||||
str[0] < 0xc0 ? -1 : /* bad first byte */
|
||||
len < 2 || (str[1] >> 6) != 2 ? -2 : /* missing or bad 2nd byte */
|
||||
str[0] < 0xc2 ? -2 : /* overlong code */
|
||||
str[0] < 0xe0 ? 2 : /* good two-byte */
|
||||
len < 3 || (str[2] >> 6) != 2 ? -3 : /* missing or bad 3rd byte */
|
||||
str[0] == 0xe0 && str[1] < 0xa0 ? -3 : /* overlong code */
|
||||
str[0] < 0xf0 ? 3 : /* good three-byte */
|
||||
len < 4 || (str[3] >> 6) != 2 ? -4 : /* missing or bad 4th byte */
|
||||
str[0] == 0xf0 && str[1] < 0x90 ? -4 : /* overlong code */
|
||||
str[0] < 0xf4 ||
|
||||
(str[0] == 0xf4 && str[1] < 0x90) ? 4 : /* good four-byte */
|
||||
-4; /* code > 0x10ffff */
|
||||
}
|
||||
|
||||
/* Return true if str[0..len-1] is valid UTF-8 *and* it contains at least one
|
||||
code of two or more bytes. This is used to determine whether or not to set
|
||||
bit 11 in the zip header flags. */
|
||||
local int isutf8(char const *str, size_t len) {
|
||||
int utf8 = 0;
|
||||
while (len) {
|
||||
int code = utf8len((unsigned char const *)str, len);
|
||||
if (code < 0)
|
||||
return 0;
|
||||
if (code > 1)
|
||||
utf8 = 1;
|
||||
str += code;
|
||||
len -= (unsigned)code;
|
||||
}
|
||||
return utf8;
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE.
|
||||
When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
|
||||
@@ -1333,6 +1377,9 @@ extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, c
|
||||
zi->ci.flag |= 6;
|
||||
if (password != NULL)
|
||||
zi->ci.flag |= 1;
|
||||
if (isutf8(filename, size_filename) &&
|
||||
(size_comment == 0 || isutf8(comment, size_comment)))
|
||||
zi->ci.flag |= (1 << 11);
|
||||
|
||||
zi->ci.crc32 = 0;
|
||||
zi->ci.method = method;
|
||||
|
||||
Vendored
+5
-4
@@ -1,11 +1,10 @@
|
||||
/* zip.h -- IO on .zip files using zlib
|
||||
Version 1.1, February 14h, 2010
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
part of the MiniZip project - ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
Copyright (C) 1998-2026 Gilles Vollant (minizip) ( https://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications for Zip64 support
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( https://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
@@ -69,6 +68,8 @@ typedef zipFile__ *zipFile;
|
||||
typedef voidp zipFile;
|
||||
#endif
|
||||
|
||||
extern const char zip_copyright[];
|
||||
|
||||
#define ZIP_OK (0)
|
||||
#define ZIP_EOF (0)
|
||||
#define ZIP_ERRNO (Z_ERRNO)
|
||||
|
||||
Reference in New Issue
Block a user