diff options
Diffstat (limited to 'src/Sockets/Utility.cpp')
-rw-r--r-- | src/Sockets/Utility.cpp | 954 |
1 files changed, 0 insertions, 954 deletions
diff --git a/src/Sockets/Utility.cpp b/src/Sockets/Utility.cpp deleted file mode 100644 index a914b39..0000000 --- a/src/Sockets/Utility.cpp +++ /dev/null @@ -1,954 +0,0 @@ -/** \file Utility.cpp - ** \date 2004-02-13 - ** \author grymse@alhem.net -**/ -/* -Copyright (C) 2004-2007 Anders Hedstrom - -This library is made available under the terms of the GNU GPL. - -If you would like to use this library in a closed-source application, -a separate license agreement is available. For information about -the closed-source license agreement for the C++ sockets library, -please visit http://www.alhem.net/Sockets/license.html and/or -email license@alhem.net. - -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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ -#include "Utility.h" -#include "Parse.h" -#include "Ipv4Address.h" -#include "Ipv6Address.h" -#include "RandomNumber.h" -#include "Base64.h" -#include <vector> -#ifdef _WIN32 -#include <time.h> -#else -#include <netdb.h> -#include <pthread.h> -#endif -#include <map> -#include <cstring> - -#ifdef SOCKETS_NAMESPACE -namespace SOCKETS_NAMESPACE { -#endif - - -// statics -std::string Utility::m_host; -bool Utility::m_local_resolved = false; -ipaddr_t Utility::m_ip = 0; -std::string Utility::m_addr; -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 -struct in6_addr Utility::m_local_ip6; -std::string Utility::m_local_addr6; -#endif -#endif - - -std::string Utility::base64(const std::string& str_in) -{ - std::string str; - Base64 m_b; - m_b.encode(str_in, str, false); // , false == do not add cr/lf - return str; -} - - -std::string Utility::base64d(const std::string& str_in) -{ - std::string str; - Base64 m_b; - m_b.decode(str_in, str); - return str; -} - - -std::string Utility::l2string(long l) -{ - std::string str; - char tmp[100]; - sprintf(tmp,"%ld",l); - str = tmp; - return str; -} - - -std::string Utility::bigint2string(uint64_t l) -{ - std::string str; - uint64_t tmp = l; - while (tmp) - { - uint64_t a = tmp % 10; - str = (char)(a + 48) + str; - tmp /= 10; - } - if (!str.size()) - { - str = "0"; - } - return str; -} - - -uint64_t Utility::atoi64(const std::string& str) -{ - uint64_t l = 0; - for (size_t i = 0; i < str.size(); i++) - { - l = l * 10 + str[i] - 48; - } - return l; -} - - -unsigned int Utility::hex2unsigned(const std::string& str) -{ - unsigned int r = 0; - for (size_t i = 0; i < str.size(); i++) - { - r = r * 16 + str[i] - 48 - ((str[i] >= 'A') ? 7 : 0) - ((str[i] >= 'a') ? 32 : 0); - } - return r; -} - - -/* -* Encode string per RFC1738 URL encoding rules -* tnx rstaveley -*/ -std::string Utility::rfc1738_encode(const std::string& src) -{ -static char hex[] = "0123456789ABCDEF"; - std::string dst; - for (size_t i = 0; i < src.size(); i++) - { - if (isalnum(src[i])) - { - dst += src[i]; - } - else - if (src[i] == ' ') - { - dst += '+'; - } - else - { - unsigned char c = static_cast<unsigned char>(src[i]); - dst += '%'; - dst += hex[c / 16]; - dst += hex[c % 16]; - } - } - return dst; -} // rfc1738_encode - - -/* -* Decode string per RFC1738 URL encoding rules -* tnx rstaveley -*/ -std::string Utility::rfc1738_decode(const std::string& src) -{ - std::string dst; - for (size_t i = 0; i < src.size(); i++) - { - if (src[i] == '%' && isxdigit(src[i + 1]) && isxdigit(src[i + 2])) - { - char c1 = src[++i]; - char c2 = src[++i]; - c1 = c1 - 48 - ((c1 >= 'A') ? 7 : 0) - ((c1 >= 'a') ? 32 : 0); - c2 = c2 - 48 - ((c2 >= 'A') ? 7 : 0) - ((c2 >= 'a') ? 32 : 0); - dst += (char)(c1 * 16 + c2); - } - else - if (src[i] == '+') - { - dst += ' '; - } - else - { - dst += src[i]; - } - } - return dst; -} // rfc1738_decode - - -bool Utility::isipv4(const std::string& str) -{ - int dots = 0; - // %! ignore :port? - for (size_t i = 0; i < str.size(); i++) - { - if (str[i] == '.') - dots++; - else - if (!isdigit(str[i])) - return false; - } - if (dots != 3) - return false; - return true; -} - - -bool Utility::isipv6(const std::string& str) -{ - size_t qc = 0; - size_t qd = 0; - for (size_t i = 0; i < str.size(); i++) - { - qc += (str[i] == ':') ? 1 : 0; - qd += (str[i] == '.') ? 1 : 0; - } - if (qc > 7) - { - return false; - } - if (qd && qd != 3) - { - return false; - } - Parse pa(str,":."); - std::string tmp = pa.getword(); - while (tmp.size()) - { - if (tmp.size() > 4) - { - return false; - } - for (size_t i = 0; i < tmp.size(); i++) - { - if (tmp[i] < '0' || (tmp[i] > '9' && tmp[i] < 'A') || - (tmp[i] > 'F' && tmp[i] < 'a') || tmp[i] > 'f') - { - return false; - } - } - // - tmp = pa.getword(); - } - return true; -} - - -bool Utility::u2ip(const std::string& str, ipaddr_t& l) -{ - struct sockaddr_in sa; - bool r = Utility::u2ip(str, sa); - memcpy(&l, &sa.sin_addr, sizeof(l)); - return r; -} - - -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 -bool Utility::u2ip(const std::string& str, struct in6_addr& l) -{ - struct sockaddr_in6 sa; - bool r = Utility::u2ip(str, sa); - l = sa.sin6_addr; - return r; -} -#endif -#endif - - -void Utility::l2ip(const ipaddr_t ip, std::string& str) -{ - struct sockaddr_in sa; - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - memcpy(&sa.sin_addr, &ip, sizeof(sa.sin_addr)); - Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), str, NI_NUMERICHOST); -} - - -void Utility::l2ip(const in_addr& ip, std::string& str) -{ - struct sockaddr_in sa; - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_addr = ip; - Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), str, NI_NUMERICHOST); -} - - -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 -void Utility::l2ip(const struct in6_addr& ip, std::string& str,bool mixed) -{ - char slask[100]; // l2ip temporary - *slask = 0; - unsigned int prev = 0; - bool skipped = false; - bool ok_to_skip = true; - if (mixed) - { - unsigned short x; - unsigned short addr16[8]; - memcpy(addr16, &ip, sizeof(addr16)); - for (size_t i = 0; i < 6; i++) - { - x = ntohs(addr16[i]); - if (*slask && (x || !ok_to_skip || prev)) - strcat(slask,":"); - if (x || !ok_to_skip) - { - sprintf(slask + strlen(slask),"%x", x); - if (x && skipped) - ok_to_skip = false; - } - else - { - skipped = true; - } - prev = x; - } - x = ntohs(addr16[6]); - sprintf(slask + strlen(slask),":%u.%u",x / 256,x & 255); - x = ntohs(addr16[7]); - sprintf(slask + strlen(slask),".%u.%u",x / 256,x & 255); - } - else - { - struct sockaddr_in6 sa; - memset(&sa, 0, sizeof(sa)); - sa.sin6_family = AF_INET6; - sa.sin6_addr = ip; - Utility::reverse( (struct sockaddr *)&sa, sizeof(sa), str, NI_NUMERICHOST); - return; - } - str = slask; -} - - -int Utility::in6_addr_compare(in6_addr a,in6_addr b) -{ - for (size_t i = 0; i < 16; i++) - { - if (a.s6_addr[i] < b.s6_addr[i]) - return -1; - if (a.s6_addr[i] > b.s6_addr[i]) - return 1; - } - return 0; -} -#endif -#endif - - -void Utility::ResolveLocal() -{ - char h[256]; - - // get local hostname and translate into ip-address - *h = 0; - gethostname(h,255); - { - if (Utility::u2ip(h, m_ip)) - { - Utility::l2ip(m_ip, m_addr); - } - } -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 - memset(&m_local_ip6, 0, sizeof(m_local_ip6)); - { - if (Utility::u2ip(h, m_local_ip6)) - { - Utility::l2ip(m_local_ip6, m_local_addr6); - } - } -#endif -#endif - m_host = h; - m_local_resolved = true; -} - - -const std::string& Utility::GetLocalHostname() -{ - if (!m_local_resolved) - { - ResolveLocal(); - } - return m_host; -} - - -ipaddr_t Utility::GetLocalIP() -{ - if (!m_local_resolved) - { - ResolveLocal(); - } - return m_ip; -} - - -const std::string& Utility::GetLocalAddress() -{ - if (!m_local_resolved) - { - ResolveLocal(); - } - return m_addr; -} - - -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 -const struct in6_addr& Utility::GetLocalIP6() -{ - if (!m_local_resolved) - { - ResolveLocal(); - } - return m_local_ip6; -} - - -const std::string& Utility::GetLocalAddress6() -{ - if (!m_local_resolved) - { - ResolveLocal(); - } - return m_local_addr6; -} -#endif -#endif - - -void Utility::SetEnv(const std::string& var,const std::string& value) -{ -#if (defined(SOLARIS8) || defined(SOLARIS)) - { - static std::map<std::string, char *> vmap; - if (vmap.find(var) != vmap.end()) - { - delete[] vmap[var]; - } - vmap[var] = new char[var.size() + 1 + value.size() + 1]; - sprintf(vmap[var], "%s=%s", var.c_str(), value.c_str()); - putenv( vmap[var] ); - } -#elif defined _WIN32 - { - std::string slask = var + "=" + value; - _putenv( (char *)slask.c_str()); - } -#else - setenv(var.c_str(), value.c_str(), 1); -#endif -} - - -std::string Utility::Sa2String(struct sockaddr *sa) -{ -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 - if (sa -> sa_family == AF_INET6) - { - struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; - std::string tmp; - Utility::l2ip(sa6 -> sin6_addr, tmp); - return tmp + ":" + Utility::l2string(ntohs(sa6 -> sin6_port)); - } -#endif -#endif - if (sa -> sa_family == AF_INET) - { - struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; - ipaddr_t a; - memcpy(&a, &sa4 -> sin_addr, 4); - std::string tmp; - Utility::l2ip(a, tmp); - return tmp + ":" + Utility::l2string(ntohs(sa4 -> sin_port)); - } - return ""; -} - - -void Utility::GetTime(struct timeval *p) -{ -#ifdef _WIN32 - FILETIME ft; // Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). - GetSystemTimeAsFileTime(&ft); - uint64_t tt; - memcpy(&tt, &ft, sizeof(tt)); - tt /= 10; // make it usecs - p->tv_sec = (long)tt / 1000000; - p->tv_usec = (long)tt % 1000000; -#else - gettimeofday(p, NULL); -#endif -} - - -std::auto_ptr<SocketAddress> Utility::CreateAddress(struct sockaddr *sa,socklen_t sa_len) -{ - switch (sa -> sa_family) - { - case AF_INET: - if (sa_len == sizeof(struct sockaddr_in)) - { - struct sockaddr_in *p = (struct sockaddr_in *)sa; - return std::auto_ptr<SocketAddress>(new Ipv4Address(*p)); - } - break; -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 - case AF_INET6: - if (sa_len == sizeof(struct sockaddr_in6)) - { - struct sockaddr_in6 *p = (struct sockaddr_in6 *)sa; - return std::auto_ptr<SocketAddress>(new Ipv6Address(*p)); - } - break; -#endif -#endif - } - return std::auto_ptr<SocketAddress>(NULL); -} - - -bool Utility::u2ip(const std::string& host, struct sockaddr_in& sa, int ai_flags) -{ - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; -#ifdef NO_GETADDRINFO - if ((ai_flags & AI_NUMERICHOST) != 0 || isipv4(host)) - { - Parse pa((char *)host.c_str(), "."); - union { - struct { - unsigned char b1; - unsigned char b2; - unsigned char b3; - unsigned char b4; - } a; - ipaddr_t l; - } u; - u.a.b1 = static_cast<unsigned char>(pa.getvalue()); - u.a.b2 = static_cast<unsigned char>(pa.getvalue()); - u.a.b3 = static_cast<unsigned char>(pa.getvalue()); - u.a.b4 = static_cast<unsigned char>(pa.getvalue()); - memcpy(&sa.sin_addr, &u.l, sizeof(sa.sin_addr)); - return true; - } -#ifndef LINUX - struct hostent *he = gethostbyname( host.c_str() ); - if (!he) - { - return false; - } - memcpy(&sa.sin_addr, he -> h_addr, sizeof(sa.sin_addr)); -#else - struct hostent he; - struct hostent *result = NULL; - int myerrno = 0; - char buf[2000]; - int n = gethostbyname_r(host.c_str(), &he, buf, sizeof(buf), &result, &myerrno); - if (n || !result) - { - return false; - } - if (he.h_addr_list && he.h_addr_list[0]) - memcpy(&sa.sin_addr, he.h_addr, 4); - else - return false; -#endif - return true; -#else - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - // AI_NUMERICHOST - // AI_CANONNAME - // AI_PASSIVE - server - // AI_ADDRCONFIG - // AI_V4MAPPED - // AI_ALL - // AI_NUMERICSERV - hints.ai_flags = ai_flags; - hints.ai_family = AF_INET; - hints.ai_socktype = 0; - hints.ai_protocol = 0; - struct addrinfo *res; - if (Utility::isipv4(host)) - hints.ai_flags |= AI_NUMERICHOST; - int n = getaddrinfo(host.c_str(), NULL, &hints, &res); - if (!n) - { - static RandomNumber prng( true ); - std::vector<struct addrinfo *> vec; - struct addrinfo *ai = res; - while (ai) - { - if (ai -> ai_addrlen == sizeof(sa)) - vec.push_back( ai ); - prng.next(); - // - ai = ai -> ai_next; - } - if (!vec.size()) - return false; - ai = vec[prng.next() % vec.size()]; - { - memcpy(&sa, ai -> ai_addr, ai -> ai_addrlen); - } - freeaddrinfo(res); - return true; - } - std::string error = "Error: "; -#ifndef __CYGWIN__ - error += gai_strerror(n); -#endif - return false; -#endif // NO_GETADDRINFO -} - - -#ifdef ENABLE_IPV6 -#ifdef IPPROTO_IPV6 -bool Utility::u2ip(const std::string& host, struct sockaddr_in6& sa, int ai_flags) -{ - memset(&sa, 0, sizeof(sa)); - sa.sin6_family = AF_INET6; -#ifdef NO_GETADDRINFO - if ((ai_flags & AI_NUMERICHOST) != 0 || isipv6(host)) - { - std::list<std::string> vec; - size_t x = 0; - for (size_t i = 0; i <= host.size(); i++) - { - if (i == host.size() || host[i] == ':') - { - std::string s = host.substr(x, i - x); - // - if (strstr(s.c_str(),".")) // x.x.x.x - { - Parse pa(s,"."); - char slask[100]; // u2ip temporary hex2string conversion - unsigned long b0 = static_cast<unsigned long>(pa.getvalue()); - unsigned long b1 = static_cast<unsigned long>(pa.getvalue()); - unsigned long b2 = static_cast<unsigned long>(pa.getvalue()); - unsigned long b3 = static_cast<unsigned long>(pa.getvalue()); - sprintf(slask,"%lx",b0 * 256 + b1); - vec.push_back(slask); - sprintf(slask,"%lx",b2 * 256 + b3); - vec.push_back(slask); - } - else - { - vec.push_back(s); - } - // - x = i + 1; - } - } - size_t sz = vec.size(); // number of byte pairs - size_t i = 0; // index in in6_addr.in6_u.u6_addr16[] ( 0 .. 7 ) - unsigned short addr16[8]; - for (std::list<std::string>::iterator it = vec.begin(); it != vec.end(); it++) - { - std::string bytepair = *it; - if (bytepair.size()) - { - addr16[i++] = htons(Utility::hex2unsigned(bytepair)); - } - else - { - addr16[i++] = 0; - while (sz++ < 8) - { - addr16[i++] = 0; - } - } - } - memcpy(&sa.sin6_addr, addr16, sizeof(addr16)); - return true; - } -#ifdef SOLARIS - int errnum = 0; - struct hostent *he = getipnodebyname( host.c_str(), AF_INET6, 0, &errnum ); -#else - struct hostent *he = gethostbyname2( host.c_str(), AF_INET6 ); -#endif - if (!he) - { - return false; - } - memcpy(&sa.sin6_addr,he -> h_addr_list[0],he -> h_length); -#ifdef SOLARIS - free(he); -#endif - return true; -#else - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = ai_flags; - hints.ai_family = AF_INET6; - hints.ai_socktype = 0; - hints.ai_protocol = 0; - struct addrinfo *res; - if (Utility::isipv6(host)) - hints.ai_flags |= AI_NUMERICHOST; - int n = getaddrinfo(host.c_str(), NULL, &hints, &res); - if (!n) - { - static RandomNumber prng( true ); - std::vector<struct addrinfo *> vec; - struct addrinfo *ai = res; - while (ai) - { - if (ai -> ai_addrlen == sizeof(sa)) - vec.push_back( ai ); - prng.next(); - // - ai = ai -> ai_next; - } - if (!vec.size()) - return false; - ai = vec[prng.next() % vec.size()]; - { - memcpy(&sa, ai -> ai_addr, ai -> ai_addrlen); - } - freeaddrinfo(res); - return true; - } - std::string error = "Error: "; -#ifndef __CYGWIN__ - error += gai_strerror(n); -#endif - return false; -#endif // NO_GETADDRINFO -} -#endif // IPPROTO_IPV6 -#endif // ENABLE_IPV6 - - -bool Utility::reverse(struct sockaddr *sa, socklen_t sa_len, std::string& hostname, int flags) -{ - std::string service; - return Utility::reverse(sa, sa_len, hostname, service, flags); -} - - -bool Utility::reverse(struct sockaddr *sa, socklen_t sa_len, std::string& hostname, std::string& service, int flags) -{ - hostname = ""; - service = ""; -#ifdef NO_GETADDRINFO - switch (sa -> sa_family) - { - case AF_INET: - if (flags & NI_NUMERICHOST) - { - union { - struct { - unsigned char b1; - unsigned char b2; - unsigned char b3; - unsigned char b4; - } a; - ipaddr_t l; - } u; - struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; - memcpy(&u.l, &sa_in -> sin_addr, sizeof(u.l)); - char tmp[100]; - sprintf(tmp, "%u.%u.%u.%u", u.a.b1, u.a.b2, u.a.b3, u.a.b4); - hostname = tmp; - return true; - } - else - { - struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; - struct hostent *h = gethostbyaddr( (const char *)&sa_in -> sin_addr, sizeof(sa_in -> sin_addr), AF_INET); - if (h) - { - hostname = h -> h_name; - return true; - } - } - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - if (flags & NI_NUMERICHOST) - { - char slask[100]; // l2ip temporary - *slask = 0; - unsigned int prev = 0; - bool skipped = false; - bool ok_to_skip = true; - { - unsigned short addr16[8]; - struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; - memcpy(addr16, &sa_in6 -> sin6_addr, sizeof(addr16)); - for (size_t i = 0; i < 8; i++) - { - unsigned short x = ntohs(addr16[i]); - if (*slask && (x || !ok_to_skip || prev)) - strcat(slask,":"); - if (x || !ok_to_skip) - { - sprintf(slask + strlen(slask),"%x", x); - if (x && skipped) - ok_to_skip = false; - } - else - { - skipped = true; - } - prev = x; - } - } - if (!*slask) - strcpy(slask, "::"); - hostname = slask; - return true; - } - else - { - // %! TODO: ipv6 reverse lookup - struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)sa; - struct hostent *h = gethostbyaddr( (const char *)&sa_in -> sin6_addr, sizeof(sa_in -> sin6_addr), AF_INET6); - if (h) - { - hostname = h -> h_name; - return true; - } - } - break; -#endif - } - return false; -#else - char host[NI_MAXHOST]; - char serv[NI_MAXSERV]; - // NI_NOFQDN - // NI_NUMERICHOST - // NI_NAMEREQD - // NI_NUMERICSERV - // NI_DGRAM - int n = getnameinfo(sa, sa_len, host, sizeof(host), serv, sizeof(serv), flags); - if (n) - { - // EAI_AGAIN - // EAI_BADFLAGS - // EAI_FAIL - // EAI_FAMILY - // EAI_MEMORY - // EAI_NONAME - // EAI_OVERFLOW - // EAI_SYSTEM - return false; - } - hostname = host; - service = serv; - return true; -#endif // NO_GETADDRINFO -} - - -bool Utility::u2service(const std::string& name, int& service, int ai_flags) -{ -#ifdef NO_GETADDRINFO - // %! - return false; -#else - struct addrinfo hints; - service = 0; - memset(&hints, 0, sizeof(hints)); - // AI_NUMERICHOST - // AI_CANONNAME - // AI_PASSIVE - server - // AI_ADDRCONFIG - // AI_V4MAPPED - // AI_ALL - // AI_NUMERICSERV - hints.ai_flags = ai_flags; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = 0; - hints.ai_protocol = 0; - struct addrinfo *res; - int n = getaddrinfo(NULL, name.c_str(), &hints, &res); - if (!n) - { - service = res -> ai_protocol; - freeaddrinfo(res); - return true; - } - return false; -#endif // NO_GETADDRINFO -} - - -unsigned long Utility::ThreadID() -{ -#ifdef _WIN32 - return GetCurrentThreadId(); -#else - return (unsigned long)pthread_self(); -#endif -} - - -std::string Utility::ToLower(const std::string& str) -{ - std::string r; - for (size_t i = 0; i < str.size(); i++) - { - if (str[i] >= 'A' && str[i] <= 'Z') - r += str[i] | 32; - else - r += str[i]; - } - return r; -} - - -std::string Utility::ToUpper(const std::string& str) -{ - std::string r; - for (size_t i = 0; i < str.size(); i++) - { - if (str[i] >= 'a' && str[i] <= 'z') - r += (char)(str[i] - 32); - else - r += str[i]; - } - return r; -} - - -std::string Utility::ToString(double d) -{ - char tmp[100]; - sprintf(tmp, "%f", d); - return tmp; -} - - -#ifdef SOCKETS_NAMESPACE -} -#endif - |