summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2005-07-25 00:19:33 +0000
committerBjørn Lindeijer <bjorn@lindeijer.nl>2005-07-25 00:19:33 +0000
commitcf471fa3f8b7aec3d44db4515536c78098a6011a (patch)
tree7a876b4cd15b4ab2a0b2f133fb1cfccfbee725d9
parentb54666222ca5020438aa9151a51a295269b1b319 (diff)
downloadmanaserv-cf471fa3f8b7aec3d44db4515536c78098a6011a.tar.gz
manaserv-cf471fa3f8b7aec3d44db4515536c78098a6011a.tar.xz
manaserv-cf471fa3f8b7aec3d44db4515536c78098a6011a.zip
Added modified Map, MapReader, ResourceManager classes and base64 functions
from client to server. Nothing tested yet, just made sure it still compiled.
-rw-r--r--configure.ac8
-rw-r--r--src/.cvsignore1
-rw-r--r--src/Makefile.am8
-rw-r--r--src/being.cpp5
-rw-r--r--src/being.h9
-rw-r--r--src/connectionhandler.cpp6
-rw-r--r--src/map.cpp335
-rw-r--r--src/map.h196
-rw-r--r--src/mapreader.cpp393
-rw-r--r--src/mapreader.h113
-rw-r--r--src/netsession.cpp2
-rw-r--r--src/resourcemanager.cpp201
-rw-r--r--src/resourcemanager.h89
-rw-r--r--src/tests/.cvsignore2
-rw-r--r--src/utils/base64.cpp152
-rw-r--r--src/utils/base64.h44
16 files changed, 1559 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac
index 82419a5..0a03bbf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,10 +16,14 @@ AC_PROG_INSTALL
# Checks for libraries.
+
AC_CHECK_LIB([crypto], [EVP_md5])
-AC_CHECK_LIB([physfs], [PHYSFS_init])
-PKG_CHECK_MODULES(XML2,[libxml-2.0])
+AC_CHECK_LIB([physfs], [PHYSFS_init], ,
+AC_MSG_ERROR([ *** Unable to find PhysFS library (icculus.org/physfs/)]))
+
+
+PKG_CHECK_MODULES(XML2, [libxml-2.0 >= 2.4])
CXXFLAGS="$CXXFLAGS $XML2_CFLAGS"
LIBS="$LIBS $XML2_LIBS"
diff --git a/src/.cvsignore b/src/.cvsignore
index 282522d..becb0e9 100644
--- a/src/.cvsignore
+++ b/src/.cvsignore
@@ -1,2 +1,3 @@
Makefile
Makefile.in
+tmwserv
diff --git a/src/Makefile.am b/src/Makefile.am
index affba32..7ecc74e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,6 +18,10 @@ tmwserv_SOURCES = main.cpp \
debug.cpp \
defines.h \
items.h \
+ map.cpp \
+ map.h \
+ mapreader.cpp \
+ mapreader.h \
messagehandler.h \
messagehandler.cpp \
messagein.h \
@@ -32,6 +36,8 @@ tmwserv_SOURCES = main.cpp \
packet.cpp \
skill.h \
skill.cpp \
+ resourcemanager.cpp \
+ resourcemanager.h \
storage.h \
storage.cpp \
account.h \
@@ -49,6 +55,8 @@ tmwserv_SOURCES = main.cpp \
dal/dataproviderfactory.cpp \
dal/recordset.h \
dal/recordset.cpp \
+ utils/base64.h \
+ utils/base64.cpp \
utils/countedptr.h \
utils/functors.h \
utils/singleton.h \
diff --git a/src/being.cpp b/src/being.cpp
index d3df77f..0aa3d45 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -28,6 +28,11 @@ namespace tmwserv
{
+PATH_NODE::PATH_NODE(unsigned short x, unsigned short y):
+ x(x), y(y)
+{
+}
+
/**
* Constructor.
*/
diff --git a/src/being.h b/src/being.h
index 2ebbd8c..47766ea 100644
--- a/src/being.h
+++ b/src/being.h
@@ -37,6 +37,15 @@ namespace tmwserv
{
+struct PATH_NODE {
+ /**
+ * Constructor.
+ */
+ PATH_NODE(unsigned short x, unsigned short y);
+
+ unsigned short x, y;
+};
+
/**
* Structure type for the raw statistics of a Being.
*/
diff --git a/src/connectionhandler.cpp b/src/connectionhandler.cpp
index 6a46b94..2583e3f 100644
--- a/src/connectionhandler.cpp
+++ b/src/connectionhandler.cpp
@@ -144,8 +144,10 @@ ConnectionHandler::startListen(ListenThreadData *ltd)
}
// Check client sockets
- std::list<NetComputer*>::iterator i;
- for (i = clients.begin(); i != clients.end(); ) {
+ NetComputers::iterator i;
+
+ for (i = clients.begin(); i != clients.end(); )
+ {
NetComputer *comp = *i;
TCPsocket s = (*i)->getSocket();
diff --git a/src/map.cpp b/src/map.cpp
new file mode 100644
index 0000000..cb992de
--- /dev/null
+++ b/src/map.cpp
@@ -0,0 +1,335 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "map.h"
+
+#include <queue>
+
+namespace tmwserv
+{
+
+
+MetaTile::MetaTile():
+ whichList(0)
+{
+}
+
+
+Location::Location(int x, int y, MetaTile *tile):
+ x(x), y(y), tile(tile)
+{
+}
+
+bool Location::operator< (const Location &loc) const
+{
+ return tile->Fcost > loc.tile->Fcost;
+}
+
+
+Map::Map():
+ width(0), height(0),
+ tileWidth(32), tileHeight(32),
+ onClosedList(1), onOpenList(2)
+{
+ metaTiles = new MetaTile[width * height];
+}
+
+Map::Map(int width, int height):
+ width(width), height(height),
+ tileWidth(32), tileHeight(32),
+ onClosedList(1), onOpenList(2)
+{
+ metaTiles = new MetaTile[width * height];
+}
+
+Map::~Map()
+{
+ delete[] metaTiles;
+}
+
+void
+Map::setSize(int width, int height)
+{
+ this->width = width;
+ this->height = height;
+ delete[] metaTiles;
+ metaTiles = new MetaTile[width * height];
+}
+
+void
+Map::setWalk(int x, int y, bool walkable)
+{
+ metaTiles[x + y * width].walkable = walkable;
+}
+
+bool
+Map::getWalk(int x, int y)
+{
+ // If walkable, check for colliding into a being
+ if (!tileCollides(x, y))
+ {
+ /*
+ std::list<Being*>::iterator i = beings.begin();
+ while (i != beings.end()) {
+ Being *being = (*i);
+ // Collision when non-portal being is found at this location
+ if (being->x == x && being->y == y && being->job != 45) {
+ return false;
+ }
+ i++;
+ }
+ */
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool
+Map::tileCollides(int x, int y)
+{
+ // You can't walk outside of the map
+ if (x < 0 || y < 0 || x >= width || y >= height) {
+ return true;
+ }
+
+ // Check if the tile is walkable
+ return !metaTiles[x + y * width].walkable;
+}
+
+MetaTile*
+Map::getMetaTile(int x, int y)
+{
+ return &metaTiles[x + y * width];
+}
+
+int
+Map::getWidth()
+{
+ return width;
+}
+
+int
+Map::getHeight()
+{
+ return height;
+}
+
+int
+Map::getTileWidth()
+{
+ return tileWidth;
+}
+
+int
+Map::getTileHeight()
+{
+ return tileHeight;
+}
+
+std::string
+Map::getProperty(const std::string &name)
+{
+ std::map<std::string,std::string>::iterator i = properties.find(name);
+
+ if (i != properties.end())
+ {
+ return (*i).second;
+ }
+
+ return "";
+}
+
+bool
+Map::hasProperty(const std::string &name)
+{
+ return (properties.find(name) != properties.end());
+}
+
+void
+Map::setProperty(const std::string &name, const std::string &value)
+{
+ properties[name] = value;
+}
+
+std::list<PATH_NODE>
+Map::findPath(int startX, int startY, int destX, int destY)
+{
+ // Path to be built up (empty by default)
+ std::list<PATH_NODE> path;
+
+ // Declare open list, a list with open tiles sorted on F cost
+ std::priority_queue<Location> openList;
+
+ // Return when destination not walkable
+ if (!getWalk(destX, destY)) return path;
+
+ // Reset starting tile's G cost to 0
+ MetaTile *startTile = getMetaTile(startX, startY);
+ startTile->Gcost = 0;
+
+ // Add the start point to the open list
+ openList.push(Location(startX, startY, startTile));
+
+ bool foundPath = false;
+
+ // Keep trying new open tiles until no more tiles to try or target found
+ while (!openList.empty() && !foundPath)
+ {
+ // Take the location with the lowest F cost from the open list, and
+ // add it to the closed list.
+ Location curr = openList.top();
+ openList.pop();
+
+ // If the tile is already on the closed list, this means it has already
+ // been processed with a shorter path to the start point (lower G cost)
+ if (curr.tile->whichList == onClosedList)
+ {
+ continue;
+ }
+
+ // Put the current tile on the closed list
+ curr.tile->whichList = onClosedList;
+
+ // Check the adjacent tiles
+ for (int dy = -1; dy <= 1; dy++)
+ {
+ for (int dx = -1; dx <= 1; dx++)
+ {
+ // Calculate location of tile to check
+ int x = curr.x + dx;
+ int y = curr.y + dy;
+
+ // Skip if if we're checking the same tile we're leaving from,
+ // or if the new location falls outside of the map boundaries
+ if ((dx == 0 && dy == 0) ||
+ (x < 0 || y < 0 || x >= width || y >= height))
+ {
+ continue;
+ }
+
+ MetaTile *newTile = getMetaTile(x, y);
+
+ // Skip if the tile is on the closed list or is not walkable
+ if (newTile->whichList == onClosedList || !getWalk(x, y))
+ {
+ continue;
+ }
+
+ // When taking a diagonal step, verify that we can skip the
+ // corner. We allow skipping past beings but not past non-
+ // walkable tiles.
+ if (dx != 0 && dy != 0)
+ {
+ MetaTile *t1 = getMetaTile(curr.x, curr.y + dy);
+ MetaTile *t2 = getMetaTile(curr.x + dx, curr.y);
+
+ if (!(t1->walkable && t2->walkable))
+ {
+ continue;
+ }
+ }
+
+ // Calculate G cost for this route, 10 for moving straight and
+ // 14 for moving diagonal
+ int Gcost = curr.tile->Gcost + ((dx == 0 || dy == 0) ? 10 : 14);
+
+ // Skip if Gcost becomes too much
+ // Warning: probably not entirely accurate
+ if (Gcost > 200)
+ {
+ continue;
+ }
+
+ if (newTile->whichList != onOpenList)
+ {
+ // Found a new tile (not on open nor on closed list)
+ // Update Hcost of the new tile using Manhatten distance
+ newTile->Hcost = 10 * (abs(x - destX) + abs(y - destY));
+
+ // Set the current tile as the parent of the new tile
+ newTile->parentX = curr.x;
+ newTile->parentY = curr.y;
+
+ // Update Gcost and Fcost of new tile
+ newTile->Gcost = Gcost;
+ newTile->Fcost = newTile->Gcost + newTile->Hcost;
+
+ if (x != destX || y != destY) {
+ // Add this tile to the open list
+ newTile->whichList = onOpenList;
+ openList.push(Location(x, y, newTile));
+ }
+ else {
+ // Target location was found
+ foundPath = true;
+ }
+ }
+ else if (Gcost < newTile->Gcost)
+ {
+ // Found a shorter route.
+ // Update Gcost and Fcost of the new tile
+ newTile->Gcost = Gcost;
+ newTile->Fcost = newTile->Gcost + newTile->Hcost;
+
+ // Set the current tile as the parent of the new tile
+ newTile->parentX = curr.x;
+ newTile->parentY = curr.y;
+
+ // Add this tile to the open list (it's already
+ // there, but this instance has a lower F score)
+ openList.push(Location(x, y, newTile));
+ }
+ }
+ }
+ }
+
+ // Two new values to indicate whether a tile is on the open or closed list,
+ // this way we don't have to clear all the values between each pathfinding.
+ onClosedList += 2;
+ onOpenList += 2;
+
+ // If a path has been found, iterate backwards using the parent locations
+ // to extract it.
+ if (foundPath)
+ {
+ int pathX = destX;
+ int pathY = destY;
+
+ while (pathX != startX || pathY != startY)
+ {
+ // Add the new path node to the start of the path list
+ path.push_front(PATH_NODE(pathX, pathY));
+
+ // Find out the next parent
+ MetaTile *tile = getMetaTile(pathX, pathY);
+ pathX = tile->parentX;
+ pathY = tile->parentY;
+ }
+ }
+
+ return path;
+}
+
+} // namespace tmwserv
diff --git a/src/map.h b/src/map.h
new file mode 100644
index 0000000..99e0a2a
--- /dev/null
+++ b/src/map.h
@@ -0,0 +1,196 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_MAP_H
+#define _TMW_MAP_H
+
+#include "being.h"
+#include <list>
+#include <map>
+#include <string>
+
+namespace tmwserv
+{
+
+
+struct PATH_NODE;
+
+/**
+ * A meta tile stores additional information about a location on a tile map.
+ * This is information that doesn't need to be repeated for each tile in each
+ * layer of the map.
+ */
+class MetaTile
+{
+ public:
+ /**
+ * Constructor.
+ */
+ MetaTile();
+
+ // Pathfinding members
+ int Fcost; /**< Estimation of total path cost */
+ int Gcost; /**< Cost from start to this location */
+ int Hcost; /**< Estimated cost to goal */
+ int whichList; /**< No list, open list or closed list */
+ int parentX; /**< X coordinate of parent tile */
+ int parentY; /**< Y coordinate of parent tile */
+ bool walkable; /**< Can beings walk on this tile */
+};
+
+/**
+ * A location on a tile map. Used for pathfinding, open list.
+ */
+class Location
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Location(int x, int y, MetaTile *tile);
+
+ /**
+ * Comparison operator.
+ */
+ bool operator< (const Location &loc) const;
+
+ int x, y;
+ MetaTile *tile;
+};
+
+/**
+ * A tile map.
+ */
+class Map
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Map();
+
+ /**
+ * Constructor that takes initial map size as parameters.
+ */
+ Map(int width, int height);
+
+ /**
+ * Destructor.
+ */
+ ~Map();
+
+ /**
+ * Sets the size of the map. This will destroy any existing map data.
+ */
+ void
+ setSize(int width, int height);
+
+ /**
+ * Get tile reference.
+ */
+ MetaTile*
+ getMetaTile(int x, int y);
+
+ /**
+ * Set walkability flag for a tile
+ */
+ void
+ setWalk(int x, int y, bool walkable);
+
+ /**
+ * Tell if a tile is walkable or not, includes checking beings.
+ */
+ bool
+ getWalk(int x, int y);
+
+ /**
+ * Tell if a tile collides, not including a check on beings.
+ */
+ bool
+ tileCollides(int x, int y);
+
+ /**
+ * Returns the width of this map.
+ */
+ int
+ getWidth();
+
+ /**
+ * Returns the height of this map.
+ */
+ int
+ getHeight();
+
+ /**
+ * Returns the tile width of this map.
+ */
+ int
+ getTileWidth();
+
+ /**
+ * Returns the tile height used by this map.
+ */
+ int
+ getTileHeight();
+
+ /**
+ * Find a path from one location to the next.
+ */
+ std::list<PATH_NODE>
+ findPath(int startX, int startY,
+ int destX, int destY);
+
+ /**
+ * Get a map property.
+ *
+ * @return the value of the given property or an empty string when it
+ * doesn't exist.
+ */
+ std::string
+ getProperty(const std::string &name);
+
+ /**
+ * Returns whether a certain property is available.
+ */
+ bool
+ hasProperty(const std::string &name);
+
+ /**
+ * Set a map property.
+ */
+ void
+ setProperty(const std::string &name, const std::string &value);
+
+ private:
+ int width, height;
+ int tileWidth, tileHeight;
+ MetaTile *metaTiles;
+ std::map<std::string, std::string> properties;
+
+ // Pathfinding members
+ int onClosedList, onOpenList;
+};
+
+} // namespace tmwserv
+
+#endif
diff --git a/src/mapreader.cpp b/src/mapreader.cpp
new file mode 100644
index 0000000..15623b1
--- /dev/null
+++ b/src/mapreader.cpp
@@ -0,0 +1,393 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "utils/logger.h"
+#include "utils/base64.h"
+#include "mapreader.h"
+#include "resourcemanager.h"
+
+#include <cassert>
+
+#include <zlib.h>
+#include <iostream>
+
+namespace tmwserv
+{
+
+
+const unsigned int DEFAULT_TILE_WIDTH = 32;
+const unsigned int DEFAULT_TILE_HEIGHT = 32;
+
+// MSVC libxml2 at the moment doesn't work right when using MinGW, missing this
+// function at link time.
+#ifdef WIN32
+#undef xmlFree
+#define xmlFree(x) ;
+#endif
+
+/**
+ * Inflates either zlib or gzip deflated memory. The inflated memory is
+ * expected to be freed by the caller.
+ */
+int
+inflateMemory(
+ unsigned char *in, unsigned int inLength,
+ unsigned char *&out, unsigned int &outLength)
+{
+ int bufferSize = 256 * 1024;
+ int ret;
+ z_stream strm;
+
+ out = (unsigned char*)malloc(bufferSize);
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.next_in = in;
+ strm.avail_in = inLength;
+ strm.next_out = out;
+ strm.avail_out = bufferSize;
+
+ ret = inflateInit2(&strm, 15 + 32);
+
+ if (ret != Z_OK)
+ return ret;
+
+ do
+ {
+ if (strm.next_out == NULL)
+ {
+ inflateEnd(&strm);
+ return Z_MEM_ERROR;
+ }
+
+ ret = inflate(&strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR);
+
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&strm);
+ return ret;
+ }
+
+ if (ret != Z_STREAM_END)
+ {
+ out = (unsigned char*)realloc(out, bufferSize * 2);
+
+ if (out == NULL)
+ {
+ inflateEnd(&strm);
+ return Z_MEM_ERROR;
+ }
+
+ strm.next_out = out + bufferSize;
+ strm.avail_out = bufferSize;
+ bufferSize *= 2;
+ }
+ }
+ while (ret != Z_STREAM_END);
+ assert(strm.avail_in == 0);
+
+ outLength = bufferSize - strm.avail_out;
+ (void)inflateEnd(&strm);
+ return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
+std::vector<Tileset*> MapReader::tilesets;
+
+Map *MapReader::readMap(const std::string &filename)
+{
+ // Load the file through resource manager
+ ResourceManager *resman = ResourceManager::getInstance();
+ int fileSize;
+ void *buffer = resman->loadFile(filename, fileSize);
+
+ if (buffer == NULL)
+ {
+ LOG_ERROR("Map file not found (" << filename.c_str() << ")");
+ return NULL;
+ }
+
+ // Inflate the gzipped map data
+ unsigned char *inflated;
+ unsigned int inflatedSize = 0;
+ int ret = inflateMemory((unsigned char*)buffer, fileSize,
+ inflated, inflatedSize);
+ free(buffer);
+
+ if (ret == Z_MEM_ERROR)
+ {
+ LOG_ERROR("Error: Out of memory while decompressing map data!");
+ return NULL;
+ }
+ else if (ret == Z_VERSION_ERROR)
+ {
+ LOG_ERROR("Error: Incompatible zlib version!");
+ return NULL;
+ }
+ else if (ret == Z_DATA_ERROR)
+ {
+ LOG_ERROR("Error: Incorrect zlib compressed data!");
+ return NULL;
+ }
+ else if (ret != Z_OK || inflated == NULL)
+ {
+ LOG_ERROR("Error: Unknown error while decompressing map data!");
+ return NULL;
+ }
+
+ xmlDocPtr doc = xmlParseMemory((char*)inflated, inflatedSize);
+ free(inflated);
+
+ // Parse the inflated map data
+ if (doc) {
+ xmlNodePtr node = xmlDocGetRootElement(doc);
+
+ if (!node || !xmlStrEqual(node->name, BAD_CAST "map")) {
+ LOG_ERROR("Error: Not a map file (" << filename << ")!");
+ return NULL;
+ }
+
+ return readMap(node, filename);
+ xmlFreeDoc(doc);
+ } else {
+ LOG_ERROR("Error while parsing map file (" << filename << ")!");
+ }
+
+ return NULL;
+}
+
+Map* MapReader::readMap(xmlNodePtr node, const std::string &path)
+{
+ xmlChar *prop;
+
+ // Take the filename off the path
+ std::string pathDir = path.substr(0, path.rfind("/") + 1);
+
+ prop = xmlGetProp(node, BAD_CAST "version");
+ xmlFree(prop);
+
+ int w = getProperty(node, "width", 0);
+ int h = getProperty(node, "height", 0);
+ // We only support tile width of 32 at the moment
+ //int tilew = getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
+ //int tileh = getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
+ int layerNr = 0;
+ Map* map = new Map(w, h);
+
+ for (node = node->xmlChildrenNode; node != NULL; node = node->next)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "property"))
+ {
+ // Example: <property name="name" value="value"/>
+
+ xmlChar *name = xmlGetProp(node, BAD_CAST "name");
+ xmlChar *value = xmlGetProp(node, BAD_CAST "value");
+
+ if (name && value)
+ {
+ map->setProperty((const char*)name, (const char*)value);
+ }
+
+ if (name) xmlFree(name);
+ if (value) xmlFree(value);
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "tileset"))
+ {
+ Tileset *tileset = readTileset(node, pathDir, map);
+ if (tileset) {
+ tilesets.push_back(tileset);
+ }
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "layer"))
+ {
+ LOG_INFO("- Loading layer " << layerNr);
+ readLayer(node, map, layerNr);
+ layerNr++;
+ }
+ }
+
+ // Clean up tilesets
+ // TODO: Dereference them somewhere
+ tilesets.clear();
+
+ return map;
+}
+
+void MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
+{
+ node = node->xmlChildrenNode;
+ int h = map->getHeight();
+ int w = map->getWidth();
+ int x = 0;
+ int y = 0;
+
+ // Load the tile data. Layers are assumed to be map size, with (0,0) as
+ // origin.
+ while (node != NULL)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "data"))
+ {
+ xmlChar *encoding = xmlGetProp(node, BAD_CAST "encoding");
+ xmlChar *compression = xmlGetProp(node, BAD_CAST "compression");
+
+ if (encoding && xmlStrEqual(encoding, BAD_CAST "base64"))
+ {
+ xmlFree(encoding);
+
+ if (compression) {
+ LOG_WARN("Warning: no layer compression supported!");
+ xmlFree(compression);
+ return;
+ }
+
+ // Read base64 encoded map file
+ xmlNodePtr dataChild = node->xmlChildrenNode;
+ if (!dataChild) continue;
+
+ int len = strlen((const char*)dataChild->content) + 1;
+ unsigned char *charData = new unsigned char[len + 1];
+ const char *charStart = (const char*)dataChild->content;
+ unsigned char *charIndex = charData;
+
+ while (*charStart) {
+ if (*charStart != ' ' && *charStart != '\t' &&
+ *charStart != '\n')
+ {
+ *charIndex = *charStart;
+ charIndex++;
+ }
+ charStart++;
+ }
+ *charIndex = '\0';
+
+ int binLen;
+ unsigned char *binData =
+ php_base64_decode(charData, strlen((char*)charData),
+ &binLen);
+
+ delete[] charData;
+
+ if (binData) {
+ for (int i = 0; i < binLen - 3; i += 4) {
+ int gid = binData[i] |
+ binData[i + 1] << 8 |
+ binData[i + 2] << 16 |
+ binData[i + 3] << 24;
+
+ setTileWithGid(map, x, y, layer, gid);
+
+ x++;
+ if (x == w) {x = 0; y++;}
+ }
+ free(binData);
+ }
+ }
+ else {
+ // Read plain XML map file
+ xmlNodePtr n2 = node->xmlChildrenNode;
+
+ while (n2 != NULL)
+ {
+ if (xmlStrEqual(n2->name, BAD_CAST "tile") && y < h)
+ {
+ int gid = getProperty(n2, "gid", -1);
+ setTileWithGid(map, x, y, layer, gid);
+
+ x++;
+ if (x == w) {x = 0; y++;}
+ }
+
+ n2 = n2->next;
+ }
+ }
+
+ // There can be only one data element
+ break;
+ }
+
+ node = node->next;
+ }
+}
+
+Tileset*
+MapReader::readTileset(xmlNodePtr node, const std::string &path, Map *map)
+{
+ if (xmlHasProp(node, BAD_CAST "source")) {
+ LOG_WARN("Warning: External tilesets not supported yet.");
+ return NULL;
+ }
+
+ int firstGid = getProperty(node, "firstgid", 0);
+ int tw = getProperty(node, "tilewidth", map->getTileWidth());
+ int th = getProperty(node, "tileheight", map->getTileHeight());
+
+ return new Tileset(tw, th, firstGid);
+}
+
+int MapReader::getProperty(xmlNodePtr node, const char* name, int def)
+{
+ xmlChar *prop = xmlGetProp(node, BAD_CAST name);
+ if (prop) {
+ int val = atoi((char*)prop);
+ xmlFree(prop);
+ return val;
+ }
+ else {
+ return def;
+ }
+}
+
+Tileset *MapReader::getTilesetWithGid(int gid)
+{
+ std::vector<Tileset*>::iterator i;
+ Tileset *set = NULL;
+
+ // Find the tileset with the highest firstGid below/eq to gid
+ for (i = tilesets.begin(); i != tilesets.end(); ++i)
+ {
+ if ((*i)->getFirstGid() <= gid) {
+ set = (*i);
+ }
+ else {
+ break;
+ }
+ }
+
+ return set;
+}
+
+void MapReader::setTileWithGid(Map *map, int x, int y, int layer, int gid)
+{
+ // Only load obstacle layer
+ if (layer == 3)
+ {
+ Tileset *set = getTilesetWithGid(gid);
+ map->setWalk(x, y, !set || (gid - set->getFirstGid() == 0));
+ }
+}
+
+} // namespace tmwserv
diff --git a/src/mapreader.h b/src/mapreader.h
new file mode 100644
index 0000000..7d89a8a
--- /dev/null
+++ b/src/mapreader.h
@@ -0,0 +1,113 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _INCLUDED_MAPREADER_H
+#define _INCLUDED_MAPREADER_H
+
+#include "map.h"
+#include <libxml/tree.h>
+#include <vector>
+
+namespace tmwserv
+{
+
+
+/**
+ * A tileset, which is on the server only used to store a firstgid.
+ */
+class Tileset
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Tileset(int w, int h, int firstGid):
+ mFirstGid(firstGid)
+ {
+ }
+
+ /**
+ * Returns the first gid.
+ */
+ int
+ getFirstGid() { return mFirstGid; }
+
+ private:
+ int mFirstGid;
+};
+
+/**
+ * Reader for XML map files (*.tmx)
+ */
+class MapReader
+{
+ public:
+ /**
+ * Read an XML map from a file.
+ */
+ static Map *readMap(const std::string &filename);
+
+ /**
+ * Read an XML map from a parsed XML tree. The path is used to find the
+ * location of referenced tileset images.
+ */
+ static Map *readMap(xmlNodePtr node, const std::string &path);
+
+ private:
+ /**
+ * Reads a map layer.
+ */
+ static void
+ readLayer(xmlNodePtr node, Map *map, int layer);
+
+ /**
+ * Reads a tile set.
+ */
+ static Tileset*
+ readTileset(xmlNodePtr node, const std::string &path, Map *map);
+
+ /**
+ * Gets an integer property from an xmlNodePtr.
+ */
+ static int
+ getProperty(xmlNodePtr node, const char* name, int def);
+
+ /**
+ * Finds the tile set that a tile with the given global id is part of.
+ */
+ static Tileset*
+ getTilesetWithGid(int gid);
+
+ /**
+ * Sets a tile using a global tile id. Used by the layer loading
+ * routine.
+ */
+ static void
+ setTileWithGid(Map *map, int x, int y, int layer, int gid);
+
+ static std::vector<Tileset*> tilesets;
+};
+
+} // namespace tmwserv
+
+#endif
diff --git a/src/netsession.cpp b/src/netsession.cpp
index f4f7721..130b18a 100644
--- a/src/netsession.cpp
+++ b/src/netsession.cpp
@@ -116,7 +116,7 @@ NetComputer *NetSession::connect(const std::string &host, Uint16 port)
// An asynchroneous wrapper could be created around this method.
IPaddress address;
-
+
if (!SDLNet_ResolveHost(&address, host.c_str(), port))
{
TCPsocket tcpsock = SDLNet_TCP_Open(&address);
diff --git a/src/resourcemanager.cpp b/src/resourcemanager.cpp
new file mode 100644
index 0000000..64f4542
--- /dev/null
+++ b/src/resourcemanager.cpp
@@ -0,0 +1,201 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "resourcemanager.h"
+#include "utils/logger.h"
+#include <iostream>
+#include <sstream>
+#include <physfs.h>
+
+#include <cassert>
+
+#ifdef WIN32
+#include <io.h>
+#include <direct.h>
+#else
+#include <unistd.h>
+#include <dirent.h>
+#endif
+
+#define TMW_DATADIR ""
+
+ResourceManager *ResourceManager::instance = NULL;
+
+ResourceManager::ResourceManager()
+{
+ // Add zip files to PhysicsFS
+ searchAndAddZipFiles();
+}
+
+ResourceManager::~ResourceManager()
+{
+}
+
+ResourceManager*
+ResourceManager::getInstance()
+{
+ // Create a new instance if necessary.
+ if (instance == NULL) instance = new ResourceManager();
+ return instance;
+}
+
+void
+ResourceManager::deleteInstance()
+{
+ if (instance != NULL) {
+ delete instance;
+ instance = NULL;
+ }
+}
+
+void
+ResourceManager::searchAndAddZipFiles()
+{
+ // Add the main data directory to our PhysicsFS search path
+ PHYSFS_addToSearchPath("data", 1);
+ PHYSFS_addToSearchPath(TMW_DATADIR "data", 1);
+
+#ifdef _WIN32
+ // Define the path in which to search
+ std::string searchString = std::string("data/*.zip");
+
+ // Create our find file data structure
+ struct _finddata_t findFileInfo;
+
+ // Find the first zipped file
+ long handle =
+ static_cast<long>(::_findfirst(searchString.c_str(), &findFileInfo));
+ long file = handle;
+
+ // Loop until all files we're searching for are found
+ while (file >= 0) {
+ // Define the file path string
+ std::string filePath = std::string("data/") +
+ std::string(findFileInfo.name);
+
+ LOG_INFO("Adding to PhysicsFS: " << findFileInfo.name);
+
+ // Add the zip file to our PhysicsFS search path
+ PHYSFS_addToSearchPath(filePath.c_str(), 1);
+
+ // Find the next file
+ file = ::_findnext(handle, &findFileInfo);
+ }
+
+ // Shutdown findfile stuff
+ ::_findclose(handle);
+#else
+ // Retrieve the current path
+ char programPath[256];
+ getcwd(programPath, 256);
+ strncat(programPath, "/data", 256 - strlen(programPath) - 1);
+
+ // Create our directory structure
+ DIR *dir = opendir(programPath);
+
+ // Return if the directory is invalid
+ if (dir == NULL) {
+ return;
+ }
+
+ struct dirent *direntry;
+ while ((direntry = readdir(dir)) != NULL)
+ {
+ char *ext = strstr(direntry->d_name, ".zip");
+
+ if (ext != NULL && strcmp(ext, ".zip") == 0)
+ {
+ // Define the file path string
+ std::string filePath = std::string(programPath) +
+ std::string("/") + std::string(direntry->d_name);
+
+ LOG_INFO("Adding to PhysicsFS: " << filePath);
+
+ // Add the zip file to our PhysicsFS search path
+ PHYSFS_addToSearchPath(filePath.c_str(), 1);
+ }
+ }
+
+ closedir(dir);
+#endif
+}
+
+void*
+ResourceManager::loadFile(const std::string &fileName, int &fileSize)
+{
+ // If the file doesn't exist indicate failure
+ if (!PHYSFS_exists(fileName.c_str())) {
+ LOG_WARN("Warning: " << fileName << " not found!");
+ return NULL;
+ }
+
+ // Attempt to open the specified file using PhysicsFS
+ PHYSFS_file* file = PHYSFS_openRead(fileName.c_str());
+
+ // If the handler is an invalid pointer indicate failure
+ if (file == NULL) {
+ LOG_WARN("Warning: " << fileName << " failed to load!");
+ return NULL;
+ }
+
+ // Get the size of the file
+ fileSize = PHYSFS_fileLength(file);
+
+ // Allocate memory and load the file
+ void *buffer = malloc(fileSize);
+ PHYSFS_read(file, buffer, 1, fileSize);
+
+ // Close the file and let the user deallocate the memory
+ PHYSFS_close(file);
+
+ return buffer;
+}
+
+std::vector<std::string>
+ResourceManager::loadTextFile(const std::string &fileName)
+{
+ int contentsLength;
+ char *fileContents = (char*)loadFile(fileName, contentsLength);
+ std::vector<std::string> lines;
+
+ if (!fileContents)
+ {
+ LOG_ERROR("Couldn't load text file: " << fileName);
+ return lines;
+ }
+
+ // Reallocate and include terminating 0 character
+ fileContents = (char*)realloc(fileContents, contentsLength + 1);
+ fileContents[contentsLength] = '\0';
+
+ // Tokenize and add each line separately
+ char *line = strtok(fileContents, "\n");
+ while (line != NULL)
+ {
+ lines.push_back(line);
+ line = strtok(NULL, "\n");
+ }
+
+ free(fileContents);
+ return lines;
+}
diff --git a/src/resourcemanager.h b/src/resourcemanager.h
new file mode 100644
index 0000000..a7d37f5
--- /dev/null
+++ b/src/resourcemanager.h
@@ -0,0 +1,89 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_RESOURCE_MANAGER_H
+#define _TMW_RESOURCE_MANAGER_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+/**
+ * A class for loading and managing resources.
+ */
+class ResourceManager
+{
+ public:
+ /**
+ * Constructor.
+ */
+ ResourceManager();
+
+ /**
+ * Destructor.
+ */
+ ~ResourceManager();
+
+ /**
+ * Allocates data into a buffer pointer for raw data loading. The
+ * returned data is expected to be freed using <code>free()</code>.
+ *
+ * @param fileName The name of the file to be loaded.
+ * @param fileSize The size of the file that was loaded.
+ *
+ * @return An allocated byte array containing the data that was loaded,
+ * or <code>NULL</code> on fail.
+ */
+ void*
+ loadFile(const std::string &fileName, int &fileSize);
+
+ /**
+ * Retrieves the contents of a text file.
+ */
+ std::vector<std::string>
+ loadTextFile(const std::string &fileName);
+
+ /**
+ * Returns an instance of the class, creating one if it does not
+ * already exist.
+ */
+ static ResourceManager*
+ getInstance();
+
+ /**
+ * Deletes the class instance if it exists.
+ */
+ static void
+ deleteInstance();
+
+ private:
+ /**
+ * Searches for zip files and adds them to the PhysicsFS search path.
+ */
+ void
+ searchAndAddZipFiles();
+
+ static ResourceManager *instance;
+};
+
+#endif
diff --git a/src/tests/.cvsignore b/src/tests/.cvsignore
new file mode 100644
index 0000000..3dda729
--- /dev/null
+++ b/src/tests/.cvsignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/src/utils/base64.cpp b/src/utils/base64.cpp
new file mode 100644
index 0000000..e2df07d
--- /dev/null
+++ b/src/utils/base64.cpp
@@ -0,0 +1,152 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Jim Winstead (jimw@php.net) |
+ +----------------------------------------------------------------------+
+ */
+/* $Id$ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "base64.h"
+
+static char base64_table[] =
+{
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
+};
+static char base64_pad = '=';
+
+unsigned char *php_base64_encode(const unsigned char *str, int length, int *ret_length) {
+ const unsigned char *current = str;
+ int i = 0;
+ unsigned char *result = (unsigned char *)malloc(((length + 3 - length % 3) * 4 / 3 + 1) * sizeof(char));
+
+ while (length > 2) { /* keep going until we have less than 24 bits */
+ result[i++] = base64_table[current[0] >> 2];
+ result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
+ result[i++] = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)];
+ result[i++] = base64_table[current[2] & 0x3f];
+
+ current += 3;
+ length -= 3; /* we just handle 3 octets of data */
+ }
+
+ /* now deal with the tail end of things */
+ if (length != 0) {
+ result[i++] = base64_table[current[0] >> 2];
+ if (length > 1) {
+ result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
+ result[i++] = base64_table[(current[1] & 0x0f) << 2];
+ result[i++] = base64_pad;
+ }
+ else {
+ result[i++] = base64_table[(current[0] & 0x03) << 4];
+ result[i++] = base64_pad;
+ result[i++] = base64_pad;
+ }
+ }
+ if(ret_length) {
+ *ret_length = i;
+ }
+ result[i] = '\0';
+ return result;
+}
+
+/* as above, but backwards. :) */
+unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_length) {
+ const unsigned char *current = str;
+ int ch, i = 0, j = 0, k;
+ /* this sucks for threaded environments */
+ static short reverse_table[256];
+ static int table_built;
+ unsigned char *result;
+
+ if (++table_built == 1) {
+ char *chp;
+ for(ch = 0; ch < 256; ch++) {
+ chp = strchr(base64_table, ch);
+ if(chp) {
+ reverse_table[ch] = chp - base64_table;
+ } else {
+ reverse_table[ch] = -1;
+ }
+ }
+ }
+
+ result = (unsigned char *)malloc(length + 1);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ /* run through the whole string, converting as we go */
+ while ((ch = *current++) != '\0') {
+ if (ch == base64_pad) break;
+
+ /* When Base64 gets POSTed, all pluses are interpreted as spaces.
+ This line changes them back. It's not exactly the Base64 spec,
+ but it is completely compatible with it (the spec says that
+ spaces are invalid). This will also save many people considerable
+ headache. - Turadg Aleahmad <turadg@wise.berkeley.edu>
+ */
+
+ if (ch == ' ') ch = '+';
+
+ ch = reverse_table[ch];
+ if (ch < 0) continue;
+
+ switch(i % 4) {
+ case 0:
+ result[j] = ch << 2;
+ break;
+ case 1:
+ result[j++] |= ch >> 4;
+ result[j] = (ch & 0x0f) << 4;
+ break;
+ case 2:
+ result[j++] |= ch >>2;
+ result[j] = (ch & 0x03) << 6;
+ break;
+ case 3:
+ result[j++] |= ch;
+ break;
+ }
+ i++;
+ }
+
+ k = j;
+ /* mop things up if we ended on a boundary */
+ if (ch == base64_pad) {
+ switch(i % 4) {
+ case 0:
+ case 1:
+ free(result);
+ return NULL;
+ case 2:
+ k++;
+ case 3:
+ result[k++] = 0;
+ }
+ }
+ if(ret_length) {
+ *ret_length = j;
+ }
+ result[k] = '\0';
+ return result;
+}
+
diff --git a/src/utils/base64.h b/src/utils/base64.h
new file mode 100644
index 0000000..5b275c4
--- /dev/null
+++ b/src/utils/base64.h
@@ -0,0 +1,44 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP HTML Embedded Scripting Language Version 3.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997,1998 PHP Development Team (See Credits file) |
+ +----------------------------------------------------------------------+
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of one of the following licenses: |
+ | |
+ | A) 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. |
+ | |
+ | B) the PHP License as published by the PHP Development Team and |
+ | included in the distribution in the file: LICENSE |
+ | |
+ | 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 both licenses referred to here. |
+ | If you did not, or have any questions about PHP licensing, please |
+ | contact core@php.net. |
+ +----------------------------------------------------------------------+
+ | Author: Jim Winstead (jimw@php.net) |
+ +----------------------------------------------------------------------+
+ */
+/* $Id$ */
+
+#ifndef _TMW_BASE64_H
+#define _TMW_BASE64_H
+
+extern unsigned char *php_base64_encode(const unsigned char *, int, int *);
+extern unsigned char *php_base64_decode(const unsigned char *, int, int *);
+
+#endif /* _TMW_BASE64_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */