mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-02 13:20:51 +00:00
Moved mime-type functions to mime.c
This commit is contained in:
1 parent
8c4521af03
commit
45347bd44c
4 files changed
+198
-197
No files matched your search
+1
-1
@@ -28,7 +28,7 @@ VERSION = $(shell perl -lne \
|
|||||||
# The order in which files are listed is important
|
# The order in which files are listed is important
|
||||||
SOURCES = src/internal.h src/util.c src/string.c src/parse_date.c \
|
SOURCES = src/internal.h src/util.c src/string.c src/parse_date.c \
|
||||||
src/options.c src/crypto.c src/auth.c src/win32.c src/unix.c \
|
src/options.c src/crypto.c src/auth.c src/win32.c src/unix.c \
|
||||||
src/mg_printf.c src/ssl.c src/http_client.c \
|
src/mg_printf.c src/ssl.c src/http_client.c src/mime.c \
|
||||||
src/mongoose.c src/lua.c
|
src/mongoose.c src/lua.c
|
||||||
|
|
||||||
TINY_SOURCES = ../mongoose.c main.c
|
TINY_SOURCES = ../mongoose.c main.c
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char *extension;
|
||||||
|
size_t ext_len;
|
||||||
|
const char *mime_type;
|
||||||
|
} builtin_mime_types[] = {
|
||||||
|
{".html", 5, "text/html"},
|
||||||
|
{".htm", 4, "text/html"},
|
||||||
|
{".shtm", 5, "text/html"},
|
||||||
|
{".shtml", 6, "text/html"},
|
||||||
|
{".css", 4, "text/css"},
|
||||||
|
{".js", 3, "application/x-javascript"},
|
||||||
|
{".ico", 4, "image/x-icon"},
|
||||||
|
{".gif", 4, "image/gif"},
|
||||||
|
{".jpg", 4, "image/jpeg"},
|
||||||
|
{".jpeg", 5, "image/jpeg"},
|
||||||
|
{".png", 4, "image/png"},
|
||||||
|
{".svg", 4, "image/svg+xml"},
|
||||||
|
{".txt", 4, "text/plain"},
|
||||||
|
{".torrent", 8, "application/x-bittorrent"},
|
||||||
|
{".wav", 4, "audio/x-wav"},
|
||||||
|
{".mp3", 4, "audio/x-mp3"},
|
||||||
|
{".mid", 4, "audio/mid"},
|
||||||
|
{".m3u", 4, "audio/x-mpegurl"},
|
||||||
|
{".ogg", 4, "application/ogg"},
|
||||||
|
{".ram", 4, "audio/x-pn-realaudio"},
|
||||||
|
{".xml", 4, "text/xml"},
|
||||||
|
{".json", 5, "text/json"},
|
||||||
|
{".xslt", 5, "application/xml"},
|
||||||
|
{".xsl", 4, "application/xml"},
|
||||||
|
{".ra", 3, "audio/x-pn-realaudio"},
|
||||||
|
{".doc", 4, "application/msword"},
|
||||||
|
{".exe", 4, "application/octet-stream"},
|
||||||
|
{".zip", 4, "application/x-zip-compressed"},
|
||||||
|
{".xls", 4, "application/excel"},
|
||||||
|
{".tgz", 4, "application/x-tar-gz"},
|
||||||
|
{".tar", 4, "application/x-tar"},
|
||||||
|
{".gz", 3, "application/x-gunzip"},
|
||||||
|
{".arj", 4, "application/x-arj-compressed"},
|
||||||
|
{".rar", 4, "application/x-arj-compressed"},
|
||||||
|
{".rtf", 4, "application/rtf"},
|
||||||
|
{".pdf", 4, "application/pdf"},
|
||||||
|
{".swf", 4, "application/x-shockwave-flash"},
|
||||||
|
{".mpg", 4, "video/mpeg"},
|
||||||
|
{".webm", 5, "video/webm"},
|
||||||
|
{".mpeg", 5, "video/mpeg"},
|
||||||
|
{".mov", 4, "video/quicktime"},
|
||||||
|
{".mp4", 4, "video/mp4"},
|
||||||
|
{".m4v", 4, "video/x-m4v"},
|
||||||
|
{".asf", 4, "video/x-ms-asf"},
|
||||||
|
{".avi", 4, "video/x-msvideo"},
|
||||||
|
{".bmp", 4, "image/bmp"},
|
||||||
|
{".ttf", 4, "application/x-font-ttf"},
|
||||||
|
{NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *mg_get_builtin_mime_type(const char *path) {
|
||||||
|
const char *ext;
|
||||||
|
size_t i, path_len;
|
||||||
|
|
||||||
|
path_len = strlen(path);
|
||||||
|
|
||||||
|
for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
|
||||||
|
ext = path + (path_len - builtin_mime_types[i].ext_len);
|
||||||
|
if (path_len > builtin_mime_types[i].ext_len &&
|
||||||
|
mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
|
||||||
|
return builtin_mime_types[i].mime_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look at the "path" extension and figure what mime type it has.
|
||||||
|
// Store mime type in the vector.
|
||||||
|
static void get_mime_type(struct mg_context *ctx, const char *path,
|
||||||
|
struct vec *vec) {
|
||||||
|
struct vec ext_vec, mime_vec;
|
||||||
|
const char *list, *ext;
|
||||||
|
size_t path_len;
|
||||||
|
|
||||||
|
path_len = strlen(path);
|
||||||
|
|
||||||
|
// Scan user-defined mime types first, in case user wants to
|
||||||
|
// override default mime types.
|
||||||
|
list = ctx->config[EXTRA_MIME_TYPES];
|
||||||
|
while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
|
||||||
|
// ext now points to the path suffix
|
||||||
|
ext = path + path_len - ext_vec.len;
|
||||||
|
if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
|
||||||
|
*vec = mime_vec;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec->ptr = mg_get_builtin_mime_type(path);
|
||||||
|
vec->len = strlen(vec->ptr);
|
||||||
|
}
|
||||||
@@ -503,104 +503,6 @@ static int get_request_len(const char *buf, int buf_len) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
|
||||||
const char *extension;
|
|
||||||
size_t ext_len;
|
|
||||||
const char *mime_type;
|
|
||||||
} builtin_mime_types[] = {
|
|
||||||
{".html", 5, "text/html"},
|
|
||||||
{".htm", 4, "text/html"},
|
|
||||||
{".shtm", 5, "text/html"},
|
|
||||||
{".shtml", 6, "text/html"},
|
|
||||||
{".css", 4, "text/css"},
|
|
||||||
{".js", 3, "application/x-javascript"},
|
|
||||||
{".ico", 4, "image/x-icon"},
|
|
||||||
{".gif", 4, "image/gif"},
|
|
||||||
{".jpg", 4, "image/jpeg"},
|
|
||||||
{".jpeg", 5, "image/jpeg"},
|
|
||||||
{".png", 4, "image/png"},
|
|
||||||
{".svg", 4, "image/svg+xml"},
|
|
||||||
{".txt", 4, "text/plain"},
|
|
||||||
{".torrent", 8, "application/x-bittorrent"},
|
|
||||||
{".wav", 4, "audio/x-wav"},
|
|
||||||
{".mp3", 4, "audio/x-mp3"},
|
|
||||||
{".mid", 4, "audio/mid"},
|
|
||||||
{".m3u", 4, "audio/x-mpegurl"},
|
|
||||||
{".ogg", 4, "application/ogg"},
|
|
||||||
{".ram", 4, "audio/x-pn-realaudio"},
|
|
||||||
{".xml", 4, "text/xml"},
|
|
||||||
{".json", 5, "text/json"},
|
|
||||||
{".xslt", 5, "application/xml"},
|
|
||||||
{".xsl", 4, "application/xml"},
|
|
||||||
{".ra", 3, "audio/x-pn-realaudio"},
|
|
||||||
{".doc", 4, "application/msword"},
|
|
||||||
{".exe", 4, "application/octet-stream"},
|
|
||||||
{".zip", 4, "application/x-zip-compressed"},
|
|
||||||
{".xls", 4, "application/excel"},
|
|
||||||
{".tgz", 4, "application/x-tar-gz"},
|
|
||||||
{".tar", 4, "application/x-tar"},
|
|
||||||
{".gz", 3, "application/x-gunzip"},
|
|
||||||
{".arj", 4, "application/x-arj-compressed"},
|
|
||||||
{".rar", 4, "application/x-arj-compressed"},
|
|
||||||
{".rtf", 4, "application/rtf"},
|
|
||||||
{".pdf", 4, "application/pdf"},
|
|
||||||
{".swf", 4, "application/x-shockwave-flash"},
|
|
||||||
{".mpg", 4, "video/mpeg"},
|
|
||||||
{".webm", 5, "video/webm"},
|
|
||||||
{".mpeg", 5, "video/mpeg"},
|
|
||||||
{".mov", 4, "video/quicktime"},
|
|
||||||
{".mp4", 4, "video/mp4"},
|
|
||||||
{".m4v", 4, "video/x-m4v"},
|
|
||||||
{".asf", 4, "video/x-ms-asf"},
|
|
||||||
{".avi", 4, "video/x-msvideo"},
|
|
||||||
{".bmp", 4, "image/bmp"},
|
|
||||||
{".ttf", 4, "application/x-font-ttf"},
|
|
||||||
{NULL, 0, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *mg_get_builtin_mime_type(const char *path) {
|
|
||||||
const char *ext;
|
|
||||||
size_t i, path_len;
|
|
||||||
|
|
||||||
path_len = strlen(path);
|
|
||||||
|
|
||||||
for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
|
|
||||||
ext = path + (path_len - builtin_mime_types[i].ext_len);
|
|
||||||
if (path_len > builtin_mime_types[i].ext_len &&
|
|
||||||
mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
|
|
||||||
return builtin_mime_types[i].mime_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "text/plain";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look at the "path" extension and figure what mime type it has.
|
|
||||||
// Store mime type in the vector.
|
|
||||||
static void get_mime_type(struct mg_context *ctx, const char *path,
|
|
||||||
struct vec *vec) {
|
|
||||||
struct vec ext_vec, mime_vec;
|
|
||||||
const char *list, *ext;
|
|
||||||
size_t path_len;
|
|
||||||
|
|
||||||
path_len = strlen(path);
|
|
||||||
|
|
||||||
// Scan user-defined mime types first, in case user wants to
|
|
||||||
// override default mime types.
|
|
||||||
list = ctx->config[EXTRA_MIME_TYPES];
|
|
||||||
while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
|
|
||||||
// ext now points to the path suffix
|
|
||||||
ext = path + path_len - ext_vec.len;
|
|
||||||
if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
|
|
||||||
*vec = mime_vec;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec->ptr = mg_get_builtin_mime_type(path);
|
|
||||||
vec->len = strlen(vec->ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_url_encode(const char *src, char *dst, size_t dst_len) {
|
void mg_url_encode(const char *src, char *dst, size_t dst_len) {
|
||||||
static const char *dont_escape = "._-$,;~()";
|
static const char *dont_escape = "._-$,;~()";
|
||||||
static const char *hex = "0123456789abcdef";
|
static const char *hex = "0123456789abcdef";
|
||||||
|
|||||||
+98
-98
@@ -2193,6 +2193,104 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl,
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char *extension;
|
||||||
|
size_t ext_len;
|
||||||
|
const char *mime_type;
|
||||||
|
} builtin_mime_types[] = {
|
||||||
|
{".html", 5, "text/html"},
|
||||||
|
{".htm", 4, "text/html"},
|
||||||
|
{".shtm", 5, "text/html"},
|
||||||
|
{".shtml", 6, "text/html"},
|
||||||
|
{".css", 4, "text/css"},
|
||||||
|
{".js", 3, "application/x-javascript"},
|
||||||
|
{".ico", 4, "image/x-icon"},
|
||||||
|
{".gif", 4, "image/gif"},
|
||||||
|
{".jpg", 4, "image/jpeg"},
|
||||||
|
{".jpeg", 5, "image/jpeg"},
|
||||||
|
{".png", 4, "image/png"},
|
||||||
|
{".svg", 4, "image/svg+xml"},
|
||||||
|
{".txt", 4, "text/plain"},
|
||||||
|
{".torrent", 8, "application/x-bittorrent"},
|
||||||
|
{".wav", 4, "audio/x-wav"},
|
||||||
|
{".mp3", 4, "audio/x-mp3"},
|
||||||
|
{".mid", 4, "audio/mid"},
|
||||||
|
{".m3u", 4, "audio/x-mpegurl"},
|
||||||
|
{".ogg", 4, "application/ogg"},
|
||||||
|
{".ram", 4, "audio/x-pn-realaudio"},
|
||||||
|
{".xml", 4, "text/xml"},
|
||||||
|
{".json", 5, "text/json"},
|
||||||
|
{".xslt", 5, "application/xml"},
|
||||||
|
{".xsl", 4, "application/xml"},
|
||||||
|
{".ra", 3, "audio/x-pn-realaudio"},
|
||||||
|
{".doc", 4, "application/msword"},
|
||||||
|
{".exe", 4, "application/octet-stream"},
|
||||||
|
{".zip", 4, "application/x-zip-compressed"},
|
||||||
|
{".xls", 4, "application/excel"},
|
||||||
|
{".tgz", 4, "application/x-tar-gz"},
|
||||||
|
{".tar", 4, "application/x-tar"},
|
||||||
|
{".gz", 3, "application/x-gunzip"},
|
||||||
|
{".arj", 4, "application/x-arj-compressed"},
|
||||||
|
{".rar", 4, "application/x-arj-compressed"},
|
||||||
|
{".rtf", 4, "application/rtf"},
|
||||||
|
{".pdf", 4, "application/pdf"},
|
||||||
|
{".swf", 4, "application/x-shockwave-flash"},
|
||||||
|
{".mpg", 4, "video/mpeg"},
|
||||||
|
{".webm", 5, "video/webm"},
|
||||||
|
{".mpeg", 5, "video/mpeg"},
|
||||||
|
{".mov", 4, "video/quicktime"},
|
||||||
|
{".mp4", 4, "video/mp4"},
|
||||||
|
{".m4v", 4, "video/x-m4v"},
|
||||||
|
{".asf", 4, "video/x-ms-asf"},
|
||||||
|
{".avi", 4, "video/x-msvideo"},
|
||||||
|
{".bmp", 4, "image/bmp"},
|
||||||
|
{".ttf", 4, "application/x-font-ttf"},
|
||||||
|
{NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *mg_get_builtin_mime_type(const char *path) {
|
||||||
|
const char *ext;
|
||||||
|
size_t i, path_len;
|
||||||
|
|
||||||
|
path_len = strlen(path);
|
||||||
|
|
||||||
|
for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
|
||||||
|
ext = path + (path_len - builtin_mime_types[i].ext_len);
|
||||||
|
if (path_len > builtin_mime_types[i].ext_len &&
|
||||||
|
mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
|
||||||
|
return builtin_mime_types[i].mime_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look at the "path" extension and figure what mime type it has.
|
||||||
|
// Store mime type in the vector.
|
||||||
|
static void get_mime_type(struct mg_context *ctx, const char *path,
|
||||||
|
struct vec *vec) {
|
||||||
|
struct vec ext_vec, mime_vec;
|
||||||
|
const char *list, *ext;
|
||||||
|
size_t path_len;
|
||||||
|
|
||||||
|
path_len = strlen(path);
|
||||||
|
|
||||||
|
// Scan user-defined mime types first, in case user wants to
|
||||||
|
// override default mime types.
|
||||||
|
list = ctx->config[EXTRA_MIME_TYPES];
|
||||||
|
while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
|
||||||
|
// ext now points to the path suffix
|
||||||
|
ext = path + path_len - ext_vec.len;
|
||||||
|
if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
|
||||||
|
*vec = mime_vec;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec->ptr = mg_get_builtin_mime_type(path);
|
||||||
|
vec->len = strlen(vec->ptr);
|
||||||
|
}
|
||||||
|
|
||||||
// Return number of bytes left to read for this connection
|
// Return number of bytes left to read for this connection
|
||||||
static int64_t left_to_read(const struct mg_connection *conn) {
|
static int64_t left_to_read(const struct mg_connection *conn) {
|
||||||
return conn->content_len + conn->request_len - conn->num_bytes_read;
|
return conn->content_len + conn->request_len - conn->num_bytes_read;
|
||||||
@@ -2696,104 +2794,6 @@ static int get_request_len(const char *buf, int buf_len) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
|
||||||
const char *extension;
|
|
||||||
size_t ext_len;
|
|
||||||
const char *mime_type;
|
|
||||||
} builtin_mime_types[] = {
|
|
||||||
{".html", 5, "text/html"},
|
|
||||||
{".htm", 4, "text/html"},
|
|
||||||
{".shtm", 5, "text/html"},
|
|
||||||
{".shtml", 6, "text/html"},
|
|
||||||
{".css", 4, "text/css"},
|
|
||||||
{".js", 3, "application/x-javascript"},
|
|
||||||
{".ico", 4, "image/x-icon"},
|
|
||||||
{".gif", 4, "image/gif"},
|
|
||||||
{".jpg", 4, "image/jpeg"},
|
|
||||||
{".jpeg", 5, "image/jpeg"},
|
|
||||||
{".png", 4, "image/png"},
|
|
||||||
{".svg", 4, "image/svg+xml"},
|
|
||||||
{".txt", 4, "text/plain"},
|
|
||||||
{".torrent", 8, "application/x-bittorrent"},
|
|
||||||
{".wav", 4, "audio/x-wav"},
|
|
||||||
{".mp3", 4, "audio/x-mp3"},
|
|
||||||
{".mid", 4, "audio/mid"},
|
|
||||||
{".m3u", 4, "audio/x-mpegurl"},
|
|
||||||
{".ogg", 4, "application/ogg"},
|
|
||||||
{".ram", 4, "audio/x-pn-realaudio"},
|
|
||||||
{".xml", 4, "text/xml"},
|
|
||||||
{".json", 5, "text/json"},
|
|
||||||
{".xslt", 5, "application/xml"},
|
|
||||||
{".xsl", 4, "application/xml"},
|
|
||||||
{".ra", 3, "audio/x-pn-realaudio"},
|
|
||||||
{".doc", 4, "application/msword"},
|
|
||||||
{".exe", 4, "application/octet-stream"},
|
|
||||||
{".zip", 4, "application/x-zip-compressed"},
|
|
||||||
{".xls", 4, "application/excel"},
|
|
||||||
{".tgz", 4, "application/x-tar-gz"},
|
|
||||||
{".tar", 4, "application/x-tar"},
|
|
||||||
{".gz", 3, "application/x-gunzip"},
|
|
||||||
{".arj", 4, "application/x-arj-compressed"},
|
|
||||||
{".rar", 4, "application/x-arj-compressed"},
|
|
||||||
{".rtf", 4, "application/rtf"},
|
|
||||||
{".pdf", 4, "application/pdf"},
|
|
||||||
{".swf", 4, "application/x-shockwave-flash"},
|
|
||||||
{".mpg", 4, "video/mpeg"},
|
|
||||||
{".webm", 5, "video/webm"},
|
|
||||||
{".mpeg", 5, "video/mpeg"},
|
|
||||||
{".mov", 4, "video/quicktime"},
|
|
||||||
{".mp4", 4, "video/mp4"},
|
|
||||||
{".m4v", 4, "video/x-m4v"},
|
|
||||||
{".asf", 4, "video/x-ms-asf"},
|
|
||||||
{".avi", 4, "video/x-msvideo"},
|
|
||||||
{".bmp", 4, "image/bmp"},
|
|
||||||
{".ttf", 4, "application/x-font-ttf"},
|
|
||||||
{NULL, 0, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *mg_get_builtin_mime_type(const char *path) {
|
|
||||||
const char *ext;
|
|
||||||
size_t i, path_len;
|
|
||||||
|
|
||||||
path_len = strlen(path);
|
|
||||||
|
|
||||||
for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
|
|
||||||
ext = path + (path_len - builtin_mime_types[i].ext_len);
|
|
||||||
if (path_len > builtin_mime_types[i].ext_len &&
|
|
||||||
mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
|
|
||||||
return builtin_mime_types[i].mime_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "text/plain";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look at the "path" extension and figure what mime type it has.
|
|
||||||
// Store mime type in the vector.
|
|
||||||
static void get_mime_type(struct mg_context *ctx, const char *path,
|
|
||||||
struct vec *vec) {
|
|
||||||
struct vec ext_vec, mime_vec;
|
|
||||||
const char *list, *ext;
|
|
||||||
size_t path_len;
|
|
||||||
|
|
||||||
path_len = strlen(path);
|
|
||||||
|
|
||||||
// Scan user-defined mime types first, in case user wants to
|
|
||||||
// override default mime types.
|
|
||||||
list = ctx->config[EXTRA_MIME_TYPES];
|
|
||||||
while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
|
|
||||||
// ext now points to the path suffix
|
|
||||||
ext = path + path_len - ext_vec.len;
|
|
||||||
if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
|
|
||||||
*vec = mime_vec;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec->ptr = mg_get_builtin_mime_type(path);
|
|
||||||
vec->len = strlen(vec->ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_url_encode(const char *src, char *dst, size_t dst_len) {
|
void mg_url_encode(const char *src, char *dst, size_t dst_len) {
|
||||||
static const char *dont_escape = "._-$,;~()";
|
static const char *dont_escape = "._-$,;~()";
|
||||||
static const char *hex = "0123456789abcdef";
|
static const char *hex = "0123456789abcdef";
|
||||||
|
|||||||
Reference in new issue
Block a user