From f6338b2e42f61f5c8673d9aca549512385212c6d Mon Sep 17 00:00:00 2001 From: darkrose Date: Sun, 6 Oct 2013 00:30:07 +1000 Subject: [PATCH] http part 3 --- data/html/footer.html | 4 + data/html/header.html | 52 ++++ src/CMakeLists.txt | 1 + src/content_cao.cpp | 2 +- src/farmesh.cpp | 2 +- src/game.cpp | 1 + src/http.cpp | 618 +++++++++++++++++++++++++++++++++++------- src/http.h | 78 ++++-- src/main.cpp | 1 + src/path.cpp | 191 +++++++++++++ src/path.h | 39 +++ src/player.cpp | 2 +- src/server.h | 13 + src/sha1.cpp | 27 ++ src/sha1.h | 4 +- src/tile.cpp | 188 +------------ src/tile.h | 17 -- 17 files changed, 911 insertions(+), 329 deletions(-) create mode 100644 data/html/footer.html create mode 100644 data/html/header.html create mode 100644 src/path.cpp create mode 100644 src/path.h diff --git a/data/html/footer.html b/data/html/footer.html new file mode 100644 index 0000000..0f47b89 --- /dev/null +++ b/data/html/footer.html @@ -0,0 +1,4 @@ + + + + diff --git a/data/html/header.html b/data/html/header.html new file mode 100644 index 0000000..565a261 --- /dev/null +++ b/data/html/header.html @@ -0,0 +1,52 @@ + + + + Minetest Classic + + + + +
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 12e51f1..0236768 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -131,6 +131,7 @@ set(common_SRCS base64.cpp ban.cpp http.cpp + path.cpp ) # This gives us the icon diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 3d30eec..1929930 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "content_cao.h" -#include "tile.h" +#include "path.h" #include "environment.h" #include "settings.h" #include diff --git a/src/farmesh.cpp b/src/farmesh.cpp index aea63cb..537746c 100644 --- a/src/farmesh.cpp +++ b/src/farmesh.cpp @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "noise.h" #include "map.h" #include "client.h" - +#include "path.h" #include "mapgen.h" FarMesh::FarMesh( diff --git a/src/game.cpp b/src/game.cpp index c158aa1..5fff394 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gettext.h" #include "log.h" #include "filesys.h" +#include "path.h" /* TODO: Move content-aware stuff to separate file by adding properties diff --git a/src/http.cpp b/src/http.cpp index 1bc7ada..1aa717a 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -21,6 +21,9 @@ #include "socket.h" #include "http.h" +#include "main.h" +#include "settings.h" +#include "filesys.h" #include "debug.h" #include #include @@ -30,7 +33,10 @@ #include "connection.h" #include "log.h" #include "sha1.h" +#include "path.h" +#include "config.h" +/* server thread main loop */ void * HTTPServerThread::Thread() { ThreadStarted(); @@ -59,16 +65,19 @@ void * HTTPServerThread::Thread() * HTTPServer */ +/* constructor */ HTTPServer::HTTPServer(Server &server): m_thread(this) { m_server = &server; } +/* destructor */ HTTPServer::~HTTPServer() { } +/* start the server running */ void HTTPServer::start(u16 port) { DSTACK(__FUNCTION_NAME); @@ -86,6 +95,7 @@ void HTTPServer::start(u16 port) infostream<<"HTTPServer: Started on port "<WaitData(50)) { @@ -104,19 +115,22 @@ void HTTPServer::step() m_peers.push_back(c); } - for (std::vector::iterator it = m_peers.begin(); it != m_peers.end(); ++it) { - HTTPRemoteClient *c = *it; + std::vector p; + + p.swap(m_peers); + + for (std::vector::iterator i = p.begin(); i != p.end(); ++i) { + HTTPRemoteClient *c = *i; try{ if (c->receive()) { - m_peers.erase(it); delete c; + continue; } }catch (SocketException &e) { - // assume it's closed - m_peers.erase(it); delete c; continue; } + m_peers.push_back(c); } } @@ -124,119 +138,443 @@ void HTTPServer::step() * HTTPRemoteClient */ +/* destructor */ HTTPRemoteClient::~HTTPRemoteClient() { + delete m_socket; } +/* receive and handle data from a remote http client */ int HTTPRemoteClient::receive() { - char buff[2048]; - if (!m_socket->WaitData(30)) + int r = fillBuffer(); + if (!r) return 0; - int r = m_socket->Receive(buff,2048); if (r<1) return 1; m_recv_headers.clear(); m_send_headers.clear(); - int h = m_recv_headers.read(buff,r); - if (h == 1) { + int h = m_recv_headers.read(m_buff,r); + if (h == -1) { return 1; - }else if (h == 2) { - //if (m_recv_headers.url() == "") - //return 1; - //while (m_socket->WaitData(1000)) { - //r = m_socket->Receive(buff,2048); - //if (r<1) - //return 1; - //h = m_recv_headers.read(buff,r); - //if (!h) - //break; - //if (h == 1) - //return 1; - //} - //if (h) + }else if (h == -2) { + if (m_recv_headers.getUrl() == "") + return 1; + while (m_socket->WaitData(1000)) { + r = fillBuffer(); + if (r<1) + return 1; + h = m_recv_headers.read(m_buff,r); + if (h > -1) + break; + if (h == -1) + return 1; + } + if (h < 0) return 1; } - if (m_recv_headers.cookie() != "" && m_recv_headers.get("User") != "") { - if (m_recv_headers.cookie() == m_server->getPlayerCookie(m_recv_headers.get("User"))) { - m_send_headers.setCookie(m_recv_headers.cookie()); + if (m_recv_headers.getCookie() != "" && m_recv_headers.getHeader("User") != "") { + if (m_recv_headers.getCookie() == m_server->getPlayerCookie(m_recv_headers.getHeader("User"))) { + m_send_headers.setCookie(m_recv_headers.getCookie()); m_auth = true; } } - //std::string u; - //for (int i=0; (u = m_recv_headers.url(i)) != ""; i++) { - //printf("%d: '%s'\n",i,u.c_str()); - //} + if (m_recv_headers.getUrl(0) == "texture") { + return handleTexture(); + }else if (m_recv_headers.getUrl(0) == "player") { + return handlePlayer(); + }else if (m_recv_headers.getUrl(0) == "") { + return handleIndex(); + } - - //setResponse("404 Not Found"); - //std::string html("404 Not Found

404 Not Found

"); - //send(html); - send((char*)"grar"); - - return 0;//m_recv_headers.keepAlive() == true ? 0 : 1; + return handleSpecial("404 Not Found"); } +/* read data from a remote http client */ +int HTTPRemoteClient::read(char* buff, int size) +{ + if (size > 2048) { + int r = 0; + int l; + int c = 2048; + int s = size; + while (fillBuffer()) { + c = 2048; + if (sWaitData(30)) + return m_end; + + return m_end+m_socket->Receive(m_buff+m_end,l); +} + +/* handle /player/ url's */ +int HTTPRemoteClient::handlePlayer() +{ + char buff[2048]; + /* player list */ + if (m_recv_headers.getUrl(1) == "") { + core::list players = m_server->getGameServer()->getPlayers(); + std::string html("

Players

\n"); + for (core::list::Iterator i = players.begin(); i != players.end(); i++) { + Player *player = *i; + html += "

getName(); + html += "\" class=\"secret\">"; + html += player->getName(); + html += "

"; + html += "

getName(); + html += "/skin\" />

"; + snprintf(buff, 2048,"% .1f, % .1f, % .1f",player->getPosition().X/BS,player->getPosition().Y/BS,player->getPosition().Z/BS); + if (player->peer_id == 0) { + html += "

Offline

"; + html += "

Last seen at: "; + }else{ + html += "

Online

"; + html += "

Currently at: "; + } + html += buff; + html += "

Privileges: "; + html += m_server->getPlayerPrivs(player->getName()); + html += "

"; + } + sendHTML((char*)html.c_str()); + return 1; + /* player skin */ + }else if (m_recv_headers.getUrl(2) == "skin") { + std::string data_path = g_settings->get("data_path"); + if (data_path == "") + data_path = "data"; + std::string file = data_path + DIR_DELIM + "textures" + DIR_DELIM + "players" + DIR_DELIM + "player_" + m_recv_headers.getUrl(1) + ".png"; + /* compare hash */ + if (m_recv_headers.getUrl(3) != "") { + FILE *f; + f = fopen(file.c_str(),"rb"); + if (!f) + return handleSpecial("204 No Content"); + fclose(f); + SHA1 s; + s.addFile(file.c_str()); + s.getDigest(buff); + if (std::string(buff) == m_recv_headers.getUrl(3)) { + return handleSpecial("204 No Content"); + }else if (m_auth && m_recv_headers.getHeader("User") == m_recv_headers.getUrl(1)) { + return handleSpecial("304 Not Modified"); + } + m_send_headers.setHeader("Content-Type","image/png"); + sendFile(file); + return 1; + } + /* get file */ + if (m_recv_headers.getMethod() != "PUT") { + m_send_headers.setHeader("Content-Type","image/png"); + sendFile(file); + return 1; + } + /* put only works for the owner */ + if (!m_auth || m_recv_headers.getHeader("User") != m_server->getPlayerFromCookie(m_recv_headers.getCookie())) + return handleSpecial("405 Method Not Allowed"); + FILE *f; + f = fopen(file.c_str(),"wb"); + if (!f) + return handleSpecial("500 Internal Server Error"); + size_t s = m_recv_headers.getLength(); + if (!s) + return handleSpecial("411 Length Required"); + size_t l; + size_t c = 2048; + if (c > s) + c = s; + if (c) { + while ((l = read(buff,c)) > 0) { + s -= l; + c = fwrite(buff,1,l,f); + if (c != l) { + fclose(f); + return handleSpecial("500 Internal Server Error"); + } + c = 2048; + if (c > s) + c = s; + if (!c) + break; + } + } + fclose(f); + return handleSpecial("201 Created"); + }else if (m_server->getGameServer()->getPlayer(m_recv_headers.getUrl(1))) { + std::string html("

Players

\n"); + Player *player = m_server->getGameServer()->getPlayer(m_recv_headers.getUrl(1)); + html += "

"; + html += player->getName(); + html += "

"; + html += "

getName(); + html += "/skin\" />

"; + snprintf(buff, 2048,"% .1f, % .1f, % .1f",player->getPosition().X/BS,player->getPosition().Y/BS,player->getPosition().Z/BS); + if (player->peer_id == 0) { + html += "

Offline

"; + html += "

Last seen at: "; + }else{ + html += "

Online

"; + html += "

Currently at: "; + } + html += buff; + html += "

Privileges: "; + html += m_server->getPlayerPrivs(player->getName()); + html += "

"; + sendHTML((char*)html.c_str()); + return 1; + } + return handleSpecial("404 Not Found"); +} + +/* handle /texture/ url's */ +int HTTPRemoteClient::handleTexture() +{ + std::string file = getTexturePath(m_recv_headers.getUrl(1)); + m_send_headers.setHeader("Content-Type","image/png"); + sendFile(file); + return 1; +} + +/* handle /model/ url's */ +int HTTPRemoteClient::handleModel() +{ + std::string file = getModelPath(m_recv_headers.getUrl(1)); + m_send_headers.setHeader("Content-Type","application/octet-stream"); + sendFile(file); + return 1; +} + +/* handle /map/// url's */ +int HTTPRemoteClient::handleMap() +{ + return handleSpecial("404 Not Found"); +} + +/* handle / url's */ +int HTTPRemoteClient::handleIndex() +{ + int c = 0; + std::string html("

"); + html += g_settings->get("motd"); + html += "

Version: "; + html += VERSION_STRING; + html += "
Players: "; + core::list players = m_server->getGameServer()->getPlayers(); + for (core::list::Iterator i = players.begin(); i != players.end(); i++) { + Player *player = *i; + if (player->peer_id != 0) { + if (c++) + html += ", "; + html += "getName(); + html += "\" class=\"secret\">"; + html += player->getName(); + html += ""; + } + } + html += "

"; + sendHTML((char*)html.c_str()); + return 1; +} + +/* simple wrapper for sending html content and/or errors */ +int HTTPRemoteClient::handleSpecial(const char* response, std::string content) +{ + setResponse(response); + std::string html("

"); + html += std::string(response) + "

" + content; + sendHTML(html); + return 1; +} + +/* send text data to a remote http client */ void HTTPRemoteClient::send(char* data) { int l = strlen(data); - m_send_headers.set("Content-Type","text/plain"); + m_send_headers.setHeader("Content-Type","text/plain"); m_send_headers.setLength(l); sendHeaders(); m_socket->Send(data,l); } +/* send html data to a remote http client */ void HTTPRemoteClient::sendHTML(char* data) { - int l = strlen(data); - m_send_headers.set("Content-Type","text/html"); - m_send_headers.setLength(l); + FILE *h; + FILE *f; + int l[4]; + char* b; + std::string data_path = g_settings->get("data_path"); + if (data_path == "") + data_path = "data"; + std::string file = data_path + DIR_DELIM + "html" + DIR_DELIM + "header.html"; + h = fopen(file.c_str(),"r"); + if (!h && data_path != "data") { + file = std::string("data") + DIR_DELIM + "html" + DIR_DELIM + "header.html"; + h = fopen(file.c_str(),"r"); + } + file = data_path + DIR_DELIM + "html" + DIR_DELIM + "footer.html"; + f = fopen(file.c_str(),"r"); + if (!f && data_path != "data") { + file = std::string("data") + DIR_DELIM + "html" + DIR_DELIM + "footer.html"; + f = fopen(file.c_str(),"r"); + } + + if (h) { + fseek(h,0,SEEK_END); + l[0] = ftell(h); + fseek(h,0,SEEK_SET); + }else{ + l[0] = 0; + } + l[1] = strlen(data); + if (f) { + fseek(f,0,SEEK_END); + l[2] = ftell(f); + fseek(f,0,SEEK_SET); + }else{ + l[2] = 0; + } + + if (l[0] > l[2]) { + b = (char*)alloca(l[0]); + }else{ + b = (char*)alloca(l[2]); + } + + l[3] = l[0]+l[1]+l[2]; + m_send_headers.setHeader("Content-Type","text/html"); + m_send_headers.setLength(l[3]); sendHeaders(); - m_socket->Send(data,l); + if (h) { + l[3] = fread(b,1,l[0],h); + m_socket->Send(b,l[3]); + fclose(h); + } + m_socket->Send(data,l[1]); + if (f) { + l[3] = fread(b,1,l[2],f); + m_socket->Send(b,l[3]); + fclose(f); + } } +/* send a file to a remote http client */ void HTTPRemoteClient::sendFile(std::string &file) { - m_send_headers.set("Content-Type","text/plain"); - m_send_headers.setLength(0); + FILE *f; + f = fopen(file.c_str(),"rb"); + if (!f) { + std::string data_path = g_settings->get("data_path"); + if (data_path == "") + data_path = "data"; + if (file.substr(data_path.size()+1,24) == "textures/players/player_") { + m_send_headers.setHeader("Location","/texture/character.png"); + handleSpecial("303 See Other","

/texture/character.png

"); + return; + } + handleSpecial("404 Not Found"); + return; + } + fseek(f,0,SEEK_END); + size_t l = ftell(f); + fseek(f,0,SEEK_SET); + + m_send_headers.setLength(l); sendHeaders(); + + char buff[1024]; + while ((l = fread(buff,1,1024,f)) > 0) { + m_socket->Send(buff,l); + } + + fclose(f); } +/* send response headers to a remote http client */ void HTTPRemoteClient::sendHeaders() { std::string v; int s; char buff[1024]; - //v = m_response; - //if (v == "") - //v = std::string("200 OK"); + v = m_response; + if (v == "") + v = std::string("200 OK"); - //s = snprintf(buff,1024,"HTTP/1.1 %s\r\n",v.c_str()); - //m_socket->Send(buff,s); - m_socket->Send("HTTP/1.1 200 OK\r\n",17); + s = snprintf(buff,1024,"HTTP/1.0 %s\r\n",v.c_str()); + m_socket->Send(buff,s); + //m_socket->Send("HTTP/1.0 200 OK\r\n",17); - //v = m_send_headers.get("Content-Type"); - //if (v == "") { + v = m_send_headers.getHeader("Content-Type"); + if (v == "") { m_socket->Send("Content-Type: text/plain\r\n",26); - //}else{ - //s = snprintf(buff,1024,"Content-Type: %s\r\n",v.c_str()); - //m_socket->Send(buff,s); - //} + }else{ + s = snprintf(buff,1024,"Content-Type: %s\r\n",v.c_str()); + m_socket->Send(buff,s); + } s = m_send_headers.length(); s = snprintf(buff,1024,"Content-Length: %d\r\n",s); m_socket->Send(buff,s); - //v = m_send_headers.cookie(); - //if (v != "") { - //s = snprintf(buff,1024,"Set-Cookie: MTID=%s\r\n",v.c_str()); - //m_socket->Send(buff,s); - //} + v = m_send_headers.getCookie(); + if (v != "") { + s = snprintf(buff,1024,"Set-Cookie: MTID=%s\r\n",v.c_str()); + m_socket->Send(buff,s); + } + + v = m_send_headers.getHeader("Location"); + if (v != "") { + s = snprintf(buff,1024,"Location: %s\r\n",v.c_str()); + m_socket->Send(buff,s); + } + + v = m_send_headers.getHeader("Refresh"); + if (v != "") { + s = snprintf(buff,1024,"Refresh: %s\r\n",v.c_str()); + m_socket->Send(buff,s); + } m_socket->Send("\r\n",2); } @@ -244,6 +582,7 @@ void HTTPRemoteClient::sendHeaders() #ifndef SERVER #include "client.h" +/* main loop for the client http fetcher */ void * HTTPClientThread::Thread() { ThreadStarted(); @@ -272,6 +611,7 @@ void * HTTPClientThread::Thread() * HTTPClient */ +/* constructor */ HTTPClient::HTTPClient(Client *client): m_cookie(""), m_thread(this) @@ -280,10 +620,12 @@ HTTPClient::HTTPClient(Client *client): m_req_mutex.Init(); } +/* destructor */ HTTPClient::~HTTPClient() { } +/* start the client http fetcher thread */ void HTTPClient::start(const Address &address) { DSTACK(__FUNCTION_NAME); @@ -301,6 +643,7 @@ void HTTPClient::start(const Address &address) infostream<<"HTTPClient: Started"< class HTTPServer; @@ -57,34 +58,49 @@ public: void clear() { m_contentLength = 0; - m_keepalive = false; m_cookie = std::string(""); m_url = std::string(""); m_url_split.clear(); } - int read(char* buff, int length); + virtual int read(char* buff, int length) = 0; u32 length() {return m_contentLength;} - bool keepAlive() {return m_keepalive;} - std::string &cookie() {return m_cookie;} - std::string &url() {return m_url;} - std::string &url(int index) {return m_url_split[index];} - std::string &get(std::string name) {return m_headers[name];} - void set(std::string name, std::string value) {m_headers[name] = value;} - void setLength(u32 length) {m_contentLength = length;} - void setKeepAlive(bool ka) {m_keepalive = ka;} + std::string getCookie() {return m_cookie;} + std::string getUrl() {return m_url;} + std::string getUrl(unsigned int index) { if (m_url_split.size() > index) return m_url_split[index]; return std::string("");} + std::string getHeader(std::string name) {return m_headers[name];} + std::string getMethod() {return m_method;} + u32 getLength() {return m_contentLength;} + void setCookie(std::string cookie) {std::string c(cookie.c_str()); m_cookie = c;} void setUrl(std::string url) {std::string u(url); m_url = u;} + void addUrl(std::string url) {m_url_split.push_back(url);} + void setHeader(std::string name, std::string value) {m_headers[name] = value;} void setMethod(std::string method) {std::string m(method); m_method = m;} - void setProtocol(std::string proto) {std::string p(proto); m_protocol = p;} + void setLength(u32 length) {m_contentLength = length;} private: std::map m_headers; u32 m_contentLength; - bool m_keepalive; std::string m_cookie; std::string m_url; std::vector m_url_split; std::string m_method; - std::string m_protocol; +}; + +class HTTPRequestHeaders : public HTTPHeaders +{ +public: + virtual int read(char* buff, int length); +private: +}; + +class HTTPResponseHeaders : public HTTPHeaders +{ +public: + virtual int read(char* buff, int length); + void setResponse(int r) {m_response = r;} + int getResponse() {return m_response;} +private: + int m_response; }; class HTTPRemoteClient @@ -96,19 +112,36 @@ public: { m_socket = sock; m_server = server; + m_start = 0; + m_end = 0; } ~HTTPRemoteClient(); int receive(); +private: + int read(char* buff, int size); + int fillBuffer(); + void sendHeaders(); + + int handlePlayer(); + int handleTexture(); + int handleModel(); + int handleMap(); + int handleIndex(); + int handleSpecial(const char* response, std::string content); + int handleSpecial(const char* response) {return handleSpecial(response,"");} + void send(char* data); void send(std::string &data) {send((char*)data.c_str());} void sendHTML(char* data); void sendHTML(std::string &data) {sendHTML((char*)data.c_str());} void sendFile(std::string &file); void setResponse(const char* response) {std::string r(response); m_response = r;} -private: - void sendHeaders(); - HTTPHeaders m_recv_headers; - HTTPHeaders m_send_headers; + + char m_buff[2048]; + int m_start; + int m_end; + HTTPRequestHeaders m_recv_headers; + HTTPResponseHeaders m_send_headers; std::string m_response; bool m_auth; TCPSocket *m_socket; @@ -123,7 +156,10 @@ public: void start(u16 port); void stop(); void step(); - std::string getPlayerCookie(std::string &name) {return m_server->getPlayerCookie(name);} + std::string getPlayerCookie(std::string name) {return m_server->getPlayerCookie(name);} + std::string getPlayerFromCookie(std::string cookie) {return m_server->getPlayerFromCookie(cookie);} + std::string getPlayerPrivs(std::string name) {return privsToString(m_server->getPlayerAuthPrivs(name));} + Server *getGameServer() {return m_server;} private: TCPSocket *m_socket; std::vector m_peers; @@ -192,12 +228,12 @@ public: private: void get(std::string &url); void post(std::string &url, char* data); - void postFile(std::string &url, std::string &file); + void put(std::string &url, std::string &file); HTTPRequest popRequest(); void sendHeaders(); TCPSocket *m_socket; - HTTPHeaders m_recv_headers; - HTTPHeaders m_send_headers; + HTTPResponseHeaders m_recv_headers; + HTTPRequestHeaders m_send_headers; std::string m_cookie; std::vector m_requests; JMutex m_req_mutex; diff --git a/src/main.cpp b/src/main.cpp index 8da9175..ba7a7b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -443,6 +443,7 @@ Doing currently: #include "content_craft.h" #include "content_craftitem.h" #include "content_toolitem.h" +#include "path.h" // This makes textures ITextureSource *g_texturesource = NULL; diff --git a/src/path.cpp b/src/path.cpp new file mode 100644 index 0000000..81d6726 --- /dev/null +++ b/src/path.cpp @@ -0,0 +1,191 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "path.h" +#include "debug.h" +#include "main.h" // for g_settings +#include "filesys.h" +#include "utility.h" +#include "settings.h" + + +/* + A cache from texture name to texture path +*/ +MutexedMap g_texturename_to_path_cache; +MutexedMap g_modelname_to_path_cache; + +/* + Replaces the filename extension. + eg: + std::string image = "a/image.png" + replace_ext(image, "jpg") + -> image = "a/image.jpg" + Returns true on success. +*/ +static bool replace_ext(std::string &path, const char *ext) +{ + if(ext == NULL) + return false; + // Find place of last dot, fail if \ or / found. + s32 last_dot_i = -1; + for(s32 i=path.size()-1; i>=0; i--) + { + if(path[i] == '.') + { + last_dot_i = i; + break; + } + + if(path[i] == '\\' || path[i] == '/') + break; + } + // If not found, return an empty string + if(last_dot_i == -1) + return false; + // Else make the new path + path = path.substr(0, last_dot_i+1) + ext; + return true; +} + +/* + Find out the full path of an image by trying different filename + extensions. + + If failed, return "". +*/ +static std::string getImagePath(std::string path) +{ + // A NULL-ended list of possible image extensions + const char *extensions[] = { + "png", "jpg", "bmp", "tga", + "pcx", "ppm", "psd", "wal", "rgb", + NULL + }; + + const char **ext = extensions; + do{ + bool r = replace_ext(path, *ext); + if(r == false) + return ""; + if(fs::PathExists(path)) + return path; + } + while((++ext) != NULL); + + return ""; +} + +/* + Gets the path to a texture by first checking if the texture exists + in data_path and if not, using the default data path. + + Checks all supported extensions by replacing the original extension. + + If not found, returns "". + + Utilizes a thread-safe cache. +*/ +std::string getTexturePath(const std::string &filename) +{ + std::string fullpath = ""; + /* + Check from cache + */ + bool incache = g_texturename_to_path_cache.get(filename, &fullpath); + if (incache && fullpath != "") + return fullpath; + + std::string rel_path = std::string("textures")+DIR_DELIM+filename; + /* + Check from data_path /textures + */ + std::string data_path = g_settings->get("data_path"); + if(data_path != "") + { + std::string testpath = data_path + DIR_DELIM + rel_path; + // Check all filename extensions. Returns "" if not found. + fullpath = getImagePath(testpath); + } + + /* + Check from default data directory + */ + if(fullpath == "") + { + std::string testpath = porting::path_data + DIR_DELIM + rel_path; + // Check all filename extensions. Returns "" if not found. + fullpath = getImagePath(testpath); + } + + // Add to cache (also an empty result is cached) + g_texturename_to_path_cache.set(filename, fullpath); + + // Finally return it + return fullpath; +} + +/* + Gets the path to a model by first checking if the model exists + in data_path and if not, using the default data path. + + Checks all supported extensions by replacing the original extension. + + If not found, returns "". + + Utilizes a thread-safe cache. +*/ +std::string getModelPath(const std::string &filename) +{ + std::string fullpath = ""; + /* + Check from cache + */ + bool incache = g_modelname_to_path_cache.get(filename, &fullpath); + if(incache) + return fullpath; + + std::string rel_path = std::string("models")+DIR_DELIM+filename; + /* + Check from data_path /models + */ + std::string data_path = g_settings->get("data_path"); + if(data_path != "") + { + std::string testpath = data_path + DIR_DELIM + rel_path; + if(fs::PathExists(testpath)) + fullpath = std::string(testpath); + } + + /* + Check from default data directory + */ + if(fullpath == "") + { + std::string testpath = porting::path_data + DIR_DELIM + rel_path; + if(fs::PathExists(testpath)) + fullpath = std::string(testpath); + } + + // Add to cache (also an empty result is cached) + g_modelname_to_path_cache.set(filename, fullpath); + + // Finally return it + return fullpath; +} diff --git a/src/path.h b/src/path.h new file mode 100644 index 0000000..fd4ea2f --- /dev/null +++ b/src/path.h @@ -0,0 +1,39 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef PATH_HEADER +#define PATH_HEADER + +#include "filesys.h" +#include + +/* + Gets the path to a texture/model by first checking if it exists + in data_path and if not, using the default data path. + + Checks all supported extensions by replacing the original extension. + + If not found, returns "". + + Utilizes a thread-safe cache. +*/ +std::string getTexturePath(const std::string &filename); +std::string getModelPath(const std::string &filename); + +#endif diff --git a/src/player.cpp b/src/player.cpp index cca2e78..6b82ef6 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mesh.h" #endif #include "settings.h" -#include "filesys.h" +#include "path.h" Player::Player(): touching_ground(false), diff --git a/src/server.h b/src/server.h index e19e9f9..71f5e18 100644 --- a/src/server.h +++ b/src/server.h @@ -455,6 +455,19 @@ public: return ""; return p->getCookie(); } + std::string getPlayerFromCookie(std::string &cookie) + { + core::list players = m_env.getPlayers(); + for (core::list::Iterator i = players.begin(); i != players.end(); i++) { + Player *player = *i; + if (player->getCookie() == cookie) + return player->getName(); + } + return std::string(""); + } + Player *getPlayer(std::string name) {return m_env.getPlayer(name.c_str());} + core::list getPlayers() {return m_env.getPlayers();} + core::list getPlayers(bool ign_disconnected) {return m_env.getPlayers(ign_disconnected);} // Saves g_settings to configpath given at initialization void saveConfig(); diff --git a/src/sha1.cpp b/src/sha1.cpp index 8fc6d35..ec0763a 100644 --- a/src/sha1.cpp +++ b/src/sha1.cpp @@ -169,6 +169,20 @@ void SHA1::addBytes( const char* data, int num ) } } +void SHA1::addFile(const char* file) +{ + char buff[2048]; + size_t l; + FILE *f; + f = fopen(file,"rb"); + if (!f) + return; + while ((l = fread(buff,1,2048,f)) > 0) { + addBytes(buff,l); + } + fclose(f); +} + // digest ************************************************************ unsigned char* SHA1::getDigest() { @@ -205,3 +219,16 @@ unsigned char* SHA1::getDigest() // return the digest return digest; } + +int SHA1::getDigest(char* buff) +{ + int l; + int t = 0; + unsigned char* d = getDigest(); + for (int i=0; i<20; i++) { + l = sprintf(buff,"%02x",d[i]); + buff += l; + t += l; + } + return t; +} diff --git a/src/sha1.h b/src/sha1.h index c049473..7c886bc 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -39,8 +39,10 @@ class SHA1 public: SHA1(); ~SHA1(); - void addBytes( const char* data, int num ); + void addBytes(const char* data, int num ); + void addFile(const char* file); unsigned char* getDigest(); + int getDigest(char* buff); // utility methods static Uint32 lrot( Uint32 x, int bits ); static void storeBigEndianUint32( unsigned char* byte, Uint32 num ); diff --git a/src/tile.cpp b/src/tile.cpp index 0837f72..4efe920 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -28,193 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "mapnode.h" // For texture atlas making #include "mineral.h" // For texture atlas making - -/* - A cache from texture name to texture path -*/ -MutexedMap g_texturename_to_path_cache; -MutexedMap g_modelname_to_path_cache; - -/* - Replaces the filename extension. - eg: - std::string image = "a/image.png" - replace_ext(image, "jpg") - -> image = "a/image.jpg" - Returns true on success. -*/ -static bool replace_ext(std::string &path, const char *ext) -{ - if(ext == NULL) - return false; - // Find place of last dot, fail if \ or / found. - s32 last_dot_i = -1; - for(s32 i=path.size()-1; i>=0; i--) - { - if(path[i] == '.') - { - last_dot_i = i; - break; - } - - if(path[i] == '\\' || path[i] == '/') - break; - } - // If not found, return an empty string - if(last_dot_i == -1) - return false; - // Else make the new path - path = path.substr(0, last_dot_i+1) + ext; - return true; -} - -/* - Find out the full path of an image by trying different filename - extensions. - - If failed, return "". -*/ -static std::string getImagePath(std::string path) -{ - // A NULL-ended list of possible image extensions - const char *extensions[] = { - "png", "jpg", "bmp", "tga", - "pcx", "ppm", "psd", "wal", "rgb", - NULL - }; - - const char **ext = extensions; - do{ - bool r = replace_ext(path, *ext); - if(r == false) - return ""; - if(fs::PathExists(path)) - return path; - } - while((++ext) != NULL); - - return ""; -} - -/* - Gets the path to a texture by first checking if the texture exists - in data_path and if not, using the default data path. - - Checks all supported extensions by replacing the original extension. - - If not found, returns "". - - Utilizes a thread-safe cache. -*/ -std::string getTexturePath(const std::string &filename) -{ - std::string fullpath = ""; - /* - Check from cache - */ - bool incache = g_texturename_to_path_cache.get(filename, &fullpath); - if (incache && fullpath != "") - return fullpath; - - std::string rel_path = std::string("textures")+DIR_DELIM+filename; - - /* - Check from user data directory - */ - if(fullpath == "") - { - std::string testpath = porting::path_userdata + DIR_DELIM + rel_path; - // Check all filename extensions. Returns "" if not found. - fullpath = getImagePath(testpath); - } - - /* - Check from data_path /textures - */ - std::string data_path = g_settings->get("data_path"); - if(data_path != "") - { - std::string testpath = data_path + DIR_DELIM + rel_path; - // Check all filename extensions. Returns "" if not found. - fullpath = getImagePath(testpath); - } - - /* - Check from default data directory - */ - if(fullpath == "") - { - std::string testpath = porting::path_data + DIR_DELIM + rel_path; - // Check all filename extensions. Returns "" if not found. - fullpath = getImagePath(testpath); - } - - // Add to cache (also an empty result is cached) - g_texturename_to_path_cache.set(filename, fullpath); - - // Finally return it - return fullpath; -} - -/* - Gets the path to a model by first checking if the model exists - in data_path and if not, using the default data path. - - Checks all supported extensions by replacing the original extension. - - If not found, returns "". - - Utilizes a thread-safe cache. -*/ -std::string getModelPath(const std::string &filename) -{ - std::string fullpath = ""; - /* - Check from cache - */ - bool incache = g_modelname_to_path_cache.get(filename, &fullpath); - if(incache) - return fullpath; - - std::string rel_path = std::string("models")+DIR_DELIM+filename; - - /* - Check from user data directory - */ - if(fullpath == "") - { - std::string testpath = porting::path_userdata + DIR_DELIM + rel_path; - // Check all filename extensions. Returns "" if not found. - fullpath = getImagePath(testpath); - } - - /* - Check from data_path /models - */ - std::string data_path = g_settings->get("data_path"); - if(data_path != "") - { - std::string testpath = data_path + DIR_DELIM + rel_path; - if(fs::PathExists(testpath)) - fullpath = std::string(testpath); - } - - /* - Check from default data directory - */ - if(fullpath == "") - { - std::string testpath = porting::path_data + DIR_DELIM + rel_path; - if(fs::PathExists(testpath)) - fullpath = std::string(testpath); - } - - // Add to cache (also an empty result is cached) - g_modelname_to_path_cache.set(filename, fullpath); - - // Finally return it - return fullpath; -} +#include "path.h" /* TextureSource diff --git a/src/tile.h b/src/tile.h index 1c1d135..262c2ba 100644 --- a/src/tile.h +++ b/src/tile.h @@ -31,23 +31,6 @@ using namespace jthread; tile.{h,cpp}: Texture handling stuff. */ -/* - Gets the path to a texture/model by first checking if it exists - in data_path and if not, using the default data path. - - Checks all supported extensions by replacing the original extension. - - If not found, returns "". - - Utilizes a thread-safe cache. -*/ -std::string getTexturePath(const std::string &filename); -std::string getModelPath(const std::string &filename); - -u32 parseImageTransform(const std::string& s); -core::dimension2d imageTransformDimension(u32 transform, core::dimension2d dim); -void imageTransform(u32 transform, video::IImage *src, video::IImage *dst); - /* Specifies a texture in an atlas.