<commit_before>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include "file_utils.h"

#ifdef OS_OSX
#include <Cocoa/Cocoa.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetController.h>
#include <sys/utsname.h>
#elif defined(OS_WIN32)
#include <windows.h>
#include <shlobj.h>
#include <Iphlpapi.h>
#include <process.h>
#elif defined(OS_LINUX)
#include <cstdarg>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if.h>
#include <sys/utsname.h>
#endif

#include <iostream>
#include <sstream>
#include <cstring>

const std::string ILLEGAL = "<>{}|\\\"^`";

static std::string safe_encode(std::string &str)
{
	std::string encodedStr;
	for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
	{
		char c = *it;
		if (isalnum(c) ||
			c == '-' || c == '_' ||
			c == '.' || c == '~' ||
			c == '/' || c == '\\' ||
			c == ' ')
		{
			encodedStr += c;
		}
		else if (c == ' ')
		{
			encodedStr += c;
		}
		else if (c <= 0x20 || c >= 0x7F || ILLEGAL.find(c) != std::string::npos)
		{
			// skip these bad out of range characters ....
		}
		else encodedStr += c;
	}
	return encodedStr;
}


namespace kroll
{
	const char HEX2DEC[256] =
	{
		/*       0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F */
		/* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 3 */  0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,

		/* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

		/* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

		/* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
	};
	// Only alphanum is safe.
	const char SAFE[256] =
	{
		/*      0 1 2 3  4 5 6 7  8 9 A B  C D E F */
		/* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,

		/* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
		/* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
		/* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
		/* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,

		/* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,

		/* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
	};

	static bool CompareVersions(std::string a, std::string b)
	{
		int a1 = FileUtils::MakeVersion(a);
		int b1 = FileUtils::MakeVersion(b);
		return b1 > a1;
	}
	std::string FileUtils::GetApplicationDirectory()
	{
#ifdef OS_OSX
		NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
		NSString* contents = [NSString stringWithFormat:@"%@/Contents",bundlePath];
		return std::string([contents UTF8String]);
#elif OS_WIN32
		char path[MAX_PATH];
		GetModuleFileName(NULL,path,MAX_PATH);
		std::string p(path);
		std::string::size_type pos = p.rfind("\\");
		if (pos!=std::string::npos)
		{
		  return p.substr(0,pos);
		}
	  	return p;
#elif OS_LINUX
		char tmp[100];
		sprintf(tmp,"/proc/%d/exe",getpid());
		char pbuf[255];
		int c = readlink(tmp,pbuf,255);
		pbuf[c]='\0';
		std::string str(pbuf);
		size_t pos = str.rfind("/");
		if (pos==std::string::npos) return str;
		return str.substr(0,pos);
#endif
	}
	std::string FileUtils::GetApplicationDataDirectory(std::string &appid)
	{
#ifdef OS_WIN32
		char path[MAX_PATH];
		int size = GetEnvironmentVariable("KR_RUNTIME_HOME",(char*)path,MAX_PATH);
		path[size]='\0';
		std::string dir = path;
#else
		std::string dir = getenv("KR_RUNTIME_HOME");
#endif
		dir+=KR_PATH_SEP;
		dir+="appdata";
		if (!IsDirectory(dir))
		{
			CreateDirectory(dir);
		}
		dir+=KR_PATH_SEP;
		dir+=appid;
		if (!IsDirectory(dir))
		{
			CreateDirectory(dir);
		}
		return dir;
	}
	std::string FileUtils::GetTempDirectory()
	{
#ifdef OS_OSX
		NSString * tempDir = NSTemporaryDirectory();
		if (tempDir == nil)
		    tempDir = @"/tmp";

		NSString *tmp = [tempDir stringByAppendingPathComponent:@"kXXXXX"];
		const char * fsTemplate = [tmp fileSystemRepresentation];
		NSMutableData * bufferData = [NSMutableData dataWithBytes: fsTemplate
		                                                   length: strlen(fsTemplate)+1];
		char * buffer = (char*)[bufferData mutableBytes];
		mkdtemp(buffer);
		NSString * temporaryDirectory = [[NSFileManager defaultManager]
		        stringWithFileSystemRepresentation: buffer
		                                    length: strlen(buffer)];
		return std::string([temporaryDirectory UTF8String]);
#elif defined(OS_WIN32)
#define BUFSIZE 512
		TCHAR szTempName[BUFSIZE];
		GetTempPath(BUFSIZE,szTempName);
		std::ostringstream s;
		srand(GetTickCount()); // initialize seed
		std::string dir(szTempName);
		s << dir;
		s << "\\k";
		s << (double)rand();
		return s.str();
#else
		std::ostringstream dir;
		const char* tmp = getenv("TMPDIR");
		const char* tmp2 = getenv("TEMP");
		if (tmp)
			dir << std::string(tmp);
		else if (tmp2)
			dir << std::string(tmp2);
		else
			dir << std::string("/tmp");

		std::string tmp_str = dir.str();
		if (tmp_str.at(tmp_str.length()-1) != '/')
			dir << "/";
		dir << "kXXXXXX";
		char* tempdir = strdup(dir.str().c_str());
		tempdir = mkdtemp(tempdir);
		tmp_str = std::string(tempdir);
		free(tempdir);
		return tmp_str;
#endif
	}
	std::string FileUtils::GetResourcesDirectory()
	{
#ifdef OS_OSX
		NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
		std::string dir = std::string([resourcePath UTF8String]);
#elif OS_WIN32
		std::string dir = FileUtils::GetApplicationDirectory();
		dir.append("\\Resources");
#elif OS_LINUX
		// TODO test this
		std::string dir = FileUtils::GetApplicationDirectory();
		dir.append("/Resources");
#endif
		return dir;
	}
	bool FileUtils::IsFile(std::string &file)
	{
#ifdef OS_OSX
		BOOL isDir = NO;
		NSString *f = [NSString stringWithCString:file.c_str()];
		NSString *p = [f stringByStandardizingPath];
		BOOL found = [[NSFileManager defaultManager] fileExistsAtPath:p isDirectory:&isDir];
		return found && !isDir;
#elif OS_WIN32
		WIN32_FIND_DATA findFileData;
		HANDLE hFind = FindFirstFile(file.c_str(), &findFileData);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			bool yesno = (findFileData.dwFileAttributes & 0x00000000) == 0x00000000;
			FindClose(hFind);
			return yesno;
		}
		return false;
#elif OS_LINUX
		struct stat st;
		return (stat(file.c_str(),&st)==0) && S_ISREG(st.st_mode);
#endif
	}
	bool FileUtils::CreateDirectory(std::string &dir)
	{
#ifdef OS_OSX
		return [[NSFileManager defaultManager] createDirectoryAtPath:[NSString stringWithCString:dir.c_str()] attributes:nil];
#elif OS_WIN32
		return ::CreateDirectory(dir.c_str(),NULL);
#elif OS_LINUX
		return mkdir(dir.c_str(),0755) == 0;
#endif
		return false;
	}
	bool FileUtils::DeleteDirectory(std::string &dir)
	{
#ifdef OS_OSX
		[[NSFileManager defaultManager] removeFileAtPath:[NSString stringWithCString:dir.c_str()] handler:nil];
#elif OS_WIN32
		SHFILEOPSTRUCT op;
		op.hwnd = NULL;
		op.wFunc = FO_DELETE;
		op.pFrom = dir.c_str();
		op.pTo = NULL;
		op.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
		int rc = SHFileOperation(&op);
		return (rc == 0);
#elif OS_LINUX
		return unlink(dir.c_str()) == 0;
#endif
		return false;
	}
	bool FileUtils::IsDirectory(std::string &dir)
	{
#ifdef OS_OSX
		BOOL isDir = NO;
		BOOL found = [[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithCString:dir.c_str()] isDirectory:&isDir];
		return found && isDir;
#elif OS_WIN32
		WIN32_FIND_DATA findFileData;
		HANDLE hFind = FindFirstFile(dir.c_str(), &findFileData);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			bool yesno = (findFileData.dwFileAttributes & 0x00000010) == 0x00000010;
			FindClose(hFind);
			return yesno;
		}
		return false;
#elif OS_LINUX
		struct stat st;
		return (stat(dir.c_str(),&st)==0) && S_ISDIR(st.st_mode);
#endif
	}

	std::string FileUtils::GetDirectory(std::string &file)
	{
		size_t pos = file.find_last_of(KR_PATH_SEP);
		if (pos == std::string::npos)
		{
			pos = file.find_last_of(KR_PATH_SEP_OTHER);
			if (pos == std::string::npos)
			{
				return "."KR_PATH_SEP; //??
			}
		}
#ifdef OS_OSX
		NSString *s = [[NSString stringWithCString:file.substr(0,pos).c_str()] stringByExpandingTildeInPath];
		return [s fileSystemRepresentation];
#else
		return file.substr(0, pos);
#endif
	}


	std::string FileUtils::Join(const char* path, ...)
	{
		va_list ap;
		va_start(ap, path);
		std::vector<std::string> parts;
		parts.push_back(std::string(path));
		while (true)
		{
			const char *i = va_arg(ap,const char*);
			if (i == NULL) break;
			parts.push_back(Trim(i));
		}
		va_end(ap);
		std::string filepath;
		std::vector<std::string>::iterator iter = parts.begin();
		while (iter!=parts.end())
		{
			std::string p = (*iter++);
			filepath+=p;
			if (filepath.length() != 0 && iter!=parts.end())
			{
				filepath+=KR_PATH_SEP;
			}
		}
#ifdef OS_OSX
		NSString *s = [[NSString stringWithCString:filepath.c_str()] stringByExpandingTildeInPath];
		NSString *p = [s stringByStandardizingPath];
		return std::string([p fileSystemRepresentation]);
#else
		return filepath;
#endif
	}

	bool FileUtils::IsHidden(std::string &file)
	{
#ifdef OS_OSX
		// TODO finish this
		return false;
#elif OS_WIN32
		WIN32_FIND_DATA findFileData;
		HANDLE hFind = FindFirstFile(file.c_str(), &findFileData);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			bool yesno = (findFileData.dwFileAttributes & 0x00000002) == 0x00000002;
			FindClose(hFind);
			return yesno;
		}
		return false;
#elif OS_LINUX
		return (file.size() > 0 && file.at(0) == '.');
#endif
	}
	bool FileUtils::IsRuntimeInstalled()
	{
		std::string dir = GetRuntimeBaseDirectory();
		return IsDirectory(dir);
	}

	std::string FileUtils::GetRuntimeBaseDirectory()
	{
#ifdef OS_WIN32
		char path[MAX_PATH];
		std::string dir;
		if (SHGetSpecialFolderPath(NULL,path,CSIDL_COMMON_APPDATA,FALSE))
		{
			dir.append(path);
			dir.append("\\");
			dir.append(PRODUCT_NAME);
		}
		else if (SHGetSpecialFolderPath(NULL,path,CSIDL_APPDATA,FALSE))
		{
			dir.append(path);
			dir.append("\\");
			dir.append(PRODUCT_NAME);
		}
		return dir;
#elif OS_OSX
		// check to see if we already have a local one
		NSString *localDir = [[NSString stringWithFormat:@"~/Library/Application Support/%s",PRODUCT_NAME] stringByExpandingTildeInPath];
		std::string ls = std::string([localDir UTF8String]);
		if (IsDirectory(ls))
		{
			return std::string([localDir UTF8String]);
		}

		// first check to see if we can install in system directory by checking
		// if we can write to it
		NSString *systemPath = @"/Library/Application Support";
		if ([[NSFileManager defaultManager] isWritableFileAtPath:systemPath])
		{
			return std::string([[systemPath stringByAppendingString:@"/"PRODUCT_NAME] UTF8String]);
		}
		// if not, we fall back to installing into user directory
		return std::string([localDir UTF8String]);
#elif OS_LINUX

		std::string uid = std::string(getenv("USER"));
		std::string p(INSTALL_PREFIX);
		p.append("/");
		p.append(PRODUCT_NAME);
		bool writable = (access(p.c_str(),W_OK)) == 0;
		if (uid.find("root")!=std::string::npos || writable)
		{
			return p;
		}
		passwd *user = getpwnam(uid.c_str());
		std::string dir = std::string(user->pw_dir) + "/" + PRODUCT_NAME + "App";
		return dir;
#endif
	}

	void FileUtils::ExtractVersion(std::string& spec, int *op, std::string &version)
	{
		if (spec.find(">=")!=std::string::npos)
		{
			*op = GreaterThanEqualTo;
			version = spec.substr(2,spec.length());
		}
		else if (spec.find("<=")!=std::string::npos)
		{
			*op = LessThanEqualTo;
			version = spec.substr(2,spec.length());
		}
		else if (spec.find("<")!=std::string::npos)
		{
			*op = LessThan;
			version = spec.substr(1,spec.length());
		}
		else if (spec.find(">")!=std::string::npos)
		{
			*op = GreaterThan;
			version = spec.substr(1,spec.length());
		}
		else if (spec.find("=")!=std::string::npos)
		{
			*op = EqualTo;
			version = spec.substr(1,spec.length());
		}
		else
		{
			*op = EqualTo;
			version = spec;
		}
	}
	int FileUtils::MakeVersion(std::string& ver)
	{
		std::string v;
		size_t pos = 0;
		while(1)
		{
			size_t newpos = ver.find(".",pos);
			if (newpos==std::string::npos)
			{
				v.append(ver.substr(pos,ver.length()));
				break;
			}
			v.append(ver.substr(pos,newpos));
			pos = newpos+1;
		}
		return atoi(v.c_str());
	}
	std::string FileUtils::FindVersioned(std::string& path, int op, std::string& version)
	{
		printf("\n1a: %s\n", path.c_str());
		std::vector<std::string> files;
		std::vector<std::string> found;
		ListDir(path,files);
		std::vector<std::string>::iterator iter = files.begin();
		int findVersion = MakeVersion(version);
		while (iter!=files.end())
		{
			std::string str = (*iter++);
			std::string fullpath = std::string(path);
			fullpath.append(KR_PATH_SEP);
			fullpath.append(str);
			printf("2: %s\n", fullpath.c_str());
			if (IsDirectory(fullpath))
			{
				int theVersion = MakeVersion(str);
				bool matched = false;

				switch(op)
				{
					case EqualTo:
					{
						matched = (theVersion == findVersion);
						break;
					}
					case GreaterThanEqualTo:
					{
						matched = (theVersion >= findVersion);
						break;
					}
					case LessThanEqualTo:
					{
						matched = (theVersion <= findVersion);
						break;
					}
					case GreaterThan:
					{
						matched = (theVersion > findVersion);
						break;
					}
					case LessThan:
					{
						matched = (theVersion < findVersion);
						break;
					}
				}
				if (matched)
				{
					found.push_back(std::string(str));
				}
			}
		}
		if (found.size() > 0)
		{
			std::sort(found.begin(),found.end(),CompareVersions);
			std::string file = found.at(0);
			std::string f = std::string(path);
			f.append(KR_PATH_SEP);
			f.append(file);
			return f;
		}
		return std::string();
	}
	std::string FileUtils::GetMachineId()
	{
		std::string path = FileUtils::Join(FileUtils::GetRuntimeBaseDirectory().c_str(),".titanium",NULL);
		if (FileUtils::IsFile(path))
		{
			std::ifstream file(path.c_str());
			if (file.bad() || file.fail())
			{
				return "-";
			}
			while (!file.eof())
			{
				std::string line;
				std::getline(file,line);
				FileUtils::Trim(line);
				return line;
			}
		}
		return "-";
	}
	std::string FileUtils::GetOSVersion()
	{
#ifdef OS_WIN32
		OSVERSIONINFO vi;
		vi.dwOSVersionInfoSize = sizeof(vi);
		if (GetVersionEx(&vi) == 0) return "?";

		std::ostringstream str;
		str << vi.dwMajorVersion << "." << vi.dwMinorVersion << " (Build " << (vi.dwBuildNumber & 0xFFFF);
		if (vi.szCSDVersion[0]) str << ": " << vi.szCSDVersion;
		str << ")";
		return str.str();
#elif OS_OSX || OS_LINUX
		struct utsname uts;
		uname(&uts);
		return uts.release;
#endif
	}
	std::string FileUtils::GetOSArchitecture()
	{
#ifdef OS_WIN32
		return std::string("win32");
#elif OS_OSX || OS_LINUX
		struct utsname uts;
		uname(&uts);
		return uts.machine;
#endif
	}
	std::string FileUtils::EncodeURIComponent(std::string src)
	{
		const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
		const unsigned char *pSrc = (const unsigned char *)src.c_str();
	   	const int SRC_LEN = src.length();
	   	unsigned char * const pStart = new unsigned char[SRC_LEN * 3];
	   	unsigned char * pEnd = pStart;
	   	const unsigned char * const SRC_END = pSrc + SRC_LEN;

	   	for (; pSrc < SRC_END; ++pSrc)
	   	{
	      if (SAFE[*pSrc])
	         *pEnd++ = *pSrc;
	      else
	      {
	         // escape this char
	         *pEnd++ = '%';
	         *pEnd++ = DEC2HEX[*pSrc >> 4];
	         *pEnd++ = DEC2HEX[*pSrc & 0x0F];
	      }
	   	}

	   	std::string sResult((char *)pStart, (char *)pEnd);
	   	delete [] pStart;

	   	return sResult;
	}
	std::string FileUtils::DecodeURIComponent(std::string src)
	{
		// Note from RFC1630: "Sequences which start with a percent
		// sign but are not followed by two hexadecimal characters
		// (0-9, A-F) are reserved for future extension"

		const unsigned char * pSrc = (const unsigned char *)src.c_str();
		const int SRC_LEN = src.length();
		const unsigned char * const SRC_END = pSrc + SRC_LEN;
		// last decodable '%'
		const unsigned char * const SRC_LAST_DEC = SRC_END - 2;

		char * const pStart = new char[SRC_LEN];
		char * pEnd = pStart;

		while (pSrc < SRC_LAST_DEC)
		{
		   if (*pSrc == '%')
		   {
		      char dec1, dec2;
		      if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])
		         && -1 != (dec2 = HEX2DEC[*(pSrc + 2)]))
		      {
		         *pEnd++ = (dec1 << 4) + dec2;
		         pSrc += 3;
		         continue;
		      }
		   }

		   *pEnd++ = *pSrc++;
		}

		// the last 2- chars
		while (pSrc < SRC_END)
		   *pEnd++ = *pSrc++;

		std::string sResult(pStart, pEnd);
		delete [] pStart;

		return sResult;
	}
	void FileUtils::Tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string &delimeters)
	{
		std::string::size_type lastPos = str.find_first_not_of(delimeters,0);
		std::string::size_type pos = str.find_first_of(delimeters,lastPos);
		while (std::string::npos!=pos || std::string::npos!=lastPos)
		{
			tokens.push_back(str.substr(lastPos,pos-lastPos));
			lastPos = str.find_first_not_of(delimeters,pos);
			pos = str.find_first_of(delimeters,lastPos);
		}
	}
	std::string FileUtils::Trim(std::string str)
	{
		std::string c(safe_encode(str));
		while (1)
		{
			size_t pos = c.rfind(" ");
			if (pos == std::string::npos || pos!=c.length()-1)
			{
				break;
			}
			c = c.substr(0,pos);
		}
		while(1)
		{
			size_t pos = c.find(" ");
			if (pos != 0)
			{
				break;
			}
			c = c.substr(1);
		}
		return c;
	}
	bool FileUtils::ReadManifest(std::string& path, std::string &runtimePath, std::vector< std::pair< std::pair<std::string,std::string>, bool> >& modules, std::vector<std::string> &moduleDirs, std::string &appname, std::string &appid, std::string &runtimeOverride, std::string &guid)
	{
		std::ifstream file(path.c_str());
		if (file.bad() || file.fail())
		{
			return false;
		}
		bool foundRuntime = false;
		const char *rt = runtimeOverride.c_str();
#ifdef DEBUG
				std::cout << "Read Manifest: " << rt << std::endl;
#endif

		while (!file.eof())
		{
			std::string line;
			std::getline(file,line);
			if (line.find(" ")==0)
			{
				continue;
			}
			size_t pos = line.find(":");
			if (pos!=std::string::npos)
			{
				std::string key = Trim(line.substr(0,pos));
				std::string value = Trim(line.substr(pos+1,line.length()));
				if (key == "#appname")
				{
					appname = value;
					continue;
				}
				else if (key == "#appid")
				{
					appid = value;
					continue;
				}
				else if (key == "#guid")
				{
					guid = value;
					continue;
				}
				else if (key.c_str()[0]=='#')
				{
					continue;
				}
				int op;
				std::string version;
				ExtractVersion(value,&op,version);
#ifdef DEBUG
				std::cout << "Component: " << key << ":" << version << ", operation: " << op << std::endl;
#endif
				std::pair<std::string,std::string> p(key,version);
				if (key == "runtime")
				{
					// check to see if our runtime is found in our override directory
					if (!runtimeOverride.empty())
					{
						std::string potentialRuntime = Join(rt,"runtime",NULL);
						if (IsDirectory(potentialRuntime))
						{
							// extra special check for Win32 since we have to place the WebKit.dll
							// inside the same relative path as .exe because of the COM embedded manifest crap-o-la
							// so if we can't find kroll.dll in the resources folder we don't override
#ifdef OS_WIN32
							std::string krolldll = kroll::FileUtils::Join(potentialRuntime.c_str(),"kroll.dll",NULL);
							if (kroll::FileUtils::IsFile(krolldll))
							{
#endif
								runtimePath = potentialRuntime;
#ifdef DEBUG
								std::cout << "found override runtime at: " << runtimePath << std::endl;
#endif
								foundRuntime = true;
								continue;
#ifdef OS_WIN32
							}
#endif
						}
					}
					runtimePath = FindRuntime(op,version);
					if (runtimePath == "")
					{
						modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,false));
					}
					else
					{
						foundRuntime = true;
					}
				}
				else
				{
					// check to see if our module is contained within our runtime override
					// directory and if it is, use it...
					std::string potentialModule = kroll::FileUtils::Join(rt,"modules",key.c_str(),NULL);

#ifdef DEBUG
					std::cout << "looking for bundled module at " << potentialModule << std::endl;
#endif
					if (IsDirectory(potentialModule))
					{
						modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,true));
						moduleDirs.push_back(potentialModule);
#ifdef DEBUG
						std::cout << "found override module at: " << potentialModule << std::endl;
#endif
						continue;
					}
					std::string dir = FindModule(key,op,version);
					bool found = dir!="";
					modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,found));
					if (found)
					{
#ifdef DEBUG
						std::cout << "found module at: " << dir << std::endl;
#endif
						moduleDirs.push_back(dir);
					}
#ifdef DEBUG
					else
					{
						std::cerr << "couldn't find module module: " << key  << "/" << version << std::endl;
					}
#endif
				}
			}
		}
		// we gotta always have a runtime
		if (!foundRuntime)
		{
			std::pair<std::string,std::string> p("runtime","0.2"); //TODO: huh, what do we use?
			modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,false));
		}
		file.close();
		return true;
	}
	std::string FileUtils::FindRuntime(int op, std::string& version)
	{
		std::string runtime = GetRuntimeBaseDirectory();
		std::string path(runtime);
#ifdef OS_WIN32
		path += "\\runtime\\win32";
#elif OS_LINUX<commit_msg>fixed problem with net installer trying to fetch runtime twice and with wrong version 2nd time<commit_after>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include "file_utils.h"

#ifdef OS_OSX
#include <Cocoa/Cocoa.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetController.h>
#include <sys/utsname.h>
#elif defined(OS_WIN32)
#include <windows.h>
#include <shlobj.h>
#include <Iphlpapi.h>
#include <process.h>
#elif defined(OS_LINUX)
#include <cstdarg>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if.h>
#include <sys/utsname.h>
#endif

#include <iostream>
#include <sstream>
#include <cstring>

const std::string ILLEGAL = "<>{}|\\\"^`";

static std::string safe_encode(std::string &str)
{
	std::string encodedStr;
	for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
	{
		char c = *it;
		if (isalnum(c) ||
			c == '-' || c == '_' ||
			c == '.' || c == '~' ||
			c == '/' || c == '\\' ||
			c == ' ')
		{
			encodedStr += c;
		}
		else if (c == ' ')
		{
			encodedStr += c;
		}
		else if (c <= 0x20 || c >= 0x7F || ILLEGAL.find(c) != std::string::npos)
		{
			// skip these bad out of range characters ....
		}
		else encodedStr += c;
	}
	return encodedStr;
}


namespace kroll
{
	const char HEX2DEC[256] =
	{
		/*       0  1  2  3   4  5  6  7   8  9  A  B   C  D  E  F */
		/* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 3 */  0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,

		/* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

		/* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,

		/* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
		/* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
	};
	// Only alphanum is safe.
	const char SAFE[256] =
	{
		/*      0 1 2 3  4 5 6 7  8 9 A B  C D E F */
		/* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,

		/* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
		/* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
		/* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
		/* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,

		/* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,

		/* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
		/* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
	};

	static bool CompareVersions(std::string a, std::string b)
	{
		int a1 = FileUtils::MakeVersion(a);
		int b1 = FileUtils::MakeVersion(b);
		return b1 > a1;
	}
	std::string FileUtils::GetApplicationDirectory()
	{
#ifdef OS_OSX
		NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
		NSString* contents = [NSString stringWithFormat:@"%@/Contents",bundlePath];
		return std::string([contents UTF8String]);
#elif OS_WIN32
		char path[MAX_PATH];
		GetModuleFileName(NULL,path,MAX_PATH);
		std::string p(path);
		std::string::size_type pos = p.rfind("\\");
		if (pos!=std::string::npos)
		{
		  return p.substr(0,pos);
		}
	  	return p;
#elif OS_LINUX
		char tmp[100];
		sprintf(tmp,"/proc/%d/exe",getpid());
		char pbuf[255];
		int c = readlink(tmp,pbuf,255);
		pbuf[c]='\0';
		std::string str(pbuf);
		size_t pos = str.rfind("/");
		if (pos==std::string::npos) return str;
		return str.substr(0,pos);
#endif
	}
	std::string FileUtils::GetApplicationDataDirectory(std::string &appid)
	{
#ifdef OS_WIN32
		char path[MAX_PATH];
		int size = GetEnvironmentVariable("KR_RUNTIME_HOME",(char*)path,MAX_PATH);
		path[size]='\0';
		std::string dir = path;
#else
		std::string dir = getenv("KR_RUNTIME_HOME");
#endif
		dir+=KR_PATH_SEP;
		dir+="appdata";
		if (!IsDirectory(dir))
		{
			CreateDirectory(dir);
		}
		dir+=KR_PATH_SEP;
		dir+=appid;
		if (!IsDirectory(dir))
		{
			CreateDirectory(dir);
		}
		return dir;
	}
	std::string FileUtils::GetTempDirectory()
	{
#ifdef OS_OSX
		NSString * tempDir = NSTemporaryDirectory();
		if (tempDir == nil)
		    tempDir = @"/tmp";

		NSString *tmp = [tempDir stringByAppendingPathComponent:@"kXXXXX"];
		const char * fsTemplate = [tmp fileSystemRepresentation];
		NSMutableData * bufferData = [NSMutableData dataWithBytes: fsTemplate
		                                                   length: strlen(fsTemplate)+1];
		char * buffer = (char*)[bufferData mutableBytes];
		mkdtemp(buffer);
		NSString * temporaryDirectory = [[NSFileManager defaultManager]
		        stringWithFileSystemRepresentation: buffer
		                                    length: strlen(buffer)];
		return std::string([temporaryDirectory UTF8String]);
#elif defined(OS_WIN32)
#define BUFSIZE 512
		TCHAR szTempName[BUFSIZE];
		GetTempPath(BUFSIZE,szTempName);
		std::ostringstream s;
		srand(GetTickCount()); // initialize seed
		std::string dir(szTempName);
		s << dir;
		s << "\\k";
		s << (double)rand();
		return s.str();
#else
		std::ostringstream dir;
		const char* tmp = getenv("TMPDIR");
		const char* tmp2 = getenv("TEMP");
		if (tmp)
			dir << std::string(tmp);
		else if (tmp2)
			dir << std::string(tmp2);
		else
			dir << std::string("/tmp");

		std::string tmp_str = dir.str();
		if (tmp_str.at(tmp_str.length()-1) != '/')
			dir << "/";
		dir << "kXXXXXX";
		char* tempdir = strdup(dir.str().c_str());
		tempdir = mkdtemp(tempdir);
		tmp_str = std::string(tempdir);
		free(tempdir);
		return tmp_str;
#endif
	}
	std::string FileUtils::GetResourcesDirectory()
	{
#ifdef OS_OSX
		NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
		std::string dir = std::string([resourcePath UTF8String]);
#elif OS_WIN32
		std::string dir = FileUtils::GetApplicationDirectory();
		dir.append("\\Resources");
#elif OS_LINUX
		// TODO test this
		std::string dir = FileUtils::GetApplicationDirectory();
		dir.append("/Resources");
#endif
		return dir;
	}
	bool FileUtils::IsFile(std::string &file)
	{
#ifdef OS_OSX
		BOOL isDir = NO;
		NSString *f = [NSString stringWithCString:file.c_str()];
		NSString *p = [f stringByStandardizingPath];
		BOOL found = [[NSFileManager defaultManager] fileExistsAtPath:p isDirectory:&isDir];
		return found && !isDir;
#elif OS_WIN32
		WIN32_FIND_DATA findFileData;
		HANDLE hFind = FindFirstFile(file.c_str(), &findFileData);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			bool yesno = (findFileData.dwFileAttributes & 0x00000000) == 0x00000000;
			FindClose(hFind);
			return yesno;
		}
		return false;
#elif OS_LINUX
		struct stat st;
		return (stat(file.c_str(),&st)==0) && S_ISREG(st.st_mode);
#endif
	}
	bool FileUtils::CreateDirectory(std::string &dir)
	{
#ifdef OS_OSX
		return [[NSFileManager defaultManager] createDirectoryAtPath:[NSString stringWithCString:dir.c_str()] attributes:nil];
#elif OS_WIN32
		return ::CreateDirectory(dir.c_str(),NULL);
#elif OS_LINUX
		return mkdir(dir.c_str(),0755) == 0;
#endif
		return false;
	}
	bool FileUtils::DeleteDirectory(std::string &dir)
	{
#ifdef OS_OSX
		[[NSFileManager defaultManager] removeFileAtPath:[NSString stringWithCString:dir.c_str()] handler:nil];
#elif OS_WIN32
		SHFILEOPSTRUCT op;
		op.hwnd = NULL;
		op.wFunc = FO_DELETE;
		op.pFrom = dir.c_str();
		op.pTo = NULL;
		op.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
		int rc = SHFileOperation(&op);
		return (rc == 0);
#elif OS_LINUX
		return unlink(dir.c_str()) == 0;
#endif
		return false;
	}
	bool FileUtils::IsDirectory(std::string &dir)
	{
#ifdef OS_OSX
		BOOL isDir = NO;
		BOOL found = [[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithCString:dir.c_str()] isDirectory:&isDir];
		return found && isDir;
#elif OS_WIN32
		WIN32_FIND_DATA findFileData;
		HANDLE hFind = FindFirstFile(dir.c_str(), &findFileData);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			bool yesno = (findFileData.dwFileAttributes & 0x00000010) == 0x00000010;
			FindClose(hFind);
			return yesno;
		}
		return false;
#elif OS_LINUX
		struct stat st;
		return (stat(dir.c_str(),&st)==0) && S_ISDIR(st.st_mode);
#endif
	}

	std::string FileUtils::GetDirectory(std::string &file)
	{
		size_t pos = file.find_last_of(KR_PATH_SEP);
		if (pos == std::string::npos)
		{
			pos = file.find_last_of(KR_PATH_SEP_OTHER);
			if (pos == std::string::npos)
			{
				return "."KR_PATH_SEP; //??
			}
		}
#ifdef OS_OSX
		NSString *s = [[NSString stringWithCString:file.substr(0,pos).c_str()] stringByExpandingTildeInPath];
		return [s fileSystemRepresentation];
#else
		return file.substr(0, pos);
#endif
	}


	std::string FileUtils::Join(const char* path, ...)
	{
		va_list ap;
		va_start(ap, path);
		std::vector<std::string> parts;
		parts.push_back(std::string(path));
		while (true)
		{
			const char *i = va_arg(ap,const char*);
			if (i == NULL) break;
			parts.push_back(Trim(i));
		}
		va_end(ap);
		std::string filepath;
		std::vector<std::string>::iterator iter = parts.begin();
		while (iter!=parts.end())
		{
			std::string p = (*iter++);
			filepath+=p;
			if (filepath.length() != 0 && iter!=parts.end())
			{
				filepath+=KR_PATH_SEP;
			}
		}
#ifdef OS_OSX
		NSString *s = [[NSString stringWithCString:filepath.c_str()] stringByExpandingTildeInPath];
		NSString *p = [s stringByStandardizingPath];
		return std::string([p fileSystemRepresentation]);
#else
		return filepath;
#endif
	}

	bool FileUtils::IsHidden(std::string &file)
	{
#ifdef OS_OSX
		// TODO finish this
		return false;
#elif OS_WIN32
		WIN32_FIND_DATA findFileData;
		HANDLE hFind = FindFirstFile(file.c_str(), &findFileData);
		if (hFind != INVALID_HANDLE_VALUE)
		{
			bool yesno = (findFileData.dwFileAttributes & 0x00000002) == 0x00000002;
			FindClose(hFind);
			return yesno;
		}
		return false;
#elif OS_LINUX
		return (file.size() > 0 && file.at(0) == '.');
#endif
	}
	bool FileUtils::IsRuntimeInstalled()
	{
		std::string dir = GetRuntimeBaseDirectory();
		return IsDirectory(dir);
	}

	std::string FileUtils::GetRuntimeBaseDirectory()
	{
#ifdef OS_WIN32
		char path[MAX_PATH];
		std::string dir;
		if (SHGetSpecialFolderPath(NULL,path,CSIDL_COMMON_APPDATA,FALSE))
		{
			dir.append(path);
			dir.append("\\");
			dir.append(PRODUCT_NAME);
		}
		else if (SHGetSpecialFolderPath(NULL,path,CSIDL_APPDATA,FALSE))
		{
			dir.append(path);
			dir.append("\\");
			dir.append(PRODUCT_NAME);
		}
		return dir;
#elif OS_OSX
		// check to see if we already have a local one
		NSString *localDir = [[NSString stringWithFormat:@"~/Library/Application Support/%s",PRODUCT_NAME] stringByExpandingTildeInPath];
		std::string ls = std::string([localDir UTF8String]);
		if (IsDirectory(ls))
		{
			return std::string([localDir UTF8String]);
		}

		// first check to see if we can install in system directory by checking
		// if we can write to it
		NSString *systemPath = @"/Library/Application Support";
		if ([[NSFileManager defaultManager] isWritableFileAtPath:systemPath])
		{
			return std::string([[systemPath stringByAppendingString:@"/"PRODUCT_NAME] UTF8String]);
		}
		// if not, we fall back to installing into user directory
		return std::string([localDir UTF8String]);
#elif OS_LINUX

		std::string uid = std::string(getenv("USER"));
		std::string p(INSTALL_PREFIX);
		p.append("/");
		p.append(PRODUCT_NAME);
		bool writable = (access(p.c_str(),W_OK)) == 0;
		if (uid.find("root")!=std::string::npos || writable)
		{
			return p;
		}
		passwd *user = getpwnam(uid.c_str());
		std::string dir = std::string(user->pw_dir) + "/" + PRODUCT_NAME + "App";
		return dir;
#endif
	}

	void FileUtils::ExtractVersion(std::string& spec, int *op, std::string &version)
	{
		if (spec.find(">=")!=std::string::npos)
		{
			*op = GreaterThanEqualTo;
			version = spec.substr(2,spec.length());
		}
		else if (spec.find("<=")!=std::string::npos)
		{
			*op = LessThanEqualTo;
			version = spec.substr(2,spec.length());
		}
		else if (spec.find("<")!=std::string::npos)
		{
			*op = LessThan;
			version = spec.substr(1,spec.length());
		}
		else if (spec.find(">")!=std::string::npos)
		{
			*op = GreaterThan;
			version = spec.substr(1,spec.length());
		}
		else if (spec.find("=")!=std::string::npos)
		{
			*op = EqualTo;
			version = spec.substr(1,spec.length());
		}
		else
		{
			*op = EqualTo;
			version = spec;
		}
	}
	int FileUtils::MakeVersion(std::string& ver)
	{
		std::string v;
		size_t pos = 0;
		while(1)
		{
			size_t newpos = ver.find(".",pos);
			if (newpos==std::string::npos)
			{
				v.append(ver.substr(pos,ver.length()));
				break;
			}
			v.append(ver.substr(pos,newpos));
			pos = newpos+1;
		}
		return atoi(v.c_str());
	}
	std::string FileUtils::FindVersioned(std::string& path, int op, std::string& version)
	{
		printf("\n1a: %s\n", path.c_str());
		std::vector<std::string> files;
		std::vector<std::string> found;
		ListDir(path,files);
		std::vector<std::string>::iterator iter = files.begin();
		int findVersion = MakeVersion(version);
		while (iter!=files.end())
		{
			std::string str = (*iter++);
			std::string fullpath = std::string(path);
			fullpath.append(KR_PATH_SEP);
			fullpath.append(str);
			printf("2: %s\n", fullpath.c_str());
			if (IsDirectory(fullpath))
			{
				int theVersion = MakeVersion(str);
				bool matched = false;

				switch(op)
				{
					case EqualTo:
					{
						matched = (theVersion == findVersion);
						break;
					}
					case GreaterThanEqualTo:
					{
						matched = (theVersion >= findVersion);
						break;
					}
					case LessThanEqualTo:
					{
						matched = (theVersion <= findVersion);
						break;
					}
					case GreaterThan:
					{
						matched = (theVersion > findVersion);
						break;
					}
					case LessThan:
					{
						matched = (theVersion < findVersion);
						break;
					}
				}
				if (matched)
				{
					found.push_back(std::string(str));
				}
			}
		}
		if (found.size() > 0)
		{
			std::sort(found.begin(),found.end(),CompareVersions);
			std::string file = found.at(0);
			std::string f = std::string(path);
			f.append(KR_PATH_SEP);
			f.append(file);
			return f;
		}
		return std::string();
	}
	std::string FileUtils::GetMachineId()
	{
		std::string path = FileUtils::Join(FileUtils::GetRuntimeBaseDirectory().c_str(),".titanium",NULL);
		if (FileUtils::IsFile(path))
		{
			std::ifstream file(path.c_str());
			if (file.bad() || file.fail())
			{
				return "-";
			}
			while (!file.eof())
			{
				std::string line;
				std::getline(file,line);
				FileUtils::Trim(line);
				return line;
			}
		}
		return "-";
	}
	std::string FileUtils::GetOSVersion()
	{
#ifdef OS_WIN32
		OSVERSIONINFO vi;
		vi.dwOSVersionInfoSize = sizeof(vi);
		if (GetVersionEx(&vi) == 0) return "?";

		std::ostringstream str;
		str << vi.dwMajorVersion << "." << vi.dwMinorVersion << " (Build " << (vi.dwBuildNumber & 0xFFFF);
		if (vi.szCSDVersion[0]) str << ": " << vi.szCSDVersion;
		str << ")";
		return str.str();
#elif OS_OSX || OS_LINUX
		struct utsname uts;
		uname(&uts);
		return uts.release;
#endif
	}
	std::string FileUtils::GetOSArchitecture()
	{
#ifdef OS_WIN32
		return std::string("win32");
#elif OS_OSX || OS_LINUX
		struct utsname uts;
		uname(&uts);
		return uts.machine;
#endif
	}
	std::string FileUtils::EncodeURIComponent(std::string src)
	{
		const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
		const unsigned char *pSrc = (const unsigned char *)src.c_str();
	   	const int SRC_LEN = src.length();
	   	unsigned char * const pStart = new unsigned char[SRC_LEN * 3];
	   	unsigned char * pEnd = pStart;
	   	const unsigned char * const SRC_END = pSrc + SRC_LEN;

	   	for (; pSrc < SRC_END; ++pSrc)
	   	{
	      if (SAFE[*pSrc])
	         *pEnd++ = *pSrc;
	      else
	      {
	         // escape this char
	         *pEnd++ = '%';
	         *pEnd++ = DEC2HEX[*pSrc >> 4];
	         *pEnd++ = DEC2HEX[*pSrc & 0x0F];
	      }
	   	}

	   	std::string sResult((char *)pStart, (char *)pEnd);
	   	delete [] pStart;

	   	return sResult;
	}
	std::string FileUtils::DecodeURIComponent(std::string src)
	{
		// Note from RFC1630: "Sequences which start with a percent
		// sign but are not followed by two hexadecimal characters
		// (0-9, A-F) are reserved for future extension"

		const unsigned char * pSrc = (const unsigned char *)src.c_str();
		const int SRC_LEN = src.length();
		const unsigned char * const SRC_END = pSrc + SRC_LEN;
		// last decodable '%'
		const unsigned char * const SRC_LAST_DEC = SRC_END - 2;

		char * const pStart = new char[SRC_LEN];
		char * pEnd = pStart;

		while (pSrc < SRC_LAST_DEC)
		{
		   if (*pSrc == '%')
		   {
		      char dec1, dec2;
		      if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])
		         && -1 != (dec2 = HEX2DEC[*(pSrc + 2)]))
		      {
		         *pEnd++ = (dec1 << 4) + dec2;
		         pSrc += 3;
		         continue;
		      }
		   }

		   *pEnd++ = *pSrc++;
		}

		// the last 2- chars
		while (pSrc < SRC_END)
		   *pEnd++ = *pSrc++;

		std::string sResult(pStart, pEnd);
		delete [] pStart;

		return sResult;
	}
	void FileUtils::Tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string &delimeters)
	{
		std::string::size_type lastPos = str.find_first_not_of(delimeters,0);
		std::string::size_type pos = str.find_first_of(delimeters,lastPos);
		while (std::string::npos!=pos || std::string::npos!=lastPos)
		{
			tokens.push_back(str.substr(lastPos,pos-lastPos));
			lastPos = str.find_first_not_of(delimeters,pos);
			pos = str.find_first_of(delimeters,lastPos);
		}
	}
	std::string FileUtils::Trim(std::string str)
	{
		std::string c(safe_encode(str));
		while (1)
		{
			size_t pos = c.rfind(" ");
			if (pos == std::string::npos || pos!=c.length()-1)
			{
				break;
			}
			c = c.substr(0,pos);
		}
		while(1)
		{
			size_t pos = c.find(" ");
			if (pos != 0)
			{
				break;
			}
			c = c.substr(1);
		}
		return c;
	}
	bool FileUtils::ReadManifest(std::string& path, std::string &runtimePath, std::vector< std::pair< std::pair<std::string,std::string>, bool> >& modules, std::vector<std::string> &moduleDirs, std::string &appname, std::string &appid, std::string &runtimeOverride, std::string &guid)
	{
		std::ifstream file(path.c_str());
		if (file.bad() || file.fail())
		{
			return false;
		}
		bool foundRuntime = false;
		const char *rt = runtimeOverride.c_str();
#ifdef DEBUG
				std::cout << "Read Manifest: " << rt << std::endl;
#endif

		while (!file.eof())
		{
			std::string line;
			std::getline(file,line);
			if (line.find(" ")==0)
			{
				continue;
			}
			size_t pos = line.find(":");
			if (pos!=std::string::npos)
			{
				std::string key = Trim(line.substr(0,pos));
				std::string value = Trim(line.substr(pos+1,line.length()));
				if (key == "#appname")
				{
					appname = value;
					continue;
				}
				else if (key == "#appid")
				{
					appid = value;
					continue;
				}
				else if (key == "#guid")
				{
					guid = value;
					continue;
				}
				else if (key.c_str()[0]=='#')
				{
					continue;
				}
				int op;
				std::string version;
				ExtractVersion(value,&op,version);
#ifdef DEBUG
				std::cout << "Component: " << key << ":" << version << ", operation: " << op << std::endl;
#endif
				std::pair<std::string,std::string> p(key,version);
				if (key == "runtime")
				{
					// check to see if our runtime is found in our override directory
					if (!runtimeOverride.empty())
					{
						std::string potentialRuntime = Join(rt,"runtime",NULL);
						if (IsDirectory(potentialRuntime))
						{
							// extra special check for Win32 since we have to place the WebKit.dll
							// inside the same relative path as .exe because of the COM embedded manifest crap-o-la
							// so if we can't find kroll.dll in the resources folder we don't override
#ifdef OS_WIN32
							std::string krolldll = kroll::FileUtils::Join(potentialRuntime.c_str(),"kroll.dll",NULL);
							if (kroll::FileUtils::IsFile(krolldll))
							{
#endif
								runtimePath = potentialRuntime;
#ifdef DEBUG
								std::cout << "found override runtime at: " << runtimePath << std::endl;
#endif
								foundRuntime = true;
								continue;
#ifdef OS_WIN32
							}
#endif
						}
					}
					runtimePath = FindRuntime(op,version);
					modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,false));
					foundRuntime = true; // so we don't add again
				}
				else
				{
					// check to see if our module is contained within our runtime override
					// directory and if it is, use it...
					std::string potentialModule = kroll::FileUtils::Join(rt,"modules",key.c_str(),NULL);

#ifdef DEBUG
					std::cout << "looking for bundled module at " << potentialModule << std::endl;
#endif
					if (IsDirectory(potentialModule))
					{
						modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,true));
						moduleDirs.push_back(potentialModule);
#ifdef DEBUG
						std::cout << "found override module at: " << potentialModule << std::endl;
#endif
						continue;
					}
					std::string dir = FindModule(key,op,version);
					bool found = dir!="";
					modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,found));
					if (found)
					{
#ifdef DEBUG
						std::cout << "found module at: " << dir << std::endl;
#endif
						moduleDirs.push_back(dir);
					}
#ifdef DEBUG
					else
					{
						std::cerr << "couldn't find module module: " << key  << "/" << version << std::endl;
					}
#endif
				}
			}
		}
		// we gotta always have a runtime
		if (!foundRuntime)
		{
			std::pair<std::string,std::string> p("runtime",STRING(PRODUCT_VERSION)); //TODO: huh, what do we use?
			modules.push_back(std::pair< std::pair<std::string,std::string>, bool>(p,false));
		}
		file.close();
		return true;
	}
	std::string FileUtils::FindRuntime(int op, std::string& version)
	{
		std::string runtime = GetRuntimeBaseDirectory();
		std::string path(runtime);
#ifdef OS_WIN32
		path += "\\runtime\\win32";
#elif OS_LINUX
{'fraction_non_alphanumeric': 0.18900449695794022, 'fraction_numerical': 0.035071863151397584, 'mean_word_length': 3.3636975759907655, 'pattern_counts': {'":': 6, '<': 279, '<?xml version=': 0, '>': 109, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 8, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2835560', 'n_tokens_mistral': 20525, 'n_tokens_neox': 17581, 'n_words': 3596}