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);
107 string functions::asString(const unsigned int number)
110 sprintf(aux, "%u", number);
114 string functions::asString(const U64 number)
117 sprintf(aux, "%llu", number);
120 sprintf (aux, "%lu", number);
122 sprintf (aux, "%llu", number);
128 string functions::asString(const float number, const char* format)
131 sprintf(aux, format, number);
135 string functions::asString(const double number, const char* format)
138 sprintf(aux, format, number);
142 string functions::asDateTime(const Second &second)
144 char aux [DateTimeSizeString];
145 return std::string(asDateTime(second, aux));
148 const char* functions::asDateTime(const Second &second, char* result)
150 struct tm* tt = localtime((time_t*) & second);
152 result, "%02d/%02d/%4d %02d:%02d:%02d",
153 tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900,
154 tt->tm_hour, tt->tm_min, tt->tm_sec
159 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
161 return dataBlock.asString(characterByLine);
164 string functions::asHexString(const int number)
167 sprintf(aux, "0x%x", number);
171 string functions::asHexString(const S64 number)
174 sprintf(aux, "0x%llx", number);
177 sprintf (aux, "0x%lx", number);
179 sprintf (aux, "0x%llx", number);
185 // from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited"
186 // Dr. Dobb's Journal, April 1996)
187 S64 functions::hash(const char* p)
189 static const int long_bits = sizeof(S64) << 3;
190 static const int one_eighth = long_bits >> 3;
191 static const int three_fourths = long_bits * 3 / 4;
192 static const S64 high_bits = ((S64)(~0L)) << (long_bits - one_eighth);
197 result = (result << one_eighth) + *p ++;
199 if((temp = result & high_bits) != 0)
200 result = (result ^(temp >> three_fourths)) &~ high_bits;
207 std::string functions::asHexString(const DataBlock& dataBlock)
209 const char* buffer = dataBlock.getData();
210 const int size = dataBlock.getSize();
214 for(int ii = 0; ii < size; ii ++) {
215 byte = (buffer [ii] & 0xf0) >> 4;
216 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
217 byte = (buffer [ii] & 0x0f);
218 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
225 * Gets the original value obtained with #asHexString (const DataBlock&).
226 * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
227 * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
228 * \param target DataBlock for string decode.
229 * \return DataBlock corresponding to the provided string.
232 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
233 throw(RuntimeException) {
235 if((hexString.length() % 2) != 0)
236 throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
239 const char* src = hexString.data();
244 for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
245 if(isxdigit(aux = src [ii - 1]) == 0)
246 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
248 hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
250 if(isxdigit(aux = src [ii]) == 0)
251 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
253 hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
260 string functions::asString(const char* format, ...)
264 va_start(ap, format);
265 vsnprintf(aux, sizeof(aux), format, ap);
270 void functions::sleep(const Millisecond &millisecond)
274 req.tv_sec = millisecond.getValue() / 1000; // segundos
275 req.tv_nsec = (millisecond.getValue() % 1000); // milisegundos
276 req.tv_nsec *= 1000000; // mili = 10e-3, nano=10-9
279 while((r = nanosleep(&req, &rem)) != 0) {
283 string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
284 msg += functions::asText("| nsec: ", (int) req.tv_nsec);
286 RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
293 bool functions::asBool(const char* str)
294 throw(RuntimeException) {
298 if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
301 if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
304 string msg("anna::funcions::asBool | Cannot interpret '");
306 msg += "' as boolean";
307 throw RuntimeException(msg, ANNA_FILE_LOCATION);
310 S64 functions::asInteger64(const char* str)
313 sscanf(str, "%lld", &number);
316 sscanf (str, "%ld", &number);
318 sscanf (str, "%lld", &number);
324 pthread_t functions::getCurrentThread()
326 WHEN_MULTITHREAD(return pthread_self());
327 WHEN_SINGLETHREAD(return 0);
330 bool functions::isLike(const char* pattern, const std::string& _value)
331 throw(RuntimeException) {
332 const char* value = _value.c_str();
336 if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
338 string msg("anna::functions::isLike | ");
339 msg += " | Pattern: ";
345 if(regerror(ret, &preg, err, sizeof(err)))
348 msg += "Invalid pattern";
350 throw RuntimeException(msg, ANNA_FILE_LOCATION);
353 const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
360 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
361 throw(RuntimeException) {
362 if(bitShift > intBitSize) {
363 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
364 throw RuntimeException(msg, ANNA_FILE_LOCATION);
367 if((bitsize(n1) + bitShift) > int64BitSize) {
368 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
369 throw RuntimeException(msg, ANNA_FILE_LOCATION);
372 if(bitsize(n2) > bitShift) {
373 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
374 throw RuntimeException(msg, ANNA_FILE_LOCATION);
381 if(bitShift == intBitSize) {
383 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
384 msg += functions::asHexString(result);
385 Logger::information(msg, ANNA_FILE_LOCATION);
394 * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
396 int functions::log2(const unsigned int v)
398 static const char LogTable256[] = {
399 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
400 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
401 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
402 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
403 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
404 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
405 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
406 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
407 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
408 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
409 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
410 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
411 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
412 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
413 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
414 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
416 int r = -1; // r will be lg(v)
417 unsigned int t, tt; // temporaries
420 r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
422 r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
428 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
430 std::string singular = (wordForSingular ? wordForSingular : "entry");
431 std::string plural = (wordForPlural ? wordForPlural : "entries");
433 if(wordForSingular && !wordForPlural)
434 plural = singular + "s";
436 result += ((number != 0) ? anna::functions::asString(number) : "no");
438 result += ((number != 1) ? plural : singular);
443 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
445 int d_size = title.size();
446 int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
449 if(mode == TextJustifyMode::Center) {
450 repeat = (repeat - 1) / 2;
451 adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
454 if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
455 for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
462 if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
465 for(int k = 0; k < repeat; k++) result += filler;
472 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
474 int ou_repeat = title.size();
475 int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
478 if(mode == TextHighlightMode::LeftAndRightline) {
479 lr_repeat = (lr_repeat - 1) / 2;
480 adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
483 if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
484 for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
489 if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
490 for(int k = 0; k < ou_repeat; k++) result += filler;
497 if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
500 for(int k = 0; k < ou_repeat; k++) result += filler;
503 if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
506 for(int k = 0; k < lr_repeat; k++) result += filler;
509 if(appendCR) result += "\n";
515 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
517 size_t pos, from = 0;
518 std::string tab, crTab = "\n";
520 for(int k = 0; k < tabSpaces; k++) tab += " ";
526 while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
527 result.replace(pos, 1, crTab);
535 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
538 if(pattern.size() < suffix.size()) return false;
540 size_t pos = pattern.rfind(suffix);
542 if(pos == std::string::npos) return false;
544 preffix.assign(pattern.c_str(), pos);
545 return (pos == (pattern.size() - suffix.size()));
549 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
552 if(pattern.size() < preffix.size()) return false;
554 if(pattern.find(preffix) != 0) return false;
556 suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
561 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
562 std::string result = text;
564 if(!item || !target) return result; // protection for NULL strings provided
566 size_t lengthReplaced = strlen(item);
567 size_t pos = result.find(item);
569 while(pos != std::string::npos) {
570 result.replace(pos, lengthReplaced, target);
574 pos = result.find(item);
581 std::string functions::addQuotationMarks(const std::string & str) throw() {
582 std::string result = "'";
589 std::string functions::addQuotationMarks(const char * str) throw() {
590 std::string result = "'";
591 result += (str ? str : "<null>");
597 std::string functions::addQuotationMarks(const int & integer) throw() {
598 std::string result = "'";
599 result += anna::functions::asString(integer);
605 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
606 std::string result = "";
609 std::vector<int>::const_iterator iter;
610 std::vector<int>::const_iterator iter_min(v.begin());
611 std::vector<int>::const_iterator iter_max(v.end());
613 for(iter = iter_min; iter != iter_max; iter++) {
614 result += anna::functions::asString(*iter);
618 // Delete the last space: starts at 'size()-1', take 1 caracter:
619 result.erase(result.size() - 1, 1);
626 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
627 std::string result = "";
630 std::vector<std::string>::const_iterator iter;
631 std::vector<std::string>::const_iterator iter_min(v.begin());
632 std::vector<std::string>::const_iterator iter_max(v.end());
634 for(iter = iter_min; iter != iter_max; iter++) {
639 // Delete the last space: starts at 'size()-1', take 1 caracter:
640 result.erase(result.size() - 1, 1);
647 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
648 std::string result = address;
650 result += anna::functions::asString(port);
655 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
657 // Supposed printable by default:
658 isFullyPrintable = true;
660 if(size == 0 || !buffer) {
662 isFullyPrintable = false;
666 for(int k = 0; k < size; k ++) {
667 unsigned char c = (unsigned char) buffer [k];
668 int printable = isprint(c);
669 result += (printable ? (char) c : '.');
671 if(!printable) isFullyPrintable = false;
678 std::string functions::getHostname() throw() {
680 std::string result = "<hostname>";
682 if(gethostname(aux, sizeof aux) == 0 /*success*/)
688 std::string functions::getDomainname() throw() {
690 std::string result = "<domainname>";
692 if(getdomainname(aux, sizeof aux) == 0 /*success*/)
698 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
699 std::string hn = hostname ? hostname : (functions::getHostname());
700 std::string dn = domainname ? domainname : (functions::getDomainname());
701 // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
703 if(hn == "") return dn;
705 if(dn == "") return hn;
707 std::string label(hn, 0, 63);
708 std::string fqdn(label + "." + dn, 0, 255);
712 std::string functions::getHostnameIP() throw() {
713 std::string result = "";
715 struct in_addr **addr_list;
716 struct in_addr ipv4addr;
718 gethostname(hostname, sizeof hostname);
720 if((he = gethostbyname(hostname)) != NULL) {
721 // Official name: he->h_name
723 addr_list = (struct in_addr **)he->h_addr_list;
725 for(int i = 0; addr_list[i] != NULL; i++) {
726 //printf("%s ", inet_ntoa(*addr_list[i]));
727 result = inet_ntoa(*addr_list[i]);
736 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
737 int length = rawPresentation.size();
739 if(length != 8 && length != 32)
740 throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
742 anna::DataBlock result(true);
744 char rByte[3]; // readable byte
747 for(int k = 0; k < length; k += 2) {
748 rByte[0] = rawPresentation[k];
749 rByte[1] = rawPresentation[k + 1];
750 sscanf(rByte, "%x", &byte);
758 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
759 int length = db.getSize();
761 if(length != 4 && length != 16)
762 throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
764 std::string result = "";
766 char rByte[3]; // readable byte
769 for(int k = 0; k < length; k++) {
770 byte = (unsigned char)db[k];
771 sprintf(rByte, "%.2X", byte);
783 // 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:
784 // A typical example of an IPv6 address is
785 // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
786 // The hexadecimal digits are case-insensitive.
788 // The 128-bit IPv6 address can be abbreviated with the following rules:
789 // -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
790 // -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
791 // 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.
793 // 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.
794 // AsÃ, las siguientes son representaciones posibles de una misma dirección:
796 // 2001:0DB8:0000:0000:0000:0000:1428:57ab
797 // 2001:0DB8:0000:0000:0000::1428:57ab
798 // 2001:0DB8:0:0:0:0:1428:57ab
799 // 2001:0DB8:0::0:1428:57ab
800 // 2001:0DB8::1428:57ab
801 // son todas válidas y significan lo mismo, pero
804 // no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
806 // Los ceros iniciales en un grupo también se pueden omitir:
807 // 2001:0DB8:02de::0e13
810 // Si la dirección es una dirección IPv4 empotrada (mapped), los últimos 32 bits pueden escribirse en base decimal, asÃ:
811 // ::ffff:192.168.89.9
814 // No se debe confundir con:
818 // El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
819 // Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
820 // (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
821 // 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
822 // casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
824 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
826 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
827 if(ipv4Type == IPv4Type::Estrict) {
828 // La expresión regular no controla si hay mas de 3 puntos:
831 for(int k = 0; k < ip.length(); k++)
832 if(ip[k] == '.') n_dot++;
837 bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
838 bool colon = (ip.find(":") != std::string::npos);
839 return (ipv4 && !colon);
842 if(ipv4Type == IPv4Type::Compatible) {
843 std::string pureIPv4 = ip;
844 bool firstDoubleColon = (ip.find("::") == 0);
846 if(firstDoubleColon) {
847 pureIPv4.erase(0, 2);
848 bool anotherColon = (pureIPv4.find(":") != std::string::npos);
850 if(anotherColon) return (false);
852 return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
856 if(ipv4Type == IPv4Type::Mapped) {
857 size_t posLastColon = ip.rfind(":");
859 if(posLastColon == std::string::npos)
862 if(!isIPv4(ip.substr(posLastColon + 1)))
865 unsigned char buf[sizeof(struct in6_addr)];
866 int s = inet_pton(AF_INET6, ip.c_str(), buf);
876 bool functions::isIPv6(const std::string & ip) throw() {
877 // Chequeo de digitos permitidos:
878 for(int k = 0; k < ip.length(); k++) {
879 bool digit = isdigit(ip[k]);
880 bool hex = ((ip[k] == 'a') ||
892 bool colon = (ip[k] == ':');
894 if(!digit && !hex && !colon)
898 return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
902 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
903 if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
904 throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
906 std::string result, pureIPv4;
907 bool firstDoubleColon = (ip.find("::") == 0);
909 if(firstDoubleColon) {
911 size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
912 pureIPv4 = ip.substr(ipv4_pos);
915 size_t posColon = ip.find(":");
917 if(posColon == 0) // first colon
918 throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
920 if(posColon != std::string::npos) // any colon
921 return ip; // seems to be IPv6 already?
923 throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
929 // Number of ocurrences for '.'
932 for(int k = 0; k < pureIPv4.length(); k++)
933 if(pureIPv4[k] == '.') n_dot++;
936 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
939 anna::Tokenizer::const_iterator tok_it;
941 tok.apply(pureIPv4, ".");
945 for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
946 token = anna::Tokenizer::data(tok_it);
947 v[cnt] = atoi(anna::Tokenizer::data(tok_it));
949 if(v[cnt] < 0 || v[cnt] > 255)
950 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
955 if(isIPv4(ip, IPv4Type::Compatible))
956 result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
958 result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
964 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
965 std::string result = ip;
966 // std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
967 std::transform(result.begin(), result.end(), result.begin(), ::tolower);
969 if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
970 result = IPv4To6(result);
972 size_t pos = result.find("::"); // zeroes simplification group
973 size_t rpos = result.rfind("::"); // zeroes simplification group
976 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
978 if(pos != std::string::npos) { // zeroes exists
979 // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
980 // Number of ocurrences for ':'
983 for(int k = 0; k < result.length(); k++)
984 if(result[k] == ':') n_colon++;
986 // Generate equivalent to '::'
987 std::string equiv_str;
989 for(int k = 0; k < (8 - n_colon); k++)
993 // Replace with equivalent:
994 result.replace(pos, 2, equiv_str);
996 // Special case: IP began with '::'
997 if(result[0] == ':') {
998 result.insert(0, "0");
1001 // Special case: IP was only '::'
1002 if(result[result.length() - 1] == ':') {
1007 // Protection: it must be seven colons:
1010 for(int k = 0; k < result.length(); k++)
1011 if(result[k] == ':') n_colon++;
1014 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1016 // Padding with zeroes at left
1017 anna::Tokenizer ipStr;
1018 anna::Tokenizer::const_iterator ipStr_it;
1020 ipStr.apply(result, ":");
1023 for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1024 token = anna::Tokenizer::data(ipStr_it);
1026 while(token.length() < 4) token.insert(0, "0");
1033 size_t lastPos = result.length() - 1;
1034 result.erase(lastPos, 1);
1036 // Chequeo de digitos permitidos:
1037 for(int k = 0; k < result.length(); k++) {
1038 bool digit = isdigit(result[k]);
1039 bool hex = ((result[k] == 'a') ||
1040 (result[k] == 'b') ||
1041 (result[k] == 'c') ||
1042 (result[k] == 'd') ||
1043 (result[k] == 'e') ||
1044 (result[k] == 'f'));
1045 bool colon = (result[k] == ':');
1047 if(!digit && !hex && !colon) {
1048 throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1056 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1057 //if (ip1 == ip2) return true; it should validate wrong-format addresses
1058 return (normalizeIP(ip1) == normalizeIP(ip2));
1062 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1063 size_t preffixPos = preffixedIpv6.find("/");
1065 if(preffixPos == std::string::npos)
1066 return (sameIP(_ipv6, preffixedIpv6));
1068 std::string ipv6 = _ipv6;
1070 if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1072 std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1073 std::string ipv6_2 = _ipv6_2;
1075 if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1077 std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1078 int ipv6_2_preffixLength = atoi(preffix.c_str());
1080 if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1081 throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1083 // No restriction, all ipv6_2 ignored (special and not usual case)
1084 if(ipv6_2_preffixLength == 0) return true;
1087 int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1088 int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1089 int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1090 char mask = 0xFF << (8 - spare);
1092 anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1093 anna::DataBlock restrictedIP1(true);
1094 restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1096 if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1099 anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1100 anna::DataBlock realIP2(true);
1101 realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1103 if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1106 int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1111 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1112 anna::DataBlock result(true);
1115 unsigned char buf[sizeof(struct in6_addr)];
1116 int s = inet_pton(AF_INET, ip.c_str(), buf);
1119 result += (S8)buf[0];
1120 result += (S8)buf[1];
1121 result += (S8)buf[2];
1122 result += (S8)buf[3];
1124 if(s < 0) perror("inet_pton");
1126 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1129 unsigned char buf[sizeof(struct in6_addr)];
1130 int s = inet_pton(AF_INET6, ip.c_str(), buf);
1133 result += (S8)buf[0];
1134 result += (S8)buf[1];
1135 result += (S8)buf[2];
1136 result += (S8)buf[3];
1137 result += (S8)buf[4];
1138 result += (S8)buf[5];
1139 result += (S8)buf[6];
1140 result += (S8)buf[7];
1141 result += (S8)buf[8];
1142 result += (S8)buf[9];
1143 result += (S8)buf[10];
1144 result += (S8)buf[11];
1145 result += (S8)buf[12];
1146 result += (S8)buf[13];
1147 result += (S8)buf[14];
1148 result += (S8)buf[15];
1150 if(s < 0) perror("inet_pton");
1152 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1158 // anna::DataBlock result(true);
1161 // if (isIPv4(ip)) {
1163 // 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/)
1164 // sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1165 // result += (S8)dec1;
1166 // result += (S8)dec2;
1167 // result += (S8)dec3;
1168 // result += (S8)dec4;
1172 // 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/)
1173 // sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1174 // result += ((S8)(hex1 >> 8));
1175 // result += ((S8)(hex1 & 0x00FF));
1176 // result += ((S8)(hex2 >> 8));
1177 // result += ((S8)(hex2 & 0x00FF));
1178 // result += ((S8)(hex3 >> 8));
1179 // result += ((S8)(hex3 & 0x00FF));
1180 // result += ((S8)(hex4 >> 8));
1181 // result += ((S8)(hex4 & 0x00FF));
1182 // result += ((S8)(hex5 >> 8));
1183 // result += ((S8)(hex5 & 0x00FF));
1184 // result += ((S8)(hex6 >> 8));
1185 // result += ((S8)(hex6 & 0x00FF));
1186 // result += ((S8)(hex7 >> 8));
1187 // result += ((S8)(hex7 & 0x00FF));
1188 // result += ((S8)(hex8 >> 8));
1189 // result += ((S8)(hex8 & 0x00FF));
1197 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1198 std::string result = "";
1199 char str[INET6_ADDRSTRLEN];
1201 if(bufferLength == 4) {
1202 if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1204 } else if(bufferLength == 16) {
1205 if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1208 throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1211 throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1213 return (normalize ? normalizeIP(result) : result);
1215 // std::string result;
1218 // if (bufferLength == 4) { // IPv4
1219 // result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1221 // else if (bufferLength == 16) { // IPv6
1222 // result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1223 // ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1224 // (((U8)buffer[1]) & 0x00FF),
1225 // ((((U8)buffer[2]) << 8) & 0xFF00) +
1226 // (((U8)buffer[3]) & 0x00FF),
1227 // ((((U8)buffer[4]) << 8) & 0xFF00) +
1228 // (((U8)buffer[5]) & 0x00FF),
1229 // ((((U8)buffer[6]) << 8) & 0xFF00) +
1230 // (((U8)buffer[7]) & 0x00FF),
1231 // ((((U8)buffer[8]) << 8) & 0xFF00) +
1232 // (((U8)buffer[9]) & 0x00FF),
1233 // ((((U8)buffer[10]) << 8) & 0xFF00) +
1234 // (((U8)buffer[11]) & 0x00FF),
1235 // ((((U8)buffer[12]) << 8) & 0xFF00) +
1236 // (((U8)buffer[13]) & 0x00FF),
1237 // ((((U8)buffer[14]) << 8) & 0xFF00) +
1238 // (((U8)buffer[15]) & 0x00FF));
1241 // throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1244 // return (normalize ? normalizeIP(result):result);
1248 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1249 size_t pos = literal.find_last_of(":");
1250 size_t lastPos = literal.size() - 1;
1251 address = ""; port = -1; // assume error
1253 if((pos != std::string::npos) && (pos != lastPos)) {
1254 address = literal.substr(0, pos);
1255 port = atoi(literal.substr(pos + 1, lastPos).c_str());
1260 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1262 std::string address;
1264 anna::Tokenizer lst;
1265 lst.apply(list, ",");
1267 if(lst.size() < 1) return result;
1269 anna::Tokenizer::const_iterator tok_min(lst.begin());
1270 anna::Tokenizer::const_iterator tok_max(lst.end());
1271 anna::Tokenizer::const_iterator tok_iter;
1273 for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1274 getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1276 if(port == -1) { result.clear(); return result; }
1278 result.push_back(socket_t(address, port));
1284 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1287 socket_v_it it_min(socketVector.begin());
1288 socket_v_it it_max(socketVector.end());
1290 for(it = it_min; it != it_max; it++) {
1291 result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1294 result.erase(result.size() - 1, 1); // remove last comma
1298 bool functions::littleEndian()
1301 char *p = (char *) &i;
1302 if (p[0] == 1) return true;
1306 const char* functions::codeInteger(char* result, const int n)
1309 char* w((char*) &aux);
1311 *(result + 1) = *(w + 1);
1312 *(result + 2) = *(w + 2);
1313 *(result + 3) = *(w + 3);
1317 const char* functions::codeShort(char* result, const short int n)
1319 short int aux(htons(n));
1320 char* w((char*) &aux);
1322 *(result + 1) = *(w + 1);
1326 const char* functions::codeInteger64(char* result, const S64 n)
1328 S64 aux(0xffffffff);
1332 n2 = (aux >> 32) & 0xffffffff;
1333 codeInteger(result, n2);
1334 n2 = n & 0xffffffff;
1335 codeInteger(result + sizeof(int), n2);
1340 const char* functions::codeFloat(char* result, const float n)
1343 anna_memcpy(&ii, &n, sizeof(n));
1344 return functions::codeInteger(result, ii);
1348 const char* functions::codeDouble(char* result, const double n)
1351 anna_memcpy(&ii, &n, sizeof(n));
1352 return functions::codeInteger64(result, ii);
1355 int functions::decodeInteger(const char* data)
1358 char* w((char*) &result);
1360 *(w + 1) = *(data + 1);
1361 *(w + 2) = *(data + 2);
1362 *(w + 3) = *(data + 3);
1363 return ntohl(result);
1366 short int functions::decodeShort(const char* data)
1369 char* w((char*) &result);
1371 *(w + 1) = *(data + 1);
1372 return ntohs(result);
1375 S64 functions::decodeInteger64(const char* data)
1377 S64 result(decodeInteger(data));
1379 return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1383 float functions::decodeFloat(const char* data)
1386 int ii = functions::decodeInteger(data);
1387 anna_memcpy(&result, &ii, sizeof(result));
1392 double functions::decodeDouble(const char* data)
1395 S64 ii = functions::decodeInteger64(data);
1396 anna_memcpy(&result, &ii, sizeof(result));
1402 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1403 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1405 isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1406 bool filler = isupNumber.OddEven;
1408 if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1409 throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1411 isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1412 isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1414 if(calledOrCalling) {
1415 isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1417 isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1418 isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1419 isupNumber.Screening = (short)(buffer[1] & 0x03);
1423 isupNumber.Digits = "";
1426 for(int k = 2; k < length; k ++) {
1427 byte = (buffer [k] & 0x0f);
1428 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1429 byte = (buffer [k] & 0xf0) >> 4;
1430 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1433 if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler
1437 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1439 if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1440 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1442 bool odd = isupNumber.OddEven;
1443 bool oddDigits = (isupNumber.Digits.size() % 2);
1445 if(odd != oddDigits)
1446 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1448 if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1449 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1451 if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1452 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1454 if(calledOrCalling) {
1455 if(isupNumber.NumberIncomplete != 0)
1456 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1458 if(isupNumber.AddressPresentationRestricted != 0)
1459 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1461 if(isupNumber.Screening != 0)
1462 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1464 if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1465 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1467 if(isupNumber.InternalNetworkNumber != 0)
1468 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1470 if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1471 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1473 if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1474 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1476 if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1477 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1482 bool filler = isupNumber.OddEven;
1483 bool hasDigits = (isupNumber.Digits.size() > 0);
1484 byte = filler ? 0x80 : 0x00;
1485 byte = byte |= isupNumber.NatureOfAddress;
1488 if(calledOrCalling) {
1489 byte = isupNumber.InternalNetworkNumber << 7;
1490 byte = byte |= (isupNumber.NumberingPlan << 4);
1492 byte = isupNumber.NumberIncomplete << 7;
1493 byte = byte |= (isupNumber.NumberingPlan << 4);
1494 byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1495 byte = byte |= isupNumber.Screening;
1501 std::string dtlc = isupNumber.Digits; // digits to lower case
1502 //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1503 const char *digits = dtlc.c_str();
1505 for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1506 if(isxdigit(byte = digits [k - 1]) == 0)
1507 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1509 hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1511 if(isxdigit(byte = digits [k]) == 0)
1512 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1514 hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1518 if(hasDigits && filler) {
1519 if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1520 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1522 target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1527 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1529 codeIsupNumber(isupNumber, calledOrCalling, target);
1530 length = target.size();
1531 memcpy(buffer, target.c_str(), length);