1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
17 #include <sys/types.h>
19 #include <sys/utsname.h>
20 #include <arpa/inet.h>
21 #include <sys/socket.h> // extraccion de IP del hostname
22 #include <netinet/in.h> // extraccion de IP del hostname
23 #include <netdb.h> // extraccion de IP del hostname
24 #include <unistd.h> // gethostname
26 #include <anna/core/functions.hpp>
27 #include <anna/core/DataBlock.hpp>
28 #include <anna/core/tracing/Logger.hpp>
29 #include <anna/core/util/Second.hpp>
30 #include <anna/core/util/Tokenizer.hpp>
38 #define PAGE_WIDTH_LENGTH 80
40 ExclusiveHash <std::string> functions::st_stringExclusiveHash;
41 ExclusiveHash <std::string, int> functions::st_string2intExclusiveHash;
43 string functions::getVersion() throw() {
44 static const int version = ANNA_VERSION;
46 int mainVersion = (version & 0xff00) >> 8;
47 int subVersion = (version & 0xff);
49 sprintf(aux, "%d.%d", mainVersion, subVersion);
51 return result += getArchitecture();
55 (1) Solo coge los dos primeros digitos del numero de release
57 string functions::getArchitecture() throw() {
59 WHEN_MULTITHREAD(result = "/MT");
60 WHEN_SINGLETHREAD(result = "/ST");
74 char* release = anna_strchr(un.release, '.'); // (1)
77 if((release = anna_strchr(release + 1, '.')) != NULL)
87 string functions::asString(const int number)
90 sprintf(aux, "%d", number);
94 string functions::asString(const S64 number)
97 //sprintf(aux, "%lld", number);
99 sprintf (aux, "%ld", number);
101 sprintf (aux, "%lld", number);
106 string functions::asString(const unsigned int number)
109 sprintf(aux, "%u", number);
113 string functions::asString(const U64 number)
116 //sprintf(aux, "%llu", number);
118 sprintf (aux, "%lu", number);
120 sprintf (aux, "%llu", number);
125 string functions::asString(const float number, const char* format)
128 sprintf(aux, format, number);
132 string functions::asString(const double number, const char* format)
135 sprintf(aux, format, number);
139 string functions::asDateTime(const Second &second)
141 char aux [DateTimeSizeString];
142 return std::string(asDateTime(second, aux));
145 const char* functions::asDateTime(const Second &second, char* result)
147 struct tm* tt = localtime((time_t*) & second);
149 result, "%02d/%02d/%4d %02d:%02d:%02d",
150 tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900,
151 tt->tm_hour, tt->tm_min, tt->tm_sec
156 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
158 return dataBlock.asString(characterByLine);
161 string functions::asHexString(const int number)
164 sprintf(aux, "0x%x", number);
168 string functions::asHexString(const S64 number)
171 //sprintf(aux, "0x%llx", number);
173 sprintf (aux, "0x%lx", number);
175 sprintf (aux, "0x%llx", number);
180 // from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited"
181 // Dr. Dobb's Journal, April 1996)
182 S64 functions::hash(const char* p)
184 static const int long_bits = sizeof(S64) << 3;
185 static const int one_eighth = long_bits >> 3;
186 static const int three_fourths = long_bits * 3 / 4;
187 static const S64 high_bits = ((S64)(~0L)) << (long_bits - one_eighth);
192 result = (result << one_eighth) + *p ++;
194 if((temp = result & high_bits) != 0)
195 result = (result ^(temp >> three_fourths)) &~ high_bits;
202 std::string functions::asHexString(const DataBlock& dataBlock)
204 const char* buffer = dataBlock.getData();
205 const int size = dataBlock.getSize();
209 for(int ii = 0; ii < size; ii ++) {
210 byte = (buffer [ii] & 0xf0) >> 4;
211 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
212 byte = (buffer [ii] & 0x0f);
213 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
220 * Gets the original value obtained with #asHexString (const DataBlock&).
221 * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
222 * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
223 * \param target DataBlock for string decode.
224 * \return DataBlock corresponding to the provided string.
227 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
228 throw(RuntimeException) {
230 if((hexString.length() % 2) != 0)
231 throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
234 const char* src = hexString.data();
239 for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
240 if(isxdigit(aux = src [ii - 1]) == 0)
241 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
243 hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
245 if(isxdigit(aux = src [ii]) == 0)
246 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
248 hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
255 string functions::asString(const char* format, ...)
259 va_start(ap, format);
260 vsnprintf(aux, sizeof(aux), format, ap);
265 void functions::sleep(const Millisecond &millisecond)
269 req.tv_sec = millisecond.getValue() / 1000; // segundos
270 req.tv_nsec = (millisecond.getValue() % 1000); // milisegundos
271 req.tv_nsec *= 1000000; // mili = 10e-3, nano=10-9
274 while((r = nanosleep(&req, &rem)) != 0) {
278 string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
279 msg += functions::asText("| nsec: ", (int) req.tv_nsec);
281 RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
288 bool functions::asBool(const char* str)
289 throw(RuntimeException) {
293 if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
296 if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
299 string msg("anna::funcions::asBool | Cannot interpret '");
301 msg += "' as boolean";
302 throw RuntimeException(msg, ANNA_FILE_LOCATION);
305 S64 functions::asInteger64(const char* str)
308 //sscanf(str, "%lld", &number);
310 sscanf (str, "%ld", &number);
312 sscanf (str, "%lld", &number);
317 pthread_t functions::getCurrentThread()
319 WHEN_MULTITHREAD(return pthread_self());
320 WHEN_SINGLETHREAD(return 0);
323 bool functions::isLike(const char* pattern, const std::string& _value)
324 throw(RuntimeException) {
325 const char* value = _value.c_str();
329 if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
331 string msg("anna::functions::isLike | ");
332 msg += " | Pattern: ";
338 if(regerror(ret, &preg, err, sizeof(err)))
341 msg += "Invalid pattern";
343 throw RuntimeException(msg, ANNA_FILE_LOCATION);
346 const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
353 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
354 throw(RuntimeException) {
355 if(bitShift > intBitSize) {
356 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
357 throw RuntimeException(msg, ANNA_FILE_LOCATION);
360 if((bitsize(n1) + bitShift) > int64BitSize) {
361 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
362 throw RuntimeException(msg, ANNA_FILE_LOCATION);
365 if(bitsize(n2) > bitShift) {
366 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
367 throw RuntimeException(msg, ANNA_FILE_LOCATION);
374 if(bitShift == intBitSize) {
376 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
377 msg += functions::asHexString(result);
378 Logger::information(msg, ANNA_FILE_LOCATION);
387 * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
389 int functions::log2(const unsigned int v)
391 static const char LogTable256[] = {
392 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
393 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
394 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
395 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
396 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
397 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
398 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
399 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
400 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
401 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
402 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
403 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
404 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
405 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
406 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
407 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
409 int r = -1; // r will be lg(v)
410 unsigned int t, tt; // temporaries
413 r = ((t = tt >> 8)) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
415 r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
421 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
423 std::string singular = (wordForSingular ? wordForSingular : "entry");
424 std::string plural = (wordForPlural ? wordForPlural : "entries");
426 if(wordForSingular && !wordForPlural)
427 plural = singular + "s";
429 result += ((number != 0) ? anna::functions::asString(number) : "no");
431 result += ((number != 1) ? plural : singular);
436 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
438 int d_size = title.size();
439 int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
442 if(mode == TextJustifyMode::Center) {
443 repeat = (repeat - 1) / 2;
444 adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
447 if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
448 for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
455 if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
458 for(int k = 0; k < repeat; k++) result += filler;
465 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
467 int ou_repeat = title.size();
468 int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
471 if(mode == TextHighlightMode::LeftAndRightline) {
472 lr_repeat = (lr_repeat - 1) / 2;
473 adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
476 if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
477 for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
482 if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
483 for(int k = 0; k < ou_repeat; k++) result += filler;
490 if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
493 for(int k = 0; k < ou_repeat; k++) result += filler;
496 if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
499 for(int k = 0; k < lr_repeat; k++) result += filler;
502 if(appendCR) result += "\n";
508 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
510 size_t pos, from = 0;
511 std::string tab, crTab = "\n";
513 for(int k = 0; k < tabSpaces; k++) tab += " ";
519 while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
520 result.replace(pos, 1, crTab);
528 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
531 if(pattern.size() < suffix.size()) return false;
533 size_t pos = pattern.rfind(suffix);
535 if(pos == std::string::npos) return false;
537 preffix.assign(pattern.c_str(), pos);
538 return (pos == (pattern.size() - suffix.size()));
542 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
545 if(pattern.size() < preffix.size()) return false;
547 if(pattern.find(preffix) != 0) return false;
549 suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
554 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
555 std::string result = text;
557 if(!item || !target) return result; // protection for NULL strings provided
559 size_t lengthReplaced = strlen(item);
560 size_t pos = result.find(item);
562 while(pos != std::string::npos) {
563 result.replace(pos, lengthReplaced, target);
567 pos = result.find(item);
574 std::string functions::addQuotationMarks(const std::string & str) throw() {
575 std::string result = "'";
582 std::string functions::addQuotationMarks(const char * str) throw() {
583 std::string result = "'";
584 result += (str ? str : "<null>");
590 std::string functions::addQuotationMarks(const int & integer) throw() {
591 std::string result = "'";
592 result += anna::functions::asString(integer);
598 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
599 std::string result = "";
602 std::vector<int>::const_iterator iter;
603 std::vector<int>::const_iterator iter_min(v.begin());
604 std::vector<int>::const_iterator iter_max(v.end());
606 for(iter = iter_min; iter != iter_max; iter++) {
607 result += anna::functions::asString(*iter);
611 // Delete the last space: starts at 'size()-1', take 1 caracter:
612 result.erase(result.size() - 1, 1);
619 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
620 std::string result = "";
623 std::vector<std::string>::const_iterator iter;
624 std::vector<std::string>::const_iterator iter_min(v.begin());
625 std::vector<std::string>::const_iterator iter_max(v.end());
627 for(iter = iter_min; iter != iter_max; iter++) {
632 // Delete the last space: starts at 'size()-1', take 1 caracter:
633 result.erase(result.size() - 1, 1);
640 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
641 std::string result = address;
643 result += anna::functions::asString(port);
648 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
650 // Supposed printable by default:
651 isFullyPrintable = true;
653 if(size == 0 || !buffer) {
655 isFullyPrintable = false;
659 for(int k = 0; k < size; k ++) {
660 unsigned char c = (unsigned char) buffer [k];
661 int printable = isprint(c);
662 result += (printable ? (char) c : '.');
664 if(!printable) isFullyPrintable = false;
671 std::string functions::getHostname() throw() {
673 std::string result = "<hostname>";
675 if(gethostname(aux, sizeof aux) == 0 /*success*/)
681 std::string functions::getDomainname() throw() {
683 std::string result = "<domainname>";
685 if(getdomainname(aux, sizeof aux) == 0 /*success*/)
691 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
692 std::string hn = hostname ? hostname : (functions::getHostname());
693 std::string dn = domainname ? domainname : (functions::getDomainname());
694 // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
696 if(hn == "") return dn;
698 if(dn == "") return hn;
700 std::string label(hn, 0, 63);
701 std::string fqdn(label + "." + dn, 0, 255);
705 std::string functions::getHostnameIP() throw() {
706 std::string result = "";
708 struct in_addr **addr_list;
709 struct in_addr ipv4addr;
711 gethostname(hostname, sizeof hostname);
713 if((he = gethostbyname(hostname)) != NULL) {
714 // Official name: he->h_name
716 addr_list = (struct in_addr **)he->h_addr_list;
718 for(int i = 0; addr_list[i] != NULL; i++) {
719 //printf("%s ", inet_ntoa(*addr_list[i]));
720 result = inet_ntoa(*addr_list[i]);
729 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
730 int length = rawPresentation.size();
732 if(length != 8 && length != 32)
733 throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
735 anna::DataBlock result(true);
737 char rByte[3]; // readable byte
740 for(int k = 0; k < length; k += 2) {
741 rByte[0] = rawPresentation[k];
742 rByte[1] = rawPresentation[k + 1];
743 sscanf(rByte, "%x", &byte);
751 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
752 int length = db.getSize();
754 if(length != 4 && length != 16)
755 throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
757 std::string result = "";
759 char rByte[3]; // readable byte
762 for(int k = 0; k < length; k++) {
763 byte = (unsigned char)db[k];
764 sprintf(rByte, "%.2X", byte);
776 // IPv6 addresses have two logical parts: a 64-bit network prefix, and a 64-bit host address part. (The host address is often automatically generated from the interface MAC address.[34]) An IPv6 address is represented by 8 groups of 16-bit hexadecimal values separated by colons (:) shown as follows:
777 // A typical example of an IPv6 address is
778 // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
779 // The hexadecimal digits are case-insensitive.
781 // The 128-bit IPv6 address can be abbreviated with the following rules:
782 // -Rule one: Leading zeroes within a 16-bit value may be omitted. For example, the address fe80:0000:0000:0000:0202:b3ff:fe1e:8329 may be written as fe80:0:0:0:202:b3ff:fe1e:8329
783 // -Rule two: A single occurrence of consecutive groups of zeroes within an address may be replaced by a double colon. For example, fe80:0:0:0:202:b3ff:fe1e:8329 becomes fe80::202:b3ff:fe1e:8329
784 // A single IPv6 address can be represented in several different ways, such as 2001:db8::1:0:0:1 and 2001:0DB8:0:0:1::1. RFC 5952 recommends a canonical textual representation.
786 // Si la dirección tiene más de una serie de grupos nulos consecutivos la compresión sólo se permite en uno de ellos.
787 // AsÃ, las siguientes son representaciones posibles de una misma dirección:
789 // 2001:0DB8:0000:0000:0000:0000:1428:57ab
790 // 2001:0DB8:0000:0000:0000::1428:57ab
791 // 2001:0DB8:0:0:0:0:1428:57ab
792 // 2001:0DB8:0::0:1428:57ab
793 // 2001:0DB8::1428:57ab
794 // son todas válidas y significan lo mismo, pero
797 // no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
799 // Los ceros iniciales en un grupo también se pueden omitir:
800 // 2001:0DB8:02de::0e13
803 // Si la dirección es una dirección IPv4 empotrada (mapped), los últimos 32 bits pueden escribirse en base decimal, asÃ:
804 // ::ffff:192.168.89.9
807 // No se debe confundir con:
811 // El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
812 // Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
813 // (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
814 // la notación mixta dirección IPv4 compatible, en cuyo caso la dirección deberÃa ser ::135.75.43.52. Este tipo de dirección IPv4 compatible
815 // casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
817 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
819 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
820 if(ipv4Type == IPv4Type::Estrict) {
821 // La expresión regular no controla si hay mas de 3 puntos:
824 for(int k = 0; k < ip.length(); k++)
825 if(ip[k] == '.') n_dot++;
830 bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
831 bool colon = (ip.find(":") != std::string::npos);
832 return (ipv4 && !colon);
835 if(ipv4Type == IPv4Type::Compatible) {
836 std::string pureIPv4 = ip;
837 bool firstDoubleColon = (ip.find("::") == 0);
839 if(firstDoubleColon) {
840 pureIPv4.erase(0, 2);
841 bool anotherColon = (pureIPv4.find(":") != std::string::npos);
843 if(anotherColon) return (false);
845 return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
849 if(ipv4Type == IPv4Type::Mapped) {
850 size_t posLastColon = ip.rfind(":");
852 if(posLastColon == std::string::npos)
855 if(!isIPv4(ip.substr(posLastColon + 1)))
858 unsigned char buf[sizeof(struct in6_addr)];
859 int s = inet_pton(AF_INET6, ip.c_str(), buf);
869 bool functions::isIPv6(const std::string & ip) throw() {
870 // Chequeo de digitos permitidos:
871 for(int k = 0; k < ip.length(); k++) {
872 bool digit = isdigit(ip[k]);
873 bool hex = ((ip[k] == 'a') ||
885 bool colon = (ip[k] == ':');
887 if(!digit && !hex && !colon)
891 return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
895 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
896 if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
897 throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
899 std::string result, pureIPv4;
900 bool firstDoubleColon = (ip.find("::") == 0);
902 if(firstDoubleColon) {
904 size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
905 pureIPv4 = ip.substr(ipv4_pos);
908 size_t posColon = ip.find(":");
910 if(posColon == 0) // first colon
911 throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
913 if(posColon != std::string::npos) // any colon
914 return ip; // seems to be IPv6 already?
916 throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
922 // Number of ocurrences for '.'
925 for(int k = 0; k < pureIPv4.length(); k++)
926 if(pureIPv4[k] == '.') n_dot++;
929 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
932 anna::Tokenizer::const_iterator tok_it;
934 tok.apply(pureIPv4, ".");
938 for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
939 token = anna::Tokenizer::data(tok_it);
940 v[cnt] = atoi(anna::Tokenizer::data(tok_it));
942 if(v[cnt] < 0 || v[cnt] > 255)
943 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
948 if(isIPv4(ip, IPv4Type::Compatible))
949 result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
951 result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
957 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
958 std::string result = ip;
959 // std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
960 std::transform(result.begin(), result.end(), result.begin(), ::tolower);
962 if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
963 result = IPv4To6(result);
965 size_t pos = result.find("::"); // zeroes simplification group
966 size_t rpos = result.rfind("::"); // zeroes simplification group
969 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
971 if(pos != std::string::npos) { // zeroes exists
972 // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
973 // Number of ocurrences for ':'
976 for(int k = 0; k < result.length(); k++)
977 if(result[k] == ':') n_colon++;
979 // Generate equivalent to '::'
980 std::string equiv_str;
982 for(int k = 0; k < (8 - n_colon); k++)
986 // Replace with equivalent:
987 result.replace(pos, 2, equiv_str);
989 // Special case: IP began with '::'
990 if(result[0] == ':') {
991 result.insert(0, "0");
994 // Special case: IP was only '::'
995 if(result[result.length() - 1] == ':') {
1000 // Protection: it must be seven colons:
1003 for(int k = 0; k < result.length(); k++)
1004 if(result[k] == ':') n_colon++;
1007 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1009 // Padding with zeroes at left
1010 anna::Tokenizer ipStr;
1011 anna::Tokenizer::const_iterator ipStr_it;
1013 ipStr.apply(result, ":");
1016 for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1017 token = anna::Tokenizer::data(ipStr_it);
1019 while(token.length() < 4) token.insert(0, "0");
1026 size_t lastPos = result.length() - 1;
1027 result.erase(lastPos, 1);
1029 // Chequeo de digitos permitidos:
1030 for(int k = 0; k < result.length(); k++) {
1031 bool digit = isdigit(result[k]);
1032 bool hex = ((result[k] == 'a') ||
1033 (result[k] == 'b') ||
1034 (result[k] == 'c') ||
1035 (result[k] == 'd') ||
1036 (result[k] == 'e') ||
1037 (result[k] == 'f'));
1038 bool colon = (result[k] == ':');
1040 if(!digit && !hex && !colon) {
1041 throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1049 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1050 //if (ip1 == ip2) return true; it should validate wrong-format addresses
1051 return (normalizeIP(ip1) == normalizeIP(ip2));
1055 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1056 size_t preffixPos = preffixedIpv6.find("/");
1058 if(preffixPos == std::string::npos)
1059 return (sameIP(_ipv6, preffixedIpv6));
1061 std::string ipv6 = _ipv6;
1063 if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1065 std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1066 std::string ipv6_2 = _ipv6_2;
1068 if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1070 std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1071 int ipv6_2_preffixLength = atoi(preffix.c_str());
1073 if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1074 throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1076 // No restriction, all ipv6_2 ignored (special and not usual case)
1077 if(ipv6_2_preffixLength == 0) return true;
1080 int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1081 int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1082 int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1083 char mask = 0xFF << (8 - spare);
1085 anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1086 anna::DataBlock restrictedIP1(true);
1087 restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1089 if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1092 anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1093 anna::DataBlock realIP2(true);
1094 realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1096 if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1099 int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1104 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1105 anna::DataBlock result(true);
1108 unsigned char buf[sizeof(struct in6_addr)];
1109 int s = inet_pton(AF_INET, ip.c_str(), buf);
1112 result += (S8)buf[0];
1113 result += (S8)buf[1];
1114 result += (S8)buf[2];
1115 result += (S8)buf[3];
1117 if(s < 0) perror("inet_pton");
1119 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1122 unsigned char buf[sizeof(struct in6_addr)];
1123 int s = inet_pton(AF_INET6, ip.c_str(), buf);
1126 result += (S8)buf[0];
1127 result += (S8)buf[1];
1128 result += (S8)buf[2];
1129 result += (S8)buf[3];
1130 result += (S8)buf[4];
1131 result += (S8)buf[5];
1132 result += (S8)buf[6];
1133 result += (S8)buf[7];
1134 result += (S8)buf[8];
1135 result += (S8)buf[9];
1136 result += (S8)buf[10];
1137 result += (S8)buf[11];
1138 result += (S8)buf[12];
1139 result += (S8)buf[13];
1140 result += (S8)buf[14];
1141 result += (S8)buf[15];
1143 if(s < 0) perror("inet_pton");
1145 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1151 // anna::DataBlock result(true);
1154 // if (isIPv4(ip)) {
1156 // int dec1, dec2, dec3, dec4; // U32 type is valid, 'int' better: argument for %d must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
1157 // sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1158 // result += (S8)dec1;
1159 // result += (S8)dec2;
1160 // result += (S8)dec3;
1161 // result += (S8)dec4;
1165 // int hex1, hex2, hex3, hex4, hex5, hex6, hex7, hex8; // U16 type is not valid: argument for %X must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
1166 // sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1167 // result += ((S8)(hex1 >> 8));
1168 // result += ((S8)(hex1 & 0x00FF));
1169 // result += ((S8)(hex2 >> 8));
1170 // result += ((S8)(hex2 & 0x00FF));
1171 // result += ((S8)(hex3 >> 8));
1172 // result += ((S8)(hex3 & 0x00FF));
1173 // result += ((S8)(hex4 >> 8));
1174 // result += ((S8)(hex4 & 0x00FF));
1175 // result += ((S8)(hex5 >> 8));
1176 // result += ((S8)(hex5 & 0x00FF));
1177 // result += ((S8)(hex6 >> 8));
1178 // result += ((S8)(hex6 & 0x00FF));
1179 // result += ((S8)(hex7 >> 8));
1180 // result += ((S8)(hex7 & 0x00FF));
1181 // result += ((S8)(hex8 >> 8));
1182 // result += ((S8)(hex8 & 0x00FF));
1190 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1191 std::string result = "";
1192 char str[INET6_ADDRSTRLEN];
1194 if(bufferLength == 4) {
1195 if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1197 } else if(bufferLength == 16) {
1198 if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1201 throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1204 throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1206 return (normalize ? normalizeIP(result) : result);
1208 // std::string result;
1211 // if (bufferLength == 4) { // IPv4
1212 // result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1214 // else if (bufferLength == 16) { // IPv6
1215 // result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1216 // ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1217 // (((U8)buffer[1]) & 0x00FF),
1218 // ((((U8)buffer[2]) << 8) & 0xFF00) +
1219 // (((U8)buffer[3]) & 0x00FF),
1220 // ((((U8)buffer[4]) << 8) & 0xFF00) +
1221 // (((U8)buffer[5]) & 0x00FF),
1222 // ((((U8)buffer[6]) << 8) & 0xFF00) +
1223 // (((U8)buffer[7]) & 0x00FF),
1224 // ((((U8)buffer[8]) << 8) & 0xFF00) +
1225 // (((U8)buffer[9]) & 0x00FF),
1226 // ((((U8)buffer[10]) << 8) & 0xFF00) +
1227 // (((U8)buffer[11]) & 0x00FF),
1228 // ((((U8)buffer[12]) << 8) & 0xFF00) +
1229 // (((U8)buffer[13]) & 0x00FF),
1230 // ((((U8)buffer[14]) << 8) & 0xFF00) +
1231 // (((U8)buffer[15]) & 0x00FF));
1234 // throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1237 // return (normalize ? normalizeIP(result):result);
1241 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1242 size_t pos = literal.find_last_of(":");
1243 size_t lastPos = literal.size() - 1;
1244 address = ""; port = -1; // assume error
1246 if((pos != std::string::npos) && (pos != lastPos)) {
1247 address = literal.substr(0, pos);
1248 port = atoi(literal.substr(pos + 1, lastPos).c_str());
1253 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1255 std::string address;
1257 anna::Tokenizer lst;
1258 lst.apply(list, ",");
1260 if(lst.size() < 1) return result;
1262 anna::Tokenizer::const_iterator tok_min(lst.begin());
1263 anna::Tokenizer::const_iterator tok_max(lst.end());
1264 anna::Tokenizer::const_iterator tok_iter;
1266 for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1267 getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1269 if(port == -1) { result.clear(); return result; }
1271 result.push_back(socket_t(address, port));
1277 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1280 socket_v_it it_min(socketVector.begin());
1281 socket_v_it it_max(socketVector.end());
1283 for(it = it_min; it != it_max; it++) {
1284 result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1287 result.erase(result.size() - 1, 1); // remove last comma
1291 bool functions::littleEndian()
1294 char *p = (char *) &i;
1295 if (p[0] == 1) return true;
1299 const char* functions::codeInteger(char* result, const int n)
1302 char* w((char*) &aux);
1304 *(result + 1) = *(w + 1);
1305 *(result + 2) = *(w + 2);
1306 *(result + 3) = *(w + 3);
1310 const char* functions::codeShort(char* result, const short int n)
1312 short int aux(htons(n));
1313 char* w((char*) &aux);
1315 *(result + 1) = *(w + 1);
1319 const char* functions::codeInteger64(char* result, const S64 n)
1321 S64 aux(0xffffffff);
1325 n2 = (aux >> 32) & 0xffffffff;
1326 codeInteger(result, n2);
1327 n2 = n & 0xffffffff;
1328 codeInteger(result + sizeof(int), n2);
1333 const char* functions::codeFloat(char* result, const float n)
1336 anna_memcpy(&ii, &n, sizeof(n));
1337 return functions::codeInteger(result, ii);
1341 const char* functions::codeDouble(char* result, const double n)
1344 anna_memcpy(&ii, &n, sizeof(n));
1345 return functions::codeInteger64(result, ii);
1348 int functions::decodeInteger(const char* data)
1351 char* w((char*) &result);
1353 *(w + 1) = *(data + 1);
1354 *(w + 2) = *(data + 2);
1355 *(w + 3) = *(data + 3);
1356 return ntohl(result);
1359 short int functions::decodeShort(const char* data)
1362 char* w((char*) &result);
1364 *(w + 1) = *(data + 1);
1365 return ntohs(result);
1368 S64 functions::decodeInteger64(const char* data)
1370 S64 result(decodeInteger(data));
1372 return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1376 float functions::decodeFloat(const char* data)
1379 int ii = functions::decodeInteger(data);
1380 anna_memcpy(&result, &ii, sizeof(result));
1385 double functions::decodeDouble(const char* data)
1388 S64 ii = functions::decodeInteger64(data);
1389 anna_memcpy(&result, &ii, sizeof(result));
1395 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1396 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1398 isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1399 bool filler = isupNumber.OddEven;
1401 if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1402 throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1404 isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1405 isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1407 if(calledOrCalling) {
1408 isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1410 isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1411 isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1412 isupNumber.Screening = (short)(buffer[1] & 0x03);
1416 isupNumber.Digits = "";
1419 for(int k = 2; k < length; k ++) {
1420 byte = (buffer [k] & 0x0f);
1421 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1422 byte = (buffer [k] & 0xf0) >> 4;
1423 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1426 if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler
1430 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1432 if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1433 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1435 bool odd = isupNumber.OddEven;
1436 bool oddDigits = (isupNumber.Digits.size() % 2);
1438 if(odd != oddDigits)
1439 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1441 if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1442 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1444 if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1445 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1447 if(calledOrCalling) {
1448 if(isupNumber.NumberIncomplete != 0)
1449 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1451 if(isupNumber.AddressPresentationRestricted != 0)
1452 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1454 if(isupNumber.Screening != 0)
1455 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1457 if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1458 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1460 if(isupNumber.InternalNetworkNumber != 0)
1461 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1463 if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1464 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1466 if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1467 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1469 if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1470 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1475 bool filler = isupNumber.OddEven;
1476 bool hasDigits = (isupNumber.Digits.size() > 0);
1477 byte = filler ? 0x80 : 0x00;
1478 byte = byte |= isupNumber.NatureOfAddress;
1481 if(calledOrCalling) {
1482 byte = isupNumber.InternalNetworkNumber << 7;
1483 byte = byte |= (isupNumber.NumberingPlan << 4);
1485 byte = isupNumber.NumberIncomplete << 7;
1486 byte = byte |= (isupNumber.NumberingPlan << 4);
1487 byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1488 byte = byte |= isupNumber.Screening;
1494 std::string dtlc = isupNumber.Digits; // digits to lower case
1495 //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1496 const char *digits = dtlc.c_str();
1498 for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1499 if(isxdigit(byte = digits [k - 1]) == 0)
1500 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1502 hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1504 if(isxdigit(byte = digits [k]) == 0)
1505 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1507 hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1511 if(hasDigits && filler) {
1512 if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1513 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1515 target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1520 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1522 codeIsupNumber(isupNumber, calledOrCalling, target);
1523 length = target.size();
1524 memcpy(buffer, target.c_str(), length);