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 unsigned long number)
96 return asString((U64)number);
99 string functions::asString(const S64 number)
102 sprintf(aux, "%lld", number);
104 sprintf (aux, "%ld", number);
106 sprintf (aux, "%lld", number);
112 string functions::asString(const unsigned int number)
115 sprintf(aux, "%u", number);
119 string functions::asString(const U64 number)
122 sprintf(aux, "%llu", number);
125 sprintf (aux, "%lu", number);
127 sprintf (aux, "%llu", number);
133 string functions::asString(const float number, const char* format)
136 sprintf(aux, format, number);
140 string functions::asString(const double number, const char* format)
143 sprintf(aux, format, number);
147 string functions::asDateTime(const Second &second)
149 char aux [DateTimeSizeString];
150 return std::string(asDateTime(second, aux));
153 const char* functions::asDateTime(const Second &second, char* result)
155 struct tm* tt = localtime((time_t*) & second);
157 result, "%02d/%02d/%4d %02d:%02d:%02d",
158 tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900,
159 tt->tm_hour, tt->tm_min, tt->tm_sec
164 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
166 return dataBlock.asString(characterByLine);
169 string functions::asHexString(const int number)
172 sprintf(aux, "0x%x", number);
176 string functions::asHexString(const long number)
178 return asHexString((S64)number);
181 string functions::asHexString(const S64 number)
184 sprintf(aux, "0x%llx", number);
187 sprintf (aux, "0x%lx", number);
189 sprintf (aux, "0x%llx", number);
195 // from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited"
196 // Dr. Dobb's Journal, April 1996)
197 S64 functions::hash(const char* p)
199 static const int long_bits = sizeof(S64) << 3;
200 static const int one_eighth = long_bits >> 3;
201 static const int three_fourths = long_bits * 3 / 4;
202 static const S64 high_bits = ((S64)(~0L)) << (long_bits - one_eighth);
207 result = (result << one_eighth) + *p ++;
209 if((temp = result & high_bits) != 0)
210 result = (result ^(temp >> three_fourths)) &~ high_bits;
217 std::string functions::asHexString(const DataBlock& dataBlock)
219 const char* buffer = dataBlock.getData();
220 const int size = dataBlock.getSize();
224 for(int ii = 0; ii < size; ii ++) {
225 byte = (buffer [ii] & 0xf0) >> 4;
226 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
227 byte = (buffer [ii] & 0x0f);
228 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
235 * Gets the original value obtained with #asHexString (const DataBlock&).
236 * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
237 * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
238 * \param target DataBlock for string decode.
239 * \return DataBlock corresponding to the provided string.
242 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
243 throw(RuntimeException) {
245 if((hexString.length() % 2) != 0)
246 throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
249 const char* src = hexString.data();
254 for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
255 if(isxdigit(aux = src [ii - 1]) == 0)
256 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
258 hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
260 if(isxdigit(aux = src [ii]) == 0)
261 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
263 hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
270 string functions::asString(const char* format, ...)
274 va_start(ap, format);
275 vsnprintf(aux, sizeof(aux), format, ap);
280 void functions::sleep(const Millisecond &millisecond)
284 req.tv_sec = millisecond.getValue() / 1000; // segundos
285 req.tv_nsec = (millisecond.getValue() % 1000); // milisegundos
286 req.tv_nsec *= 1000000; // mili = 10e-3, nano=10-9
289 while((r = nanosleep(&req, &rem)) != 0) {
293 string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
294 msg += functions::asText("| nsec: ", (int) req.tv_nsec);
296 RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
303 bool functions::asBool(const char* str)
304 throw(RuntimeException) {
308 if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
311 if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
314 string msg("anna::funcions::asBool | Cannot interpret '");
316 msg += "' as boolean";
317 throw RuntimeException(msg, ANNA_FILE_LOCATION);
320 S64 functions::asInteger64(const char* str)
323 sscanf(str, "%lld", &number);
326 sscanf (str, "%ld", &number);
328 sscanf (str, "%lld", &number);
334 pthread_t functions::getCurrentThread()
336 WHEN_MULTITHREAD(return pthread_self());
337 WHEN_SINGLETHREAD(return 0);
340 bool functions::isLike(const char* pattern, const std::string& _value)
341 throw(RuntimeException) {
342 const char* value = _value.c_str();
346 if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
348 string msg("anna::functions::isLike | ");
349 msg += " | Pattern: ";
355 if(regerror(ret, &preg, err, sizeof(err)))
358 msg += "Invalid pattern";
360 throw RuntimeException(msg, ANNA_FILE_LOCATION);
363 const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
370 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
371 throw(RuntimeException) {
372 if(bitShift > intBitSize) {
373 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
374 throw RuntimeException(msg, ANNA_FILE_LOCATION);
377 if((bitsize(n1) + bitShift) > int64BitSize) {
378 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
379 throw RuntimeException(msg, ANNA_FILE_LOCATION);
382 if(bitsize(n2) > bitShift) {
383 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
384 throw RuntimeException(msg, ANNA_FILE_LOCATION);
391 if(bitShift == intBitSize) {
393 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
394 msg += functions::asHexString(result);
395 Logger::information(msg, ANNA_FILE_LOCATION);
404 * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
406 int functions::log2(const unsigned int v)
408 static const char LogTable256[] = {
409 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
410 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
411 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
412 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
413 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
414 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
415 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
416 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
417 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
418 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
419 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
420 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
421 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
422 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
423 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
424 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
426 int r = -1; // r will be lg(v)
427 unsigned int t, tt; // temporaries
430 r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
432 r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
438 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
440 std::string singular = (wordForSingular ? wordForSingular : "entry");
441 std::string plural = (wordForPlural ? wordForPlural : "entries");
443 if(wordForSingular && !wordForPlural)
444 plural = singular + "s";
446 result += ((number != 0) ? anna::functions::asString(number) : "no");
448 result += ((number != 1) ? plural : singular);
453 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
455 int d_size = title.size();
456 int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
459 if(mode == TextJustifyMode::Center) {
460 repeat = (repeat - 1) / 2;
461 adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
464 if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
465 for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
472 if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
475 for(int k = 0; k < repeat; k++) result += filler;
482 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
484 int ou_repeat = title.size();
485 int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
488 if(mode == TextHighlightMode::LeftAndRightline) {
489 lr_repeat = (lr_repeat - 1) / 2;
490 adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
493 if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
494 for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
499 if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
500 for(int k = 0; k < ou_repeat; k++) result += filler;
507 if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
510 for(int k = 0; k < ou_repeat; k++) result += filler;
513 if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
516 for(int k = 0; k < lr_repeat; k++) result += filler;
519 if(appendCR) result += "\n";
525 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
527 size_t pos, from = 0;
528 std::string tab, crTab = "\n";
530 for(int k = 0; k < tabSpaces; k++) tab += " ";
536 while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
537 result.replace(pos, 1, crTab);
545 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
548 if(pattern.size() < suffix.size()) return false;
550 size_t pos = pattern.rfind(suffix);
552 if(pos == std::string::npos) return false;
554 preffix.assign(pattern.c_str(), pos);
555 return (pos == (pattern.size() - suffix.size()));
559 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
562 if(pattern.size() < preffix.size()) return false;
564 if(pattern.find(preffix) != 0) return false;
566 suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
571 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
572 std::string result = text;
574 if(!item || !target) return result; // protection for NULL strings provided
576 size_t lengthReplaced = strlen(item);
577 size_t pos = result.find(item);
579 while(pos != std::string::npos) {
580 result.replace(pos, lengthReplaced, target);
584 pos = result.find(item);
591 std::string functions::addQuotationMarks(const std::string & str) throw() {
592 std::string result = "'";
599 std::string functions::addQuotationMarks(const char * str) throw() {
600 std::string result = "'";
601 result += (str ? str : "<null>");
607 std::string functions::addQuotationMarks(const int & integer) throw() {
608 std::string result = "'";
609 result += anna::functions::asString(integer);
615 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
616 std::string result = "";
619 std::vector<int>::const_iterator iter;
620 std::vector<int>::const_iterator iter_min(v.begin());
621 std::vector<int>::const_iterator iter_max(v.end());
623 for(iter = iter_min; iter != iter_max; iter++) {
624 result += anna::functions::asString(*iter);
628 // Delete the last space: starts at 'size()-1', take 1 caracter:
629 result.erase(result.size() - 1, 1);
636 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
637 std::string result = "";
640 std::vector<std::string>::const_iterator iter;
641 std::vector<std::string>::const_iterator iter_min(v.begin());
642 std::vector<std::string>::const_iterator iter_max(v.end());
644 for(iter = iter_min; iter != iter_max; iter++) {
649 // Delete the last space: starts at 'size()-1', take 1 caracter:
650 result.erase(result.size() - 1, 1);
657 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
658 std::string result = address;
660 result += anna::functions::asString(port);
665 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
667 // Supposed printable by default:
668 isFullyPrintable = true;
670 if(size == 0 || !buffer) {
672 isFullyPrintable = false;
676 for(int k = 0; k < size; k ++) {
677 unsigned char c = (unsigned char) buffer [k];
678 int printable = isprint(c);
679 result += (printable ? (char) c : '.');
681 if(!printable) isFullyPrintable = false;
688 std::string functions::getHostname() throw() {
690 std::string result = "<hostname>";
692 if(gethostname(aux, sizeof aux) == 0 /*success*/)
698 std::string functions::getDomainname() throw() {
700 std::string result = "<domainname>";
702 if(getdomainname(aux, sizeof aux) == 0 /*success*/)
708 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
709 std::string hn = hostname ? hostname : (functions::getHostname());
710 std::string dn = domainname ? domainname : (functions::getDomainname());
711 // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
713 if(hn == "") return dn;
715 if(dn == "") return hn;
717 std::string label(hn, 0, 63);
718 std::string fqdn(label + "." + dn, 0, 255);
722 std::string functions::getHostnameIP() throw() {
723 std::string result = "";
725 struct in_addr **addr_list;
726 struct in_addr ipv4addr;
728 gethostname(hostname, sizeof hostname);
730 if((he = gethostbyname(hostname)) != NULL) {
731 // Official name: he->h_name
733 addr_list = (struct in_addr **)he->h_addr_list;
735 for(int i = 0; addr_list[i] != NULL; i++) {
736 //printf("%s ", inet_ntoa(*addr_list[i]));
737 result = inet_ntoa(*addr_list[i]);
746 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
747 int length = rawPresentation.size();
749 if(length != 8 && length != 32)
750 throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
752 anna::DataBlock result(true);
754 char rByte[3]; // readable byte
757 for(int k = 0; k < length; k += 2) {
758 rByte[0] = rawPresentation[k];
759 rByte[1] = rawPresentation[k + 1];
760 sscanf(rByte, "%x", &byte);
768 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
769 int length = db.getSize();
771 if(length != 4 && length != 16)
772 throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
774 std::string result = "";
776 char rByte[3]; // readable byte
779 for(int k = 0; k < length; k++) {
780 byte = (unsigned char)db[k];
781 sprintf(rByte, "%.2X", byte);
793 // 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:
794 // A typical example of an IPv6 address is
795 // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
796 // The hexadecimal digits are case-insensitive.
798 // The 128-bit IPv6 address can be abbreviated with the following rules:
799 // -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
800 // -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
801 // 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.
803 // 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.
804 // AsÃ, las siguientes son representaciones posibles de una misma dirección:
806 // 2001:0DB8:0000:0000:0000:0000:1428:57ab
807 // 2001:0DB8:0000:0000:0000::1428:57ab
808 // 2001:0DB8:0:0:0:0:1428:57ab
809 // 2001:0DB8:0::0:1428:57ab
810 // 2001:0DB8::1428:57ab
811 // son todas válidas y significan lo mismo, pero
814 // no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
816 // Los ceros iniciales en un grupo también se pueden omitir:
817 // 2001:0DB8:02de::0e13
820 // Si la dirección es una dirección IPv4 empotrada (mapped), los últimos 32 bits pueden escribirse en base decimal, asÃ:
821 // ::ffff:192.168.89.9
824 // No se debe confundir con:
828 // El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
829 // Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
830 // (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
831 // 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
832 // casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
834 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
836 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
837 if(ipv4Type == IPv4Type::Estrict) {
838 // La expresión regular no controla si hay mas de 3 puntos:
841 for(int k = 0; k < ip.length(); k++)
842 if(ip[k] == '.') n_dot++;
847 bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
848 bool colon = (ip.find(":") != std::string::npos);
849 return (ipv4 && !colon);
852 if(ipv4Type == IPv4Type::Compatible) {
853 std::string pureIPv4 = ip;
854 bool firstDoubleColon = (ip.find("::") == 0);
856 if(firstDoubleColon) {
857 pureIPv4.erase(0, 2);
858 bool anotherColon = (pureIPv4.find(":") != std::string::npos);
860 if(anotherColon) return (false);
862 return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
866 if(ipv4Type == IPv4Type::Mapped) {
867 size_t posLastColon = ip.rfind(":");
869 if(posLastColon == std::string::npos)
872 if(!isIPv4(ip.substr(posLastColon + 1)))
875 unsigned char buf[sizeof(struct in6_addr)];
876 int s = inet_pton(AF_INET6, ip.c_str(), buf);
886 bool functions::isIPv6(const std::string & ip) throw() {
887 // Chequeo de digitos permitidos:
888 for(int k = 0; k < ip.length(); k++) {
889 bool digit = isdigit(ip[k]);
890 bool hex = ((ip[k] == 'a') ||
902 bool colon = (ip[k] == ':');
904 if(!digit && !hex && !colon)
908 return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
912 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
913 if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
914 throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
916 std::string result, pureIPv4;
917 bool firstDoubleColon = (ip.find("::") == 0);
919 if(firstDoubleColon) {
921 size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
922 pureIPv4 = ip.substr(ipv4_pos);
925 size_t posColon = ip.find(":");
927 if(posColon == 0) // first colon
928 throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
930 if(posColon != std::string::npos) // any colon
931 return ip; // seems to be IPv6 already?
933 throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
939 // Number of ocurrences for '.'
942 for(int k = 0; k < pureIPv4.length(); k++)
943 if(pureIPv4[k] == '.') n_dot++;
946 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
949 anna::Tokenizer::const_iterator tok_it;
951 tok.apply(pureIPv4, ".");
955 for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
956 token = anna::Tokenizer::data(tok_it);
957 v[cnt] = atoi(anna::Tokenizer::data(tok_it));
959 if(v[cnt] < 0 || v[cnt] > 255)
960 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
965 if(isIPv4(ip, IPv4Type::Compatible))
966 result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
968 result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
974 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
975 std::string result = ip;
976 // std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
977 std::transform(result.begin(), result.end(), result.begin(), ::tolower);
979 if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
980 result = IPv4To6(result);
982 size_t pos = result.find("::"); // zeroes simplification group
983 size_t rpos = result.rfind("::"); // zeroes simplification group
986 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
988 if(pos != std::string::npos) { // zeroes exists
989 // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
990 // Number of ocurrences for ':'
993 for(int k = 0; k < result.length(); k++)
994 if(result[k] == ':') n_colon++;
996 // Generate equivalent to '::'
997 std::string equiv_str;
999 for(int k = 0; k < (8 - n_colon); k++)
1003 // Replace with equivalent:
1004 result.replace(pos, 2, equiv_str);
1006 // Special case: IP began with '::'
1007 if(result[0] == ':') {
1008 result.insert(0, "0");
1011 // Special case: IP was only '::'
1012 if(result[result.length() - 1] == ':') {
1017 // Protection: it must be seven colons:
1020 for(int k = 0; k < result.length(); k++)
1021 if(result[k] == ':') n_colon++;
1024 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1026 // Padding with zeroes at left
1027 anna::Tokenizer ipStr;
1028 anna::Tokenizer::const_iterator ipStr_it;
1030 ipStr.apply(result, ":");
1033 for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1034 token = anna::Tokenizer::data(ipStr_it);
1036 while(token.length() < 4) token.insert(0, "0");
1043 size_t lastPos = result.length() - 1;
1044 result.erase(lastPos, 1);
1046 // Chequeo de digitos permitidos:
1047 for(int k = 0; k < result.length(); k++) {
1048 bool digit = isdigit(result[k]);
1049 bool hex = ((result[k] == 'a') ||
1050 (result[k] == 'b') ||
1051 (result[k] == 'c') ||
1052 (result[k] == 'd') ||
1053 (result[k] == 'e') ||
1054 (result[k] == 'f'));
1055 bool colon = (result[k] == ':');
1057 if(!digit && !hex && !colon) {
1058 throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1066 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1067 //if (ip1 == ip2) return true; it should validate wrong-format addresses
1068 return (normalizeIP(ip1) == normalizeIP(ip2));
1072 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1073 size_t preffixPos = preffixedIpv6.find("/");
1075 if(preffixPos == std::string::npos)
1076 return (sameIP(_ipv6, preffixedIpv6));
1078 std::string ipv6 = _ipv6;
1080 if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1082 std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1083 std::string ipv6_2 = _ipv6_2;
1085 if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1087 std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1088 int ipv6_2_preffixLength = atoi(preffix.c_str());
1090 if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1091 throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1093 // No restriction, all ipv6_2 ignored (special and not usual case)
1094 if(ipv6_2_preffixLength == 0) return true;
1097 int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1098 int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1099 int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1100 char mask = 0xFF << (8 - spare);
1102 anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1103 anna::DataBlock restrictedIP1(true);
1104 restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1106 if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1109 anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1110 anna::DataBlock realIP2(true);
1111 realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1113 if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1116 int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1121 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1122 anna::DataBlock result(true);
1125 unsigned char buf[sizeof(struct in6_addr)];
1126 int s = inet_pton(AF_INET, ip.c_str(), buf);
1129 result += (S8)buf[0];
1130 result += (S8)buf[1];
1131 result += (S8)buf[2];
1132 result += (S8)buf[3];
1134 if(s < 0) perror("inet_pton");
1136 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1139 unsigned char buf[sizeof(struct in6_addr)];
1140 int s = inet_pton(AF_INET6, ip.c_str(), buf);
1143 result += (S8)buf[0];
1144 result += (S8)buf[1];
1145 result += (S8)buf[2];
1146 result += (S8)buf[3];
1147 result += (S8)buf[4];
1148 result += (S8)buf[5];
1149 result += (S8)buf[6];
1150 result += (S8)buf[7];
1151 result += (S8)buf[8];
1152 result += (S8)buf[9];
1153 result += (S8)buf[10];
1154 result += (S8)buf[11];
1155 result += (S8)buf[12];
1156 result += (S8)buf[13];
1157 result += (S8)buf[14];
1158 result += (S8)buf[15];
1160 if(s < 0) perror("inet_pton");
1162 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1168 // anna::DataBlock result(true);
1171 // if (isIPv4(ip)) {
1173 // 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/)
1174 // sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1175 // result += (S8)dec1;
1176 // result += (S8)dec2;
1177 // result += (S8)dec3;
1178 // result += (S8)dec4;
1182 // 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/)
1183 // sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1184 // result += ((S8)(hex1 >> 8));
1185 // result += ((S8)(hex1 & 0x00FF));
1186 // result += ((S8)(hex2 >> 8));
1187 // result += ((S8)(hex2 & 0x00FF));
1188 // result += ((S8)(hex3 >> 8));
1189 // result += ((S8)(hex3 & 0x00FF));
1190 // result += ((S8)(hex4 >> 8));
1191 // result += ((S8)(hex4 & 0x00FF));
1192 // result += ((S8)(hex5 >> 8));
1193 // result += ((S8)(hex5 & 0x00FF));
1194 // result += ((S8)(hex6 >> 8));
1195 // result += ((S8)(hex6 & 0x00FF));
1196 // result += ((S8)(hex7 >> 8));
1197 // result += ((S8)(hex7 & 0x00FF));
1198 // result += ((S8)(hex8 >> 8));
1199 // result += ((S8)(hex8 & 0x00FF));
1207 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1208 std::string result = "";
1209 char str[INET6_ADDRSTRLEN];
1211 if(bufferLength == 4) {
1212 if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1214 } else if(bufferLength == 16) {
1215 if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1218 throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1221 throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1223 return (normalize ? normalizeIP(result) : result);
1225 // std::string result;
1228 // if (bufferLength == 4) { // IPv4
1229 // result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1231 // else if (bufferLength == 16) { // IPv6
1232 // result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1233 // ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1234 // (((U8)buffer[1]) & 0x00FF),
1235 // ((((U8)buffer[2]) << 8) & 0xFF00) +
1236 // (((U8)buffer[3]) & 0x00FF),
1237 // ((((U8)buffer[4]) << 8) & 0xFF00) +
1238 // (((U8)buffer[5]) & 0x00FF),
1239 // ((((U8)buffer[6]) << 8) & 0xFF00) +
1240 // (((U8)buffer[7]) & 0x00FF),
1241 // ((((U8)buffer[8]) << 8) & 0xFF00) +
1242 // (((U8)buffer[9]) & 0x00FF),
1243 // ((((U8)buffer[10]) << 8) & 0xFF00) +
1244 // (((U8)buffer[11]) & 0x00FF),
1245 // ((((U8)buffer[12]) << 8) & 0xFF00) +
1246 // (((U8)buffer[13]) & 0x00FF),
1247 // ((((U8)buffer[14]) << 8) & 0xFF00) +
1248 // (((U8)buffer[15]) & 0x00FF));
1251 // throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1254 // return (normalize ? normalizeIP(result):result);
1258 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1259 size_t pos = literal.find_last_of(":");
1260 size_t lastPos = literal.size() - 1;
1261 address = ""; port = -1; // assume error
1263 if((pos != std::string::npos) && (pos != lastPos)) {
1264 address = literal.substr(0, pos);
1265 port = atoi(literal.substr(pos + 1, lastPos).c_str());
1270 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1272 std::string address;
1274 anna::Tokenizer lst;
1275 lst.apply(list, ",");
1277 if(lst.size() < 1) return result;
1279 anna::Tokenizer::const_iterator tok_min(lst.begin());
1280 anna::Tokenizer::const_iterator tok_max(lst.end());
1281 anna::Tokenizer::const_iterator tok_iter;
1283 for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1284 getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1286 if(port == -1) { result.clear(); return result; }
1288 result.push_back(socket_t(address, port));
1294 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1297 socket_v_it it_min(socketVector.begin());
1298 socket_v_it it_max(socketVector.end());
1300 for(it = it_min; it != it_max; it++) {
1301 result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1304 result.erase(result.size() - 1, 1); // remove last comma
1308 bool functions::littleEndian()
1311 char *p = (char *) &i;
1312 if (p[0] == 1) return true;
1316 const char* functions::codeInteger(char* result, const int n)
1319 char* w((char*) &aux);
1321 *(result + 1) = *(w + 1);
1322 *(result + 2) = *(w + 2);
1323 *(result + 3) = *(w + 3);
1327 const char* functions::codeShort(char* result, const short int n)
1329 short int aux(htons(n));
1330 char* w((char*) &aux);
1332 *(result + 1) = *(w + 1);
1336 const char* functions::codeInteger64(char* result, const S64 n)
1338 S64 aux(0xffffffff);
1342 n2 = (aux >> 32) & 0xffffffff;
1343 codeInteger(result, n2);
1344 n2 = n & 0xffffffff;
1345 codeInteger(result + sizeof(int), n2);
1350 const char* functions::codeFloat(char* result, const float n)
1353 anna_memcpy(&ii, &n, sizeof(n));
1354 return functions::codeInteger(result, ii);
1358 const char* functions::codeDouble(char* result, const double n)
1361 anna_memcpy(&ii, &n, sizeof(n));
1362 return functions::codeInteger64(result, ii);
1365 int functions::decodeInteger(const char* data)
1368 char* w((char*) &result);
1370 *(w + 1) = *(data + 1);
1371 *(w + 2) = *(data + 2);
1372 *(w + 3) = *(data + 3);
1373 return ntohl(result);
1376 short int functions::decodeShort(const char* data)
1379 char* w((char*) &result);
1381 *(w + 1) = *(data + 1);
1382 return ntohs(result);
1385 S64 functions::decodeInteger64(const char* data)
1387 S64 result(decodeInteger(data));
1389 return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1393 float functions::decodeFloat(const char* data)
1396 int ii = functions::decodeInteger(data);
1397 anna_memcpy(&result, &ii, sizeof(result));
1402 double functions::decodeDouble(const char* data)
1405 S64 ii = functions::decodeInteger64(data);
1406 anna_memcpy(&result, &ii, sizeof(result));
1412 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1413 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1415 isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1416 bool filler = isupNumber.OddEven;
1418 if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1419 throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1421 isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1422 isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1424 if(calledOrCalling) {
1425 isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1427 isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1428 isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1429 isupNumber.Screening = (short)(buffer[1] & 0x03);
1433 isupNumber.Digits = "";
1436 for(int k = 2; k < length; k ++) {
1437 byte = (buffer [k] & 0x0f);
1438 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1439 byte = (buffer [k] & 0xf0) >> 4;
1440 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1443 if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler
1447 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1449 if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1450 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1452 bool odd = isupNumber.OddEven;
1453 bool oddDigits = (isupNumber.Digits.size() % 2);
1455 if(odd != oddDigits)
1456 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1458 if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1459 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1461 if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1462 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1464 if(calledOrCalling) {
1465 if(isupNumber.NumberIncomplete != 0)
1466 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1468 if(isupNumber.AddressPresentationRestricted != 0)
1469 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1471 if(isupNumber.Screening != 0)
1472 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1474 if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1475 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1477 if(isupNumber.InternalNetworkNumber != 0)
1478 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1480 if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1481 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1483 if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1484 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1486 if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1487 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1492 bool filler = isupNumber.OddEven;
1493 bool hasDigits = (isupNumber.Digits.size() > 0);
1494 byte = filler ? 0x80 : 0x00;
1495 byte = byte |= isupNumber.NatureOfAddress;
1498 if(calledOrCalling) {
1499 byte = isupNumber.InternalNetworkNumber << 7;
1500 byte = byte |= (isupNumber.NumberingPlan << 4);
1502 byte = isupNumber.NumberIncomplete << 7;
1503 byte = byte |= (isupNumber.NumberingPlan << 4);
1504 byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1505 byte = byte |= isupNumber.Screening;
1511 std::string dtlc = isupNumber.Digits; // digits to lower case
1512 //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1513 const char *digits = dtlc.c_str();
1515 for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1516 if(isxdigit(byte = digits [k - 1]) == 0)
1517 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1519 hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1521 if(isxdigit(byte = digits [k]) == 0)
1522 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1524 hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1528 if(hasDigits && filler) {
1529 if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1530 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1532 target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1537 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1539 codeIsupNumber(isupNumber, calledOrCalling, target);
1540 length = target.size();
1541 memcpy(buffer, target.c_str(), length);