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 string functions::getVersion() throw() {
41 static const int version = ANNA_VERSION;
43 int mainVersion = (version & 0xff00) >> 8;
44 int subVersion = (version & 0xff);
46 sprintf(aux, "%d.%d", mainVersion, subVersion);
48 return result += getArchitecture();
52 (1) Solo coge los dos primeros digitos del numero de release
54 string functions::getArchitecture() throw() {
56 WHEN_MULTITHREAD(result = "/MT");
57 WHEN_SINGLETHREAD(result = "/ST");
71 char* release = anna_strchr(un.release, '.'); // (1)
74 if((release = anna_strchr(release + 1, '.')) != NULL)
84 string functions::asString(const int number)
87 sprintf(aux, "%d", number);
91 string functions::asString(const S64 number)
94 //sprintf(aux, "%lld", number);
96 sprintf (aux, "%ld", number);
98 sprintf (aux, "%lld", number);
103 string functions::asString(const unsigned int number)
106 sprintf(aux, "%u", number);
110 string functions::asString(const U64 number)
113 //sprintf(aux, "%llu", number);
115 sprintf (aux, "%lu", number);
117 sprintf (aux, "%llu", number);
122 string functions::asString(const float number, const char* format)
125 sprintf(aux, format, number);
129 string functions::asString(const double number, const char* format)
132 sprintf(aux, format, number);
136 string functions::asDateTime(const Second &second)
138 char aux [DateTimeSizeString];
139 return std::string(asDateTime(second, aux));
142 const char* functions::asDateTime(const Second &second, char* result)
144 struct tm* tt = localtime((time_t*) & second);
146 result, "%02d/%02d/%4d %02d:%02d:%02d",
147 tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900,
148 tt->tm_hour, tt->tm_min, tt->tm_sec
153 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
155 return dataBlock.asString(characterByLine);
158 string functions::asHexString(const int number)
161 sprintf(aux, "0x%x", number);
165 string functions::asHexString(const S64 number)
168 //sprintf(aux, "0x%llx", number);
170 sprintf (aux, "0x%lx", number);
172 sprintf (aux, "0x%llx", number);
177 // from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited"
178 // Dr. Dobb's Journal, April 1996)
179 S64 functions::hash(const char* p)
181 static const int long_bits = sizeof(S64) << 3;
182 static const int one_eighth = long_bits >> 3;
183 static const int three_fourths = long_bits * 3 / 4;
184 static const S64 high_bits = ((S64)(~0L)) << (long_bits - one_eighth);
189 result = (result << one_eighth) + *p ++;
191 if((temp = result & high_bits) != 0)
192 result = (result ^(temp >> three_fourths)) &~ high_bits;
199 std::string functions::asHexString(const DataBlock& dataBlock)
201 const char* buffer = dataBlock.getData();
202 const int size = dataBlock.getSize();
206 for(int ii = 0; ii < size; ii ++) {
207 byte = (buffer [ii] & 0xf0) >> 4;
208 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
209 byte = (buffer [ii] & 0x0f);
210 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
217 * Gets the original value obtained with #asHexString (const DataBlock&).
218 * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
219 * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
220 * \param target DataBlock for string decode.
221 * \return DataBlock corresponding to the provided string.
224 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
225 throw(RuntimeException) {
227 if((hexString.length() % 2) != 0)
228 throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
231 const char* src = hexString.data();
236 for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
237 if(isxdigit(aux = src [ii - 1]) == 0)
238 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
240 hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
242 if(isxdigit(aux = src [ii]) == 0)
243 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
245 hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
252 string functions::asString(const char* format, ...)
256 va_start(ap, format);
257 vsnprintf(aux, sizeof(aux), format, ap);
262 void functions::sleep(const Millisecond &millisecond)
266 req.tv_sec = millisecond.getValue() / 1000; // segundos
267 req.tv_nsec = (millisecond.getValue() % 1000); // milisegundos
268 req.tv_nsec *= 1000000; // mili = 10e-3, nano=10-9
271 while((r = nanosleep(&req, &rem)) != 0) {
275 string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
276 msg += functions::asText("| nsec: ", (int) req.tv_nsec);
278 RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
285 bool functions::asBool(const char* str)
286 throw(RuntimeException) {
290 if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
293 if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
296 string msg("anna::funcions::asBool | Cannot interpret '");
298 msg += "' as boolean";
299 throw RuntimeException(msg, ANNA_FILE_LOCATION);
302 S64 functions::asInteger64(const char* str)
305 //sscanf(str, "%lld", &number);
307 sscanf (str, "%ld", &number);
309 sscanf (str, "%lld", &number);
314 pthread_t functions::getCurrentThread()
316 WHEN_MULTITHREAD(return pthread_self());
317 WHEN_SINGLETHREAD(return 0);
320 bool functions::isLike(const char* pattern, const std::string& _value)
321 throw(RuntimeException) {
322 const char* value = _value.c_str();
326 if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
328 string msg("anna::functions::isLike | ");
329 msg += " | Pattern: ";
335 if(regerror(ret, &preg, err, sizeof(err)))
338 msg += "Invalid pattern";
340 throw RuntimeException(msg, ANNA_FILE_LOCATION);
343 const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
350 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
351 throw(RuntimeException) {
352 if(bitShift > intBitSize) {
353 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
354 throw RuntimeException(msg, ANNA_FILE_LOCATION);
357 if((bitsize(n1) + bitShift) > int64BitSize) {
358 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
359 throw RuntimeException(msg, ANNA_FILE_LOCATION);
362 if(bitsize(n2) > bitShift) {
363 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
364 throw RuntimeException(msg, ANNA_FILE_LOCATION);
371 if(bitShift == intBitSize) {
373 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
374 msg += functions::asHexString(result);
375 Logger::information(msg, ANNA_FILE_LOCATION);
384 * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
386 int functions::log2(const unsigned int v)
388 static const char LogTable256[] = {
389 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
390 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
391 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
392 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
393 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
394 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
395 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
396 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
397 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
398 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
399 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
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
406 int r = -1; // r will be lg(v)
407 unsigned int t, tt; // temporaries
410 r = ((t = tt >> 8)) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
412 r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
418 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
420 std::string singular = (wordForSingular ? wordForSingular : "entry");
421 std::string plural = (wordForPlural ? wordForPlural : "entries");
423 if(wordForSingular && !wordForPlural)
424 plural = singular + "s";
426 result += ((number != 0) ? anna::functions::asString(number) : "no");
428 result += ((number != 1) ? plural : singular);
433 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
435 int d_size = title.size();
436 int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
439 if(mode == TextJustifyMode::Center) {
440 repeat = (repeat - 1) / 2;
441 adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
444 if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
445 for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
452 if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
455 for(int k = 0; k < repeat; k++) result += filler;
462 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
464 int ou_repeat = title.size();
465 int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
468 if(mode == TextHighlightMode::LeftAndRightline) {
469 lr_repeat = (lr_repeat - 1) / 2;
470 adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
473 if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
474 for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
479 if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
480 for(int k = 0; k < ou_repeat; k++) result += filler;
487 if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
490 for(int k = 0; k < ou_repeat; k++) result += filler;
493 if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
496 for(int k = 0; k < lr_repeat; k++) result += filler;
499 if(appendCR) result += "\n";
505 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
507 size_t pos, from = 0;
508 std::string tab, crTab = "\n";
510 for(int k = 0; k < tabSpaces; k++) tab += " ";
516 while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
517 result.replace(pos, 1, crTab);
525 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
528 if(pattern.size() < suffix.size()) return false;
530 size_t pos = pattern.rfind(suffix);
532 if(pos == std::string::npos) return false;
534 preffix.assign(pattern.c_str(), pos);
535 return (pos == (pattern.size() - suffix.size()));
539 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
542 if(pattern.size() < preffix.size()) return false;
544 if(pattern.find(preffix) != 0) return false;
546 suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
551 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
552 std::string result = text;
554 if(!item || !target) return result; // protection for NULL strings provided
556 size_t lengthReplaced = strlen(item);
557 size_t pos = result.find(item);
559 while(pos != std::string::npos) {
560 result.replace(pos, lengthReplaced, target);
564 pos = result.find(item);
571 std::string functions::addQuotationMarks(const std::string & str) throw() {
572 std::string result = "'";
579 std::string functions::addQuotationMarks(const char * str) throw() {
580 std::string result = "'";
581 result += (str ? str : "<null>");
587 std::string functions::addQuotationMarks(const int & integer) throw() {
588 std::string result = "'";
589 result += anna::functions::asString(integer);
595 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
596 std::string result = "";
599 std::vector<int>::const_iterator iter;
600 std::vector<int>::const_iterator iter_min(v.begin());
601 std::vector<int>::const_iterator iter_max(v.end());
603 for(iter = iter_min; iter != iter_max; iter++) {
604 result += anna::functions::asString(*iter);
608 // Delete the last space: starts at 'size()-1', take 1 caracter:
609 result.erase(result.size() - 1, 1);
616 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
617 std::string result = "";
620 std::vector<std::string>::const_iterator iter;
621 std::vector<std::string>::const_iterator iter_min(v.begin());
622 std::vector<std::string>::const_iterator iter_max(v.end());
624 for(iter = iter_min; iter != iter_max; iter++) {
629 // Delete the last space: starts at 'size()-1', take 1 caracter:
630 result.erase(result.size() - 1, 1);
637 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
638 std::string result = address;
640 result += anna::functions::asString(port);
645 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
647 // Supposed printable by default:
648 isFullyPrintable = true;
650 if(size == 0 || !buffer) {
652 isFullyPrintable = false;
656 for(int k = 0; k < size; k ++) {
657 unsigned char c = (unsigned char) buffer [k];
658 int printable = isprint(c);
659 result += (printable ? (char) c : '.');
661 if(!printable) isFullyPrintable = false;
668 std::string functions::getHostname() throw() {
670 std::string result = "<hostname>";
672 if(gethostname(aux, sizeof aux) == 0 /*success*/)
678 std::string functions::getDomainname() throw() {
680 std::string result = "<domainname>";
682 if(getdomainname(aux, sizeof aux) == 0 /*success*/)
688 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
689 std::string hn = hostname ? hostname : (functions::getHostname());
690 std::string dn = domainname ? domainname : (functions::getDomainname());
691 // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
693 if(hn == "") return dn;
695 if(dn == "") return hn;
697 std::string label(hn, 0, 63);
698 std::string fqdn(label + "." + dn, 0, 255);
702 std::string functions::getHostnameIP() throw() {
703 std::string result = "";
705 struct in_addr **addr_list;
706 struct in_addr ipv4addr;
708 gethostname(hostname, sizeof hostname);
710 if((he = gethostbyname(hostname)) != NULL) {
711 // Official name: he->h_name
713 addr_list = (struct in_addr **)he->h_addr_list;
715 for(int i = 0; addr_list[i] != NULL; i++) {
716 //printf("%s ", inet_ntoa(*addr_list[i]));
717 result = inet_ntoa(*addr_list[i]);
726 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
727 int length = rawPresentation.size();
729 if(length != 8 && length != 32)
730 throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
732 anna::DataBlock result(true);
734 char rByte[3]; // readable byte
737 for(int k = 0; k < length; k += 2) {
738 rByte[0] = rawPresentation[k];
739 rByte[1] = rawPresentation[k + 1];
740 sscanf(rByte, "%x", &byte);
748 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
749 int length = db.getSize();
751 if(length != 4 && length != 16)
752 throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
754 std::string result = "";
756 char rByte[3]; // readable byte
759 for(int k = 0; k < length; k++) {
760 byte = (unsigned char)db[k];
761 sprintf(rByte, "%.2X", byte);
773 // 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:
774 // A typical example of an IPv6 address is
775 // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
776 // The hexadecimal digits are case-insensitive.
778 // The 128-bit IPv6 address can be abbreviated with the following rules:
779 // -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
780 // -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
781 // 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.
783 // 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.
784 // AsÃ, las siguientes son representaciones posibles de una misma dirección:
786 // 2001:0DB8:0000:0000:0000:0000:1428:57ab
787 // 2001:0DB8:0000:0000:0000::1428:57ab
788 // 2001:0DB8:0:0:0:0:1428:57ab
789 // 2001:0DB8:0::0:1428:57ab
790 // 2001:0DB8::1428:57ab
791 // son todas válidas y significan lo mismo, pero
794 // no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
796 // Los ceros iniciales en un grupo también se pueden omitir:
797 // 2001:0DB8:02de::0e13
800 // Si la dirección es una dirección IPv4 empotrada (mapped), los últimos 32 bits pueden escribirse en base decimal, asÃ:
801 // ::ffff:192.168.89.9
804 // No se debe confundir con:
808 // El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
809 // Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
810 // (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
811 // 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
812 // casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
814 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
816 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
817 if(ipv4Type == IPv4Type::Estrict) {
818 // La expresión regular no controla si hay mas de 3 puntos:
821 for(int k = 0; k < ip.length(); k++)
822 if(ip[k] == '.') n_dot++;
827 bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
828 bool colon = (ip.find(":") != std::string::npos);
829 return (ipv4 && !colon);
832 if(ipv4Type == IPv4Type::Compatible) {
833 std::string pureIPv4 = ip;
834 bool firstDoubleColon = (ip.find("::") == 0);
836 if(firstDoubleColon) {
837 pureIPv4.erase(0, 2);
838 bool anotherColon = (pureIPv4.find(":") != std::string::npos);
840 if(anotherColon) return (false);
842 return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
846 if(ipv4Type == IPv4Type::Mapped) {
847 size_t posLastColon = ip.rfind(":");
849 if(posLastColon == std::string::npos)
852 if(!isIPv4(ip.substr(posLastColon + 1)))
855 unsigned char buf[sizeof(struct in6_addr)];
856 int s = inet_pton(AF_INET6, ip.c_str(), buf);
866 bool functions::isIPv6(const std::string & ip) throw() {
867 // Chequeo de digitos permitidos:
868 for(int k = 0; k < ip.length(); k++) {
869 bool digit = isdigit(ip[k]);
870 bool hex = ((ip[k] == 'a') ||
882 bool colon = (ip[k] == ':');
884 if(!digit && !hex && !colon)
888 return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
892 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
893 if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
894 throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
896 std::string result, pureIPv4;
897 bool firstDoubleColon = (ip.find("::") == 0);
899 if(firstDoubleColon) {
901 size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
902 pureIPv4 = ip.substr(ipv4_pos);
905 size_t posColon = ip.find(":");
907 if(posColon == 0) // first colon
908 throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
910 if(posColon != std::string::npos) // any colon
911 return ip; // seems to be IPv6 already?
913 throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
919 // Number of ocurrences for '.'
922 for(int k = 0; k < pureIPv4.length(); k++)
923 if(pureIPv4[k] == '.') n_dot++;
926 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
929 anna::Tokenizer::const_iterator tok_it;
931 tok.apply(pureIPv4, ".");
935 for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
936 token = anna::Tokenizer::data(tok_it);
937 v[cnt] = atoi(anna::Tokenizer::data(tok_it));
939 if(v[cnt] < 0 || v[cnt] > 255)
940 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
945 if(isIPv4(ip, IPv4Type::Compatible))
946 result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
948 result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
954 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
955 std::string result = ip;
956 // std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
957 std::transform(result.begin(), result.end(), result.begin(), ::tolower);
959 if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
960 result = IPv4To6(result);
962 size_t pos = result.find("::"); // zeroes simplification group
963 size_t rpos = result.rfind("::"); // zeroes simplification group
966 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
968 if(pos != std::string::npos) { // zeroes exists
969 // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
970 // Number of ocurrences for ':'
973 for(int k = 0; k < result.length(); k++)
974 if(result[k] == ':') n_colon++;
976 // Generate equivalent to '::'
977 std::string equiv_str;
979 for(int k = 0; k < (8 - n_colon); k++)
983 // Replace with equivalent:
984 result.replace(pos, 2, equiv_str);
986 // Special case: IP began with '::'
987 if(result[0] == ':') {
988 result.insert(0, "0");
991 // Special case: IP was only '::'
992 if(result[result.length() - 1] == ':') {
997 // Protection: it must be seven colons:
1000 for(int k = 0; k < result.length(); k++)
1001 if(result[k] == ':') n_colon++;
1004 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1006 // Padding with zeroes at left
1007 anna::Tokenizer ipStr;
1008 anna::Tokenizer::const_iterator ipStr_it;
1010 ipStr.apply(result, ":");
1013 for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1014 token = anna::Tokenizer::data(ipStr_it);
1016 while(token.length() < 4) token.insert(0, "0");
1023 size_t lastPos = result.length() - 1;
1024 result.erase(lastPos, 1);
1026 // Chequeo de digitos permitidos:
1027 for(int k = 0; k < result.length(); k++) {
1028 bool digit = isdigit(result[k]);
1029 bool hex = ((result[k] == 'a') ||
1030 (result[k] == 'b') ||
1031 (result[k] == 'c') ||
1032 (result[k] == 'd') ||
1033 (result[k] == 'e') ||
1034 (result[k] == 'f'));
1035 bool colon = (result[k] == ':');
1037 if(!digit && !hex && !colon) {
1038 throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1046 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1047 //if (ip1 == ip2) return true; it should validate wrong-format addresses
1048 return (normalizeIP(ip1) == normalizeIP(ip2));
1052 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1053 size_t preffixPos = preffixedIpv6.find("/");
1055 if(preffixPos == std::string::npos)
1056 return (sameIP(_ipv6, preffixedIpv6));
1058 std::string ipv6 = _ipv6;
1060 if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1062 std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1063 std::string ipv6_2 = _ipv6_2;
1065 if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1067 std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1068 int ipv6_2_preffixLength = atoi(preffix.c_str());
1070 if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1071 throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1073 // No restriction, all ipv6_2 ignored (special and not usual case)
1074 if(ipv6_2_preffixLength == 0) return true;
1077 int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1078 int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1079 int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1080 char mask = 0xFF << (8 - spare);
1082 anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1083 anna::DataBlock restrictedIP1(true);
1084 restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1086 if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1089 anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1090 anna::DataBlock realIP2(true);
1091 realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1093 if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1096 int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1101 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1102 anna::DataBlock result(true);
1105 unsigned char buf[sizeof(struct in6_addr)];
1106 int s = inet_pton(AF_INET, ip.c_str(), buf);
1109 result += (S8)buf[0];
1110 result += (S8)buf[1];
1111 result += (S8)buf[2];
1112 result += (S8)buf[3];
1114 if(s < 0) perror("inet_pton");
1116 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1119 unsigned char buf[sizeof(struct in6_addr)];
1120 int s = inet_pton(AF_INET6, ip.c_str(), buf);
1123 result += (S8)buf[0];
1124 result += (S8)buf[1];
1125 result += (S8)buf[2];
1126 result += (S8)buf[3];
1127 result += (S8)buf[4];
1128 result += (S8)buf[5];
1129 result += (S8)buf[6];
1130 result += (S8)buf[7];
1131 result += (S8)buf[8];
1132 result += (S8)buf[9];
1133 result += (S8)buf[10];
1134 result += (S8)buf[11];
1135 result += (S8)buf[12];
1136 result += (S8)buf[13];
1137 result += (S8)buf[14];
1138 result += (S8)buf[15];
1140 if(s < 0) perror("inet_pton");
1142 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1148 // anna::DataBlock result(true);
1151 // if (isIPv4(ip)) {
1153 // 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/)
1154 // sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1155 // result += (S8)dec1;
1156 // result += (S8)dec2;
1157 // result += (S8)dec3;
1158 // result += (S8)dec4;
1162 // 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/)
1163 // sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1164 // result += ((S8)(hex1 >> 8));
1165 // result += ((S8)(hex1 & 0x00FF));
1166 // result += ((S8)(hex2 >> 8));
1167 // result += ((S8)(hex2 & 0x00FF));
1168 // result += ((S8)(hex3 >> 8));
1169 // result += ((S8)(hex3 & 0x00FF));
1170 // result += ((S8)(hex4 >> 8));
1171 // result += ((S8)(hex4 & 0x00FF));
1172 // result += ((S8)(hex5 >> 8));
1173 // result += ((S8)(hex5 & 0x00FF));
1174 // result += ((S8)(hex6 >> 8));
1175 // result += ((S8)(hex6 & 0x00FF));
1176 // result += ((S8)(hex7 >> 8));
1177 // result += ((S8)(hex7 & 0x00FF));
1178 // result += ((S8)(hex8 >> 8));
1179 // result += ((S8)(hex8 & 0x00FF));
1187 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1188 std::string result = "";
1189 char str[INET6_ADDRSTRLEN];
1191 if(bufferLength == 4) {
1192 if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1194 } else if(bufferLength == 16) {
1195 if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1198 throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1201 throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1203 return (normalize ? normalizeIP(result) : result);
1205 // std::string result;
1208 // if (bufferLength == 4) { // IPv4
1209 // result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1211 // else if (bufferLength == 16) { // IPv6
1212 // result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1213 // ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1214 // (((U8)buffer[1]) & 0x00FF),
1215 // ((((U8)buffer[2]) << 8) & 0xFF00) +
1216 // (((U8)buffer[3]) & 0x00FF),
1217 // ((((U8)buffer[4]) << 8) & 0xFF00) +
1218 // (((U8)buffer[5]) & 0x00FF),
1219 // ((((U8)buffer[6]) << 8) & 0xFF00) +
1220 // (((U8)buffer[7]) & 0x00FF),
1221 // ((((U8)buffer[8]) << 8) & 0xFF00) +
1222 // (((U8)buffer[9]) & 0x00FF),
1223 // ((((U8)buffer[10]) << 8) & 0xFF00) +
1224 // (((U8)buffer[11]) & 0x00FF),
1225 // ((((U8)buffer[12]) << 8) & 0xFF00) +
1226 // (((U8)buffer[13]) & 0x00FF),
1227 // ((((U8)buffer[14]) << 8) & 0xFF00) +
1228 // (((U8)buffer[15]) & 0x00FF));
1231 // throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1234 // return (normalize ? normalizeIP(result):result);
1238 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1239 size_t pos = literal.find_last_of(":");
1240 size_t lastPos = literal.size() - 1;
1241 address = ""; port = -1; // assume error
1243 if((pos != std::string::npos) && (pos != lastPos)) {
1244 address = literal.substr(0, pos);
1245 port = atoi(literal.substr(pos + 1, lastPos).c_str());
1250 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1252 std::string address;
1254 anna::Tokenizer lst;
1255 lst.apply(list, ",");
1257 if(lst.size() < 1) return result;
1259 anna::Tokenizer::const_iterator tok_min(lst.begin());
1260 anna::Tokenizer::const_iterator tok_max(lst.end());
1261 anna::Tokenizer::const_iterator tok_iter;
1263 for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1264 getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1266 if(port == -1) { result.clear(); return result; }
1268 result.push_back(socket_t(address, port));
1274 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1277 socket_v_it it_min(socketVector.begin());
1278 socket_v_it it_max(socketVector.end());
1280 for(it = it_min; it != it_max; it++) {
1281 result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1284 result.erase(result.size() - 1, 1); // remove last comma
1288 bool functions::littleEndian()
1291 char *p = (char *) &i;
1292 if (p[0] == 1) return true;
1296 const char* functions::codeInteger(char* result, const int n)
1299 char* w((char*) &aux);
1301 *(result + 1) = *(w + 1);
1302 *(result + 2) = *(w + 2);
1303 *(result + 3) = *(w + 3);
1307 const char* functions::codeShort(char* result, const short int n)
1309 short int aux(htons(n));
1310 char* w((char*) &aux);
1312 *(result + 1) = *(w + 1);
1316 const char* functions::codeInteger64(char* result, const S64 n)
1318 S64 aux(0xffffffff);
1322 n2 = (aux >> 32) & 0xffffffff;
1323 codeInteger(result, n2);
1324 n2 = n & 0xffffffff;
1325 codeInteger(result + sizeof(int), n2);
1330 const char* functions::codeFloat(char* result, const float n)
1333 anna_memcpy(&ii, &n, sizeof(n));
1334 return functions::codeInteger(result, ii);
1338 const char* functions::codeDouble(char* result, const double n)
1341 anna_memcpy(&ii, &n, sizeof(n));
1342 return functions::codeInteger64(result, ii);
1345 int functions::decodeInteger(const char* data)
1348 char* w((char*) &result);
1350 *(w + 1) = *(data + 1);
1351 *(w + 2) = *(data + 2);
1352 *(w + 3) = *(data + 3);
1353 return ntohl(result);
1356 short int functions::decodeShort(const char* data)
1359 char* w((char*) &result);
1361 *(w + 1) = *(data + 1);
1362 return ntohs(result);
1365 S64 functions::decodeInteger64(const char* data)
1367 S64 result(decodeInteger(data));
1369 return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1373 float functions::decodeFloat(const char* data)
1376 int ii = functions::decodeInteger(data);
1377 anna_memcpy(&result, &ii, sizeof(result));
1382 double functions::decodeDouble(const char* data)
1385 S64 ii = functions::decodeInteger64(data);
1386 anna_memcpy(&result, &ii, sizeof(result));
1392 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1393 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1395 isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1396 bool filler = isupNumber.OddEven;
1398 if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1399 throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1401 isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1402 isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1404 if(calledOrCalling) {
1405 isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1407 isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1408 isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1409 isupNumber.Screening = (short)(buffer[1] & 0x03);
1413 isupNumber.Digits = "";
1416 for(int k = 2; k < length; k ++) {
1417 byte = (buffer [k] & 0x0f);
1418 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1419 byte = (buffer [k] & 0xf0) >> 4;
1420 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1423 if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler
1427 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1429 if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1430 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1432 bool odd = isupNumber.OddEven;
1433 bool oddDigits = (isupNumber.Digits.size() % 2);
1435 if(odd != oddDigits)
1436 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1438 if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1439 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1441 if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1442 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1444 if(calledOrCalling) {
1445 if(isupNumber.NumberIncomplete != 0)
1446 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1448 if(isupNumber.AddressPresentationRestricted != 0)
1449 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1451 if(isupNumber.Screening != 0)
1452 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1454 if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1455 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1457 if(isupNumber.InternalNetworkNumber != 0)
1458 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1460 if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1461 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1463 if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1464 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1466 if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1467 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1472 bool filler = isupNumber.OddEven;
1473 bool hasDigits = (isupNumber.Digits.size() > 0);
1474 byte = filler ? 0x80 : 0x00;
1475 byte = byte |= isupNumber.NatureOfAddress;
1478 if(calledOrCalling) {
1479 byte = isupNumber.InternalNetworkNumber << 7;
1480 byte = byte |= (isupNumber.NumberingPlan << 4);
1482 byte = isupNumber.NumberIncomplete << 7;
1483 byte = byte |= (isupNumber.NumberingPlan << 4);
1484 byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1485 byte = byte |= isupNumber.Screening;
1491 std::string dtlc = isupNumber.Digits; // digits to lower case
1492 //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1493 const char *digits = dtlc.c_str();
1495 for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1496 if(isxdigit(byte = digits [k - 1]) == 0)
1497 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1499 hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1501 if(isxdigit(byte = digits [k]) == 0)
1502 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1504 hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1508 if(hasDigits && filler) {
1509 if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1510 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1512 target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1517 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1519 codeIsupNumber(isupNumber, calledOrCalling, target);
1520 length = target.size();
1521 memcpy(buffer, target.c_str(), length);