1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
45 #include <sys/types.h>
47 #include <sys/utsname.h>
48 #include <arpa/inet.h>
49 #include <sys/socket.h> // extraccion de IP del hostname
50 #include <netinet/in.h> // extraccion de IP del hostname
51 #include <netdb.h> // extraccion de IP del hostname
52 #include <unistd.h> // gethostname
54 #include <anna/core/functions.hpp>
55 #include <anna/core/DataBlock.hpp>
56 #include <anna/core/tracing/Logger.hpp>
57 #include <anna/core/util/Second.hpp>
58 #include <anna/core/util/Tokenizer.hpp>
66 #define PAGE_WIDTH_LENGTH 80
68 ExclusiveHash <std::string> functions::st_stringExclusiveHash;
69 ExclusiveHash <std::string, int> functions::st_string2intExclusiveHash;
71 string functions::getVersion() throw() {
72 static const int version = ANNA_VERSION;
74 int mainVersion = (version & 0xff00) >> 8;
75 int subVersion = (version & 0xff);
77 sprintf(aux, "%d.%d", mainVersion, subVersion);
79 return result += getArchitecture();
83 (1) Solo coge los dos primeros digitos del numero de release
85 string functions::getArchitecture() throw() {
87 WHEN_MULTITHREAD(result = "/MT");
88 WHEN_SINGLETHREAD(result = "/ST");
100 result += un.sysname;
102 char* release = anna_strchr(un.release, '.'); // (1)
105 if((release = anna_strchr(release + 1, '.')) != NULL)
108 result += un.release;
110 result += un.machine;
115 string functions::asString(const int number)
118 sprintf(aux, "%d", number);
122 string functions::asString(const unsigned long number)
124 return asString((U64)number);
127 string functions::asString(const S64 number)
130 sprintf(aux, "%lld", number);
132 sprintf (aux, "%ld", number);
134 sprintf (aux, "%lld", number);
140 string functions::asString(const unsigned int number)
143 sprintf(aux, "%u", number);
147 string functions::asString(const U64 number)
150 sprintf(aux, "%llu", number);
153 sprintf (aux, "%lu", number);
155 sprintf (aux, "%llu", number);
161 string functions::asString(const float number, const char* format)
164 sprintf(aux, format, number);
168 string functions::asString(const double number, const char* format)
171 sprintf(aux, format, number);
175 string functions::asDateTime(const Second &second)
177 char aux [DateTimeSizeString];
178 return std::string(asDateTime(second, aux));
181 const char* functions::asDateTime(const Second &second, char* result)
183 struct tm* tt = localtime((time_t*) & second);
185 result, "%02d/%02d/%4d %02d:%02d:%02d",
186 tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900,
187 tt->tm_hour, tt->tm_min, tt->tm_sec
192 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
194 return dataBlock.asString(characterByLine);
197 string functions::asHexString(const int number)
200 sprintf(aux, "0x%x", number);
204 string functions::asHexString(const long number)
206 return asHexString((S64)number);
209 string functions::asHexString(const S64 number)
212 sprintf(aux, "0x%llx", number);
215 sprintf (aux, "0x%lx", number);
217 sprintf (aux, "0x%llx", number);
223 // from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited"
224 // Dr. Dobb's Journal, April 1996)
225 S64 functions::hash(const char* p)
227 static const int long_bits = sizeof(S64) << 3;
228 static const int one_eighth = long_bits >> 3;
229 static const int three_fourths = long_bits * 3 / 4;
230 static const S64 high_bits = ((S64)(~0L)) << (long_bits - one_eighth);
235 result = (result << one_eighth) + *p ++;
237 if((temp = result & high_bits) != 0)
238 result = (result ^(temp >> three_fourths)) &~ high_bits;
245 std::string functions::asHexString(const DataBlock& dataBlock)
247 const char* buffer = dataBlock.getData();
248 const int size = dataBlock.getSize();
252 for(int ii = 0; ii < size; ii ++) {
253 byte = (buffer [ii] & 0xf0) >> 4;
254 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
255 byte = (buffer [ii] & 0x0f);
256 result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
263 * Obtiene el valor original de una cadena obtenido con #asHexString (const DataBlock&).
264 * \param hexString Cadena que contiene el búfer.
265 * \param target Bloque de datos sobre el que decodificar la cadena.
266 * \return El bloque de datos original correspondiente a la cadena recibida.
269 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
270 throw(RuntimeException) {
271 if((hexString.length() % 2) != 0)
272 throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
275 const char* src = hexString.data();
280 for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
281 if(isxdigit(aux = src [ii - 1]) == 0)
282 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
284 hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
286 if(isxdigit(aux = src [ii]) == 0)
287 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
289 hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
296 string functions::asString(const char* format, ...)
300 va_start(ap, format);
301 vsnprintf(aux, sizeof(aux), format, ap);
306 void functions::sleep(const Millisecond &millisecond)
310 req.tv_sec = millisecond.getValue() / 1000; // segundos
311 req.tv_nsec = (millisecond.getValue() % 1000); // milisegundos
312 req.tv_nsec *= 1000000; // mili = 10e-3, nano=10-9
315 while((r = nanosleep(&req, &rem)) != 0) {
319 string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
320 msg += functions::asText("| nsec: ", (int) req.tv_nsec);
322 RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
329 bool functions::asBool(const char* str)
330 throw(RuntimeException) {
334 if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
337 if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
340 string msg("anna::funcions::asBool | Cannot interpret '");
342 msg += "' as boolean";
343 throw RuntimeException(msg, ANNA_FILE_LOCATION);
346 S64 functions::asInteger64(const char* str)
349 sscanf(str, "%lld", &number);
352 sscanf (str, "%ld", &number);
354 sscanf (str, "%lld", &number);
360 pthread_t functions::getCurrentThread()
362 WHEN_MULTITHREAD(return pthread_self());
363 WHEN_SINGLETHREAD(return 0);
366 bool functions::isLike(const char* pattern, const std::string& _value)
367 throw(RuntimeException) {
368 const char* value = _value.c_str();
372 if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
374 string msg("anna::functions::isLike | ");
375 msg += " | Pattern: ";
381 if(regerror(ret, &preg, err, sizeof(err)))
384 msg += "Invalid pattern";
386 throw RuntimeException(msg, ANNA_FILE_LOCATION);
389 const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
396 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
397 throw(RuntimeException) {
398 if(bitShift > intBitSize) {
399 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
400 throw RuntimeException(msg, ANNA_FILE_LOCATION);
403 if((bitsize(n1) + bitShift) > int64BitSize) {
404 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
405 throw RuntimeException(msg, ANNA_FILE_LOCATION);
408 if(bitsize(n2) > bitShift) {
409 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
410 throw RuntimeException(msg, ANNA_FILE_LOCATION);
417 if(bitShift == intBitSize) {
419 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
420 msg += functions::asHexString(result);
421 Logger::information(msg, ANNA_FILE_LOCATION);
430 * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
432 int functions::log2(const unsigned int v)
434 static const char LogTable256[] = {
435 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
436 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
437 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
438 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
439 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
440 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
441 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
442 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
443 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
444 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
445 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
446 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
447 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
448 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
449 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
450 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
452 int r = -1; // r will be lg(v)
453 unsigned int t, tt; // temporaries
456 r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
458 r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
464 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
466 std::string singular = (wordForSingular ? wordForSingular : "entry");
467 std::string plural = (wordForPlural ? wordForPlural : "entries");
469 if(wordForSingular && !wordForPlural)
470 plural = singular + "s";
472 result += ((number != 0) ? anna::functions::asString(number) : "no");
474 result += ((number != 1) ? plural : singular);
479 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
481 int d_size = title.size();
482 int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
485 if(mode == TextJustifyMode::Center) {
486 repeat = (repeat - 1) / 2;
487 adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
490 if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
491 for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
498 if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
501 for(int k = 0; k < repeat; k++) result += filler;
508 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
510 int ou_repeat = title.size();
511 int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
514 if(mode == TextHighlightMode::LeftAndRightline) {
515 lr_repeat = (lr_repeat - 1) / 2;
516 adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
519 if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
520 for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
525 if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
526 for(int k = 0; k < ou_repeat; k++) result += filler;
533 if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
536 for(int k = 0; k < ou_repeat; k++) result += filler;
539 if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
542 for(int k = 0; k < lr_repeat; k++) result += filler;
545 if(appendCR) result += "\n";
551 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
553 size_t pos, from = 0;
554 std::string tab, crTab = "\n";
556 for(int k = 0; k < tabSpaces; k++) tab += " ";
562 while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
563 result.replace(pos, 1, crTab);
571 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
574 if(pattern.size() < suffix.size()) return false;
576 size_t pos = pattern.rfind(suffix);
578 if(pos == std::string::npos) return false;
580 preffix.assign(pattern.c_str(), pos);
581 return (pos == (pattern.size() - suffix.size()));
585 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
588 if(pattern.size() < preffix.size()) return false;
590 if(pattern.find(preffix) != 0) return false;
592 suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
597 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
598 std::string result = text;
600 if(!item || !target) return result; // protection for NULL strings provided
602 size_t lengthReplaced = strlen(item);
603 size_t pos = result.find(item);
605 while(pos != std::string::npos) {
606 result.replace(pos, lengthReplaced, target);
610 pos = result.find(item);
617 std::string functions::addQuotationMarks(const std::string & str) throw() {
618 std::string result = "'";
625 std::string functions::addQuotationMarks(const char * str) throw() {
626 std::string result = "'";
627 result += (str ? str : "<null>");
633 std::string functions::addQuotationMarks(const int & integer) throw() {
634 std::string result = "'";
635 result += anna::functions::asString(integer);
641 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
642 std::string result = "";
645 std::vector<int>::const_iterator iter;
646 std::vector<int>::const_iterator iter_min(v.begin());
647 std::vector<int>::const_iterator iter_max(v.end());
649 for(iter = iter_min; iter != iter_max; iter++) {
650 result += anna::functions::asString(*iter);
654 // Delete the last space: starts at 'size()-1', take 1 caracter:
655 result.erase(result.size() - 1, 1);
662 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
663 std::string result = "";
666 std::vector<std::string>::const_iterator iter;
667 std::vector<std::string>::const_iterator iter_min(v.begin());
668 std::vector<std::string>::const_iterator iter_max(v.end());
670 for(iter = iter_min; iter != iter_max; iter++) {
675 // Delete the last space: starts at 'size()-1', take 1 caracter:
676 result.erase(result.size() - 1, 1);
683 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
684 std::string result = address;
686 result += anna::functions::asString(port);
691 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
693 // Supposed printable by default:
694 isFullyPrintable = true;
696 if(size == 0 || !buffer) {
698 isFullyPrintable = false;
702 for(int k = 0; k < size; k ++) {
703 unsigned char c = (unsigned char) buffer [k];
704 int printable = isprint(c);
705 result += (printable ? (char) c : '.');
707 if(!printable) isFullyPrintable = false;
714 std::string functions::getHostname() throw() {
716 std::string result = "<hostname>";
718 if(gethostname(aux, sizeof aux) == 0 /*success*/)
724 std::string functions::getDomainname() throw() {
726 std::string result = "<domainname>";
728 if(getdomainname(aux, sizeof aux) == 0 /*success*/)
734 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
735 std::string hn = hostname ? hostname : (functions::getHostname());
736 std::string dn = domainname ? domainname : (functions::getDomainname());
737 // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
739 if(hn == "") return dn;
741 if(dn == "") return hn;
743 std::string label(hn, 0, 63);
744 std::string fqdn(label + "." + dn, 0, 255);
748 std::string functions::getHostnameIP() throw() {
749 std::string result = "";
751 struct in_addr **addr_list;
752 struct in_addr ipv4addr;
754 gethostname(hostname, sizeof hostname);
756 if((he = gethostbyname(hostname)) != NULL) {
757 // Official name: he->h_name
759 addr_list = (struct in_addr **)he->h_addr_list;
761 for(int i = 0; addr_list[i] != NULL; i++) {
762 //printf("%s ", inet_ntoa(*addr_list[i]));
763 result = inet_ntoa(*addr_list[i]);
772 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
773 int length = rawPresentation.size();
775 if(length != 8 && length != 32)
776 throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
778 anna::DataBlock result(true);
780 char rByte[3]; // readable byte
783 for(int k = 0; k < length; k += 2) {
784 rByte[0] = rawPresentation[k];
785 rByte[1] = rawPresentation[k + 1];
786 sscanf(rByte, "%x", &byte);
794 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
795 int length = db.getSize();
797 if(length != 4 && length != 16)
798 throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
800 std::string result = "";
802 char rByte[3]; // readable byte
805 for(int k = 0; k < length; k++) {
806 byte = (unsigned char)db[k];
807 sprintf(rByte, "%.2X", byte);
819 // 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:
820 // A typical example of an IPv6 address is
821 // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
822 // The hexadecimal digits are case-insensitive.
824 // The 128-bit IPv6 address can be abbreviated with the following rules:
825 // -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
826 // -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
827 // 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.
829 // 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.
830 // AsÃ, las siguientes son representaciones posibles de una misma dirección:
832 // 2001:0DB8:0000:0000:0000:0000:1428:57ab
833 // 2001:0DB8:0000:0000:0000::1428:57ab
834 // 2001:0DB8:0:0:0:0:1428:57ab
835 // 2001:0DB8:0::0:1428:57ab
836 // 2001:0DB8::1428:57ab
837 // son todas válidas y significan lo mismo, pero
840 // no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
842 // Los ceros iniciales en un grupo también se pueden omitir:
843 // 2001:0DB8:02de::0e13
846 // Si la dirección es una dirección IPv4 empotrada (mapped), los últimos 32 bits pueden escribirse en base decimal, asÃ:
847 // ::ffff:192.168.89.9
850 // No se debe confundir con:
854 // El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
855 // Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
856 // (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
857 // 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
858 // casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
860 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
862 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
863 if(ipv4Type == IPv4Type::Estrict) {
864 // La expresión regular no controla si hay mas de 3 puntos:
867 for(int k = 0; k < ip.length(); k++)
868 if(ip[k] == '.') n_dot++;
873 bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
874 bool colon = (ip.find(":") != std::string::npos);
875 return (ipv4 && !colon);
878 if(ipv4Type == IPv4Type::Compatible) {
879 std::string pureIPv4 = ip;
880 bool firstDoubleColon = (ip.find("::") == 0);
882 if(firstDoubleColon) {
883 pureIPv4.erase(0, 2);
884 bool anotherColon = (pureIPv4.find(":") != std::string::npos);
886 if(anotherColon) return (false);
888 return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
892 if(ipv4Type == IPv4Type::Mapped) {
893 size_t posLastColon = ip.rfind(":");
895 if(posLastColon == std::string::npos)
898 if(!isIPv4(ip.substr(posLastColon + 1)))
901 unsigned char buf[sizeof(struct in6_addr)];
902 int s = inet_pton(AF_INET6, ip.c_str(), buf);
912 bool functions::isIPv6(const std::string & ip) throw() {
913 // Chequeo de digitos permitidos:
914 for(int k = 0; k < ip.length(); k++) {
915 bool digit = isdigit(ip[k]);
916 bool hex = ((ip[k] == 'a') ||
928 bool colon = (ip[k] == ':');
930 if(!digit && !hex && !colon)
934 return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
938 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
939 if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
940 throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
942 std::string result, pureIPv4;
943 bool firstDoubleColon = (ip.find("::") == 0);
945 if(firstDoubleColon) {
947 size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
948 pureIPv4 = ip.substr(ipv4_pos);
951 size_t posColon = ip.find(":");
953 if(posColon == 0) // first colon
954 throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
956 if(posColon != std::string::npos) // any colon
957 return ip; // seems to be IPv6 already?
959 throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
965 // Number of ocurrences for '.'
968 for(int k = 0; k < pureIPv4.length(); k++)
969 if(pureIPv4[k] == '.') n_dot++;
972 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
975 anna::Tokenizer::const_iterator tok_it;
977 tok.apply(pureIPv4, ".");
981 for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
982 token = anna::Tokenizer::data(tok_it);
983 v[cnt] = atoi(anna::Tokenizer::data(tok_it));
985 if(v[cnt] < 0 || v[cnt] > 255)
986 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
991 if(isIPv4(ip, IPv4Type::Compatible))
992 result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
994 result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
1000 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
1001 std::string result = ip;
1002 // std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
1003 std::transform(result.begin(), result.end(), result.begin(), ::tolower);
1005 if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
1006 result = IPv4To6(result);
1008 size_t pos = result.find("::"); // zeroes simplification group
1009 size_t rpos = result.rfind("::"); // zeroes simplification group
1012 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
1014 if(pos != std::string::npos) { // zeroes exists
1015 // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
1016 // Number of ocurrences for ':'
1019 for(int k = 0; k < result.length(); k++)
1020 if(result[k] == ':') n_colon++;
1022 // Generate equivalent to '::'
1023 std::string equiv_str;
1025 for(int k = 0; k < (8 - n_colon); k++)
1029 // Replace with equivalent:
1030 result.replace(pos, 2, equiv_str);
1032 // Special case: IP began with '::'
1033 if(result[0] == ':') {
1034 result.insert(0, "0");
1037 // Special case: IP was only '::'
1038 if(result[result.length() - 1] == ':') {
1043 // Protection: it must be seven colons:
1046 for(int k = 0; k < result.length(); k++)
1047 if(result[k] == ':') n_colon++;
1050 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1052 // Padding with zeroes at left
1053 anna::Tokenizer ipStr;
1054 anna::Tokenizer::const_iterator ipStr_it;
1056 ipStr.apply(result, ":");
1059 for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1060 token = anna::Tokenizer::data(ipStr_it);
1062 while(token.length() < 4) token.insert(0, "0");
1069 size_t lastPos = result.length() - 1;
1070 result.erase(lastPos, 1);
1072 // Chequeo de digitos permitidos:
1073 for(int k = 0; k < result.length(); k++) {
1074 bool digit = isdigit(result[k]);
1075 bool hex = ((result[k] == 'a') ||
1076 (result[k] == 'b') ||
1077 (result[k] == 'c') ||
1078 (result[k] == 'd') ||
1079 (result[k] == 'e') ||
1080 (result[k] == 'f'));
1081 bool colon = (result[k] == ':');
1083 if(!digit && !hex && !colon) {
1084 throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1092 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1093 //if (ip1 == ip2) return true; it should validate wrong-format addresses
1094 return (normalizeIP(ip1) == normalizeIP(ip2));
1098 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1099 size_t preffixPos = preffixedIpv6.find("/");
1101 if(preffixPos == std::string::npos)
1102 return (sameIP(_ipv6, preffixedIpv6));
1104 std::string ipv6 = _ipv6;
1106 if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1108 std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1109 std::string ipv6_2 = _ipv6_2;
1111 if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1113 std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1114 int ipv6_2_preffixLength = atoi(preffix.c_str());
1116 if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1117 throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1119 // No restriction, all ipv6_2 ignored (special and not usual case)
1120 if(ipv6_2_preffixLength == 0) return true;
1123 int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1124 int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1125 int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1126 char mask = 0xFF << (8 - spare);
1128 anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1129 anna::DataBlock restrictedIP1(true);
1130 restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1132 if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1135 anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1136 anna::DataBlock realIP2(true);
1137 realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1139 if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1142 int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1147 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1148 anna::DataBlock result(true);
1151 unsigned char buf[sizeof(struct in6_addr)];
1152 int s = inet_pton(AF_INET, ip.c_str(), buf);
1155 result += (S8)buf[0];
1156 result += (S8)buf[1];
1157 result += (S8)buf[2];
1158 result += (S8)buf[3];
1160 if(s < 0) perror("inet_pton");
1162 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1165 unsigned char buf[sizeof(struct in6_addr)];
1166 int s = inet_pton(AF_INET6, ip.c_str(), buf);
1169 result += (S8)buf[0];
1170 result += (S8)buf[1];
1171 result += (S8)buf[2];
1172 result += (S8)buf[3];
1173 result += (S8)buf[4];
1174 result += (S8)buf[5];
1175 result += (S8)buf[6];
1176 result += (S8)buf[7];
1177 result += (S8)buf[8];
1178 result += (S8)buf[9];
1179 result += (S8)buf[10];
1180 result += (S8)buf[11];
1181 result += (S8)buf[12];
1182 result += (S8)buf[13];
1183 result += (S8)buf[14];
1184 result += (S8)buf[15];
1186 if(s < 0) perror("inet_pton");
1188 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1194 // anna::DataBlock result(true);
1197 // if (isIPv4(ip)) {
1199 // 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/)
1200 // sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1201 // result += (S8)dec1;
1202 // result += (S8)dec2;
1203 // result += (S8)dec3;
1204 // result += (S8)dec4;
1208 // 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/)
1209 // sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1210 // result += ((S8)(hex1 >> 8));
1211 // result += ((S8)(hex1 & 0x00FF));
1212 // result += ((S8)(hex2 >> 8));
1213 // result += ((S8)(hex2 & 0x00FF));
1214 // result += ((S8)(hex3 >> 8));
1215 // result += ((S8)(hex3 & 0x00FF));
1216 // result += ((S8)(hex4 >> 8));
1217 // result += ((S8)(hex4 & 0x00FF));
1218 // result += ((S8)(hex5 >> 8));
1219 // result += ((S8)(hex5 & 0x00FF));
1220 // result += ((S8)(hex6 >> 8));
1221 // result += ((S8)(hex6 & 0x00FF));
1222 // result += ((S8)(hex7 >> 8));
1223 // result += ((S8)(hex7 & 0x00FF));
1224 // result += ((S8)(hex8 >> 8));
1225 // result += ((S8)(hex8 & 0x00FF));
1233 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1234 std::string result = "";
1235 char str[INET6_ADDRSTRLEN];
1237 if(bufferLength == 4) {
1238 if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1240 } else if(bufferLength == 16) {
1241 if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1244 throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1247 throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1249 return (normalize ? normalizeIP(result) : result);
1251 // std::string result;
1254 // if (bufferLength == 4) { // IPv4
1255 // result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1257 // else if (bufferLength == 16) { // IPv6
1258 // result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1259 // ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1260 // (((U8)buffer[1]) & 0x00FF),
1261 // ((((U8)buffer[2]) << 8) & 0xFF00) +
1262 // (((U8)buffer[3]) & 0x00FF),
1263 // ((((U8)buffer[4]) << 8) & 0xFF00) +
1264 // (((U8)buffer[5]) & 0x00FF),
1265 // ((((U8)buffer[6]) << 8) & 0xFF00) +
1266 // (((U8)buffer[7]) & 0x00FF),
1267 // ((((U8)buffer[8]) << 8) & 0xFF00) +
1268 // (((U8)buffer[9]) & 0x00FF),
1269 // ((((U8)buffer[10]) << 8) & 0xFF00) +
1270 // (((U8)buffer[11]) & 0x00FF),
1271 // ((((U8)buffer[12]) << 8) & 0xFF00) +
1272 // (((U8)buffer[13]) & 0x00FF),
1273 // ((((U8)buffer[14]) << 8) & 0xFF00) +
1274 // (((U8)buffer[15]) & 0x00FF));
1277 // throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1280 // return (normalize ? normalizeIP(result):result);
1284 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1285 size_t pos = literal.find_last_of(":");
1286 size_t lastPos = literal.size() - 1;
1287 address = ""; port = -1; // assume error
1289 if((pos != std::string::npos) && (pos != lastPos)) {
1290 address = literal.substr(0, pos);
1291 port = atoi(literal.substr(pos + 1, lastPos).c_str());
1296 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1298 std::string address;
1300 anna::Tokenizer lst;
1301 lst.apply(list, ",");
1303 if(lst.size() < 1) return result;
1305 anna::Tokenizer::const_iterator tok_min(lst.begin());
1306 anna::Tokenizer::const_iterator tok_max(lst.end());
1307 anna::Tokenizer::const_iterator tok_iter;
1309 for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1310 getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1312 if(port == -1) { result.clear(); return result; }
1314 result.push_back(socket_t(address, port));
1320 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1323 socket_v_it it_min(socketVector.begin());
1324 socket_v_it it_max(socketVector.end());
1326 for(it = it_min; it != it_max; it++) {
1327 result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1330 result.erase(result.size() - 1, 1); // remove last comma
1334 bool functions::littleEndian()
1337 char *p = (char *) &i;
1338 if (p[0] == 1) return true;
1342 const char* functions::codeInteger(char* result, const int n)
1345 char* w((char*) &aux);
1347 *(result + 1) = *(w + 1);
1348 *(result + 2) = *(w + 2);
1349 *(result + 3) = *(w + 3);
1353 const char* functions::codeShort(char* result, const short int n)
1355 short int aux(htons(n));
1356 char* w((char*) &aux);
1358 *(result + 1) = *(w + 1);
1362 const char* functions::codeInteger64(char* result, const S64 n)
1364 S64 aux(0xffffffff);
1368 n2 = (aux >> 32) & 0xffffffff;
1369 codeInteger(result, n2);
1370 n2 = n & 0xffffffff;
1371 codeInteger(result + sizeof(int), n2);
1376 const char* functions::codeFloat(char* result, const float n)
1379 anna_memcpy(&ii, &n, sizeof(n));
1380 return functions::codeInteger(result, ii);
1384 const char* functions::codeDouble(char* result, const double n)
1387 anna_memcpy(&ii, &n, sizeof(n));
1388 return functions::codeInteger64(result, ii);
1391 int functions::decodeInteger(const char* data)
1394 char* w((char*) &result);
1396 *(w + 1) = *(data + 1);
1397 *(w + 2) = *(data + 2);
1398 *(w + 3) = *(data + 3);
1399 return ntohl(result);
1402 short int functions::decodeShort(const char* data)
1405 char* w((char*) &result);
1407 *(w + 1) = *(data + 1);
1408 return ntohs(result);
1411 S64 functions::decodeInteger64(const char* data)
1413 S64 result(decodeInteger(data));
1415 return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1419 float functions::decodeFloat(const char* data)
1422 int ii = functions::decodeInteger(data);
1423 anna_memcpy(&result, &ii, sizeof(result));
1428 double functions::decodeDouble(const char* data)
1431 S64 ii = functions::decodeInteger64(data);
1432 anna_memcpy(&result, &ii, sizeof(result));
1438 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1439 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1441 isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1442 bool filler = isupNumber.OddEven;
1444 if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1445 throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1447 isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1448 isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1450 if(calledOrCalling) {
1451 isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1453 isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1454 isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1455 isupNumber.Screening = (short)(buffer[1] & 0x03);
1459 isupNumber.Digits = "";
1462 for(int k = 2; k < length; k ++) {
1463 byte = (buffer [k] & 0x0f);
1464 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1465 byte = (buffer [k] & 0xf0) >> 4;
1466 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1469 if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler
1473 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1475 if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1476 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1478 bool odd = isupNumber.OddEven;
1479 bool oddDigits = (isupNumber.Digits.size() % 2);
1481 if(odd != oddDigits)
1482 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1484 if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1485 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1487 if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1488 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1490 if(calledOrCalling) {
1491 if(isupNumber.NumberIncomplete != 0)
1492 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1494 if(isupNumber.AddressPresentationRestricted != 0)
1495 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1497 if(isupNumber.Screening != 0)
1498 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1500 if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1501 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1503 if(isupNumber.InternalNetworkNumber != 0)
1504 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1506 if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1507 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1509 if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1510 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1512 if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1513 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1518 bool filler = isupNumber.OddEven;
1519 bool hasDigits = (isupNumber.Digits.size() > 0);
1520 byte = filler ? 0x80 : 0x00;
1521 byte = byte |= isupNumber.NatureOfAddress;
1524 if(calledOrCalling) {
1525 byte = isupNumber.InternalNetworkNumber << 7;
1526 byte = byte |= (isupNumber.NumberingPlan << 4);
1528 byte = isupNumber.NumberIncomplete << 7;
1529 byte = byte |= (isupNumber.NumberingPlan << 4);
1530 byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1531 byte = byte |= isupNumber.Screening;
1537 std::string dtlc = isupNumber.Digits; // digits to lower case
1538 //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1539 const char *digits = dtlc.c_str();
1541 for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1542 if(isxdigit(byte = digits [k - 1]) == 0)
1543 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1545 hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1547 if(isxdigit(byte = digits [k]) == 0)
1548 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1550 hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1554 if(hasDigits && filler) {
1555 if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1556 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1558 target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1563 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1565 codeIsupNumber(isupNumber, calledOrCalling, target);
1566 length = target.size();
1567 memcpy(buffer, target.c_str(), length);