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 * Gets the original value obtained with #asHexString (const DataBlock&).
264 * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
265 * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
266 * \param target DataBlock for string decode.
267 * \return DataBlock corresponding to the provided string.
270 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
271 throw(RuntimeException) {
273 if((hexString.length() % 2) != 0)
274 throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
277 const char* src = hexString.data();
282 for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
283 if(isxdigit(aux = src [ii - 1]) == 0)
284 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
286 hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
288 if(isxdigit(aux = src [ii]) == 0)
289 throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
291 hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
298 string functions::asString(const char* format, ...)
302 va_start(ap, format);
303 vsnprintf(aux, sizeof(aux), format, ap);
308 void functions::sleep(const Millisecond &millisecond)
312 req.tv_sec = millisecond.getValue() / 1000; // segundos
313 req.tv_nsec = (millisecond.getValue() % 1000); // milisegundos
314 req.tv_nsec *= 1000000; // mili = 10e-3, nano=10-9
317 while((r = nanosleep(&req, &rem)) != 0) {
321 string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
322 msg += functions::asText("| nsec: ", (int) req.tv_nsec);
324 RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
331 bool functions::asBool(const char* str)
332 throw(RuntimeException) {
336 if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
339 if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
342 string msg("anna::funcions::asBool | Cannot interpret '");
344 msg += "' as boolean";
345 throw RuntimeException(msg, ANNA_FILE_LOCATION);
348 S64 functions::asInteger64(const char* str)
351 sscanf(str, "%lld", &number);
354 sscanf (str, "%ld", &number);
356 sscanf (str, "%lld", &number);
362 pthread_t functions::getCurrentThread()
364 WHEN_MULTITHREAD(return pthread_self());
365 WHEN_SINGLETHREAD(return 0);
368 bool functions::isLike(const char* pattern, const std::string& _value)
369 throw(RuntimeException) {
370 const char* value = _value.c_str();
374 if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
376 string msg("anna::functions::isLike | ");
377 msg += " | Pattern: ";
383 if(regerror(ret, &preg, err, sizeof(err)))
386 msg += "Invalid pattern";
388 throw RuntimeException(msg, ANNA_FILE_LOCATION);
391 const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
398 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
399 throw(RuntimeException) {
400 if(bitShift > intBitSize) {
401 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
402 throw RuntimeException(msg, ANNA_FILE_LOCATION);
405 if((bitsize(n1) + bitShift) > int64BitSize) {
406 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
407 throw RuntimeException(msg, ANNA_FILE_LOCATION);
410 if(bitsize(n2) > bitShift) {
411 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
412 throw RuntimeException(msg, ANNA_FILE_LOCATION);
419 if(bitShift == intBitSize) {
421 string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
422 msg += functions::asHexString(result);
423 Logger::information(msg, ANNA_FILE_LOCATION);
432 * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
434 int functions::log2(const unsigned int v)
436 static const char LogTable256[] = {
437 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
438 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
439 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
440 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
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 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
444 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
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,
451 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
452 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
454 int r = -1; // r will be lg(v)
455 unsigned int t, tt; // temporaries
458 r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
460 r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
466 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
468 std::string singular = (wordForSingular ? wordForSingular : "entry");
469 std::string plural = (wordForPlural ? wordForPlural : "entries");
471 if(wordForSingular && !wordForPlural)
472 plural = singular + "s";
474 result += ((number != 0) ? anna::functions::asString(number) : "no");
476 result += ((number != 1) ? plural : singular);
481 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
483 int d_size = title.size();
484 int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
487 if(mode == TextJustifyMode::Center) {
488 repeat = (repeat - 1) / 2;
489 adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
492 if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
493 for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
500 if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
503 for(int k = 0; k < repeat; k++) result += filler;
510 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
512 int ou_repeat = title.size();
513 int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
516 if(mode == TextHighlightMode::LeftAndRightline) {
517 lr_repeat = (lr_repeat - 1) / 2;
518 adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
521 if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
522 for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
527 if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
528 for(int k = 0; k < ou_repeat; k++) result += filler;
535 if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
538 for(int k = 0; k < ou_repeat; k++) result += filler;
541 if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
544 for(int k = 0; k < lr_repeat; k++) result += filler;
547 if(appendCR) result += "\n";
553 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
555 size_t pos, from = 0;
556 std::string tab, crTab = "\n";
558 for(int k = 0; k < tabSpaces; k++) tab += " ";
564 while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
565 result.replace(pos, 1, crTab);
573 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
576 if(pattern.size() < suffix.size()) return false;
578 size_t pos = pattern.rfind(suffix);
580 if(pos == std::string::npos) return false;
582 preffix.assign(pattern.c_str(), pos);
583 return (pos == (pattern.size() - suffix.size()));
587 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
590 if(pattern.size() < preffix.size()) return false;
592 if(pattern.find(preffix) != 0) return false;
594 suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
599 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
600 std::string result = text;
602 if(!item || !target) return result; // protection for NULL strings provided
604 size_t lengthReplaced = strlen(item);
605 size_t pos = result.find(item);
607 while(pos != std::string::npos) {
608 result.replace(pos, lengthReplaced, target);
612 pos = result.find(item);
619 std::string functions::addQuotationMarks(const std::string & str) throw() {
620 std::string result = "'";
627 std::string functions::addQuotationMarks(const char * str) throw() {
628 std::string result = "'";
629 result += (str ? str : "<null>");
635 std::string functions::addQuotationMarks(const int & integer) throw() {
636 std::string result = "'";
637 result += anna::functions::asString(integer);
643 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
644 std::string result = "";
647 std::vector<int>::const_iterator iter;
648 std::vector<int>::const_iterator iter_min(v.begin());
649 std::vector<int>::const_iterator iter_max(v.end());
651 for(iter = iter_min; iter != iter_max; iter++) {
652 result += anna::functions::asString(*iter);
656 // Delete the last space: starts at 'size()-1', take 1 caracter:
657 result.erase(result.size() - 1, 1);
664 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
665 std::string result = "";
668 std::vector<std::string>::const_iterator iter;
669 std::vector<std::string>::const_iterator iter_min(v.begin());
670 std::vector<std::string>::const_iterator iter_max(v.end());
672 for(iter = iter_min; iter != iter_max; iter++) {
677 // Delete the last space: starts at 'size()-1', take 1 caracter:
678 result.erase(result.size() - 1, 1);
685 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
686 std::string result = address;
688 result += anna::functions::asString(port);
693 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
695 // Supposed printable by default:
696 isFullyPrintable = true;
698 if(size == 0 || !buffer) {
700 isFullyPrintable = false;
704 for(int k = 0; k < size; k ++) {
705 unsigned char c = (unsigned char) buffer [k];
706 int printable = isprint(c);
707 result += (printable ? (char) c : '.');
709 if(!printable) isFullyPrintable = false;
716 std::string functions::getHostname() throw() {
718 std::string result = "<hostname>";
720 if(gethostname(aux, sizeof aux) == 0 /*success*/)
726 std::string functions::getDomainname() throw() {
728 std::string result = "<domainname>";
730 if(getdomainname(aux, sizeof aux) == 0 /*success*/)
736 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
737 std::string hn = hostname ? hostname : (functions::getHostname());
738 std::string dn = domainname ? domainname : (functions::getDomainname());
739 // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
741 if(hn == "") return dn;
743 if(dn == "") return hn;
745 std::string label(hn, 0, 63);
746 std::string fqdn(label + "." + dn, 0, 255);
750 std::string functions::getHostnameIP() throw() {
751 std::string result = "";
753 struct in_addr **addr_list;
754 struct in_addr ipv4addr;
756 gethostname(hostname, sizeof hostname);
758 if((he = gethostbyname(hostname)) != NULL) {
759 // Official name: he->h_name
761 addr_list = (struct in_addr **)he->h_addr_list;
763 for(int i = 0; addr_list[i] != NULL; i++) {
764 //printf("%s ", inet_ntoa(*addr_list[i]));
765 result = inet_ntoa(*addr_list[i]);
774 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
775 int length = rawPresentation.size();
777 if(length != 8 && length != 32)
778 throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
780 anna::DataBlock result(true);
782 char rByte[3]; // readable byte
785 for(int k = 0; k < length; k += 2) {
786 rByte[0] = rawPresentation[k];
787 rByte[1] = rawPresentation[k + 1];
788 sscanf(rByte, "%x", &byte);
796 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
797 int length = db.getSize();
799 if(length != 4 && length != 16)
800 throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
802 std::string result = "";
804 char rByte[3]; // readable byte
807 for(int k = 0; k < length; k++) {
808 byte = (unsigned char)db[k];
809 sprintf(rByte, "%.2X", byte);
821 // 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:
822 // A typical example of an IPv6 address is
823 // 2001:0db8:85a3:0000:0000:8a2e:0370:7334
824 // The hexadecimal digits are case-insensitive.
826 // The 128-bit IPv6 address can be abbreviated with the following rules:
827 // -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
828 // -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
829 // 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.
831 // 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.
832 // AsÃ, las siguientes son representaciones posibles de una misma dirección:
834 // 2001:0DB8:0000:0000:0000:0000:1428:57ab
835 // 2001:0DB8:0000:0000:0000::1428:57ab
836 // 2001:0DB8:0:0:0:0:1428:57ab
837 // 2001:0DB8:0::0:1428:57ab
838 // 2001:0DB8::1428:57ab
839 // son todas válidas y significan lo mismo, pero
842 // no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
844 // Los ceros iniciales en un grupo también se pueden omitir:
845 // 2001:0DB8:02de::0e13
848 // Si la dirección es una dirección IPv4 empotrada (mapped), los últimos 32 bits pueden escribirse en base decimal, asÃ:
849 // ::ffff:192.168.89.9
852 // No se debe confundir con:
856 // El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
857 // Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
858 // (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
859 // 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
860 // casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
862 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
864 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
865 if(ipv4Type == IPv4Type::Estrict) {
866 // La expresión regular no controla si hay mas de 3 puntos:
869 for(int k = 0; k < ip.length(); k++)
870 if(ip[k] == '.') n_dot++;
875 bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
876 bool colon = (ip.find(":") != std::string::npos);
877 return (ipv4 && !colon);
880 if(ipv4Type == IPv4Type::Compatible) {
881 std::string pureIPv4 = ip;
882 bool firstDoubleColon = (ip.find("::") == 0);
884 if(firstDoubleColon) {
885 pureIPv4.erase(0, 2);
886 bool anotherColon = (pureIPv4.find(":") != std::string::npos);
888 if(anotherColon) return (false);
890 return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
894 if(ipv4Type == IPv4Type::Mapped) {
895 size_t posLastColon = ip.rfind(":");
897 if(posLastColon == std::string::npos)
900 if(!isIPv4(ip.substr(posLastColon + 1)))
903 unsigned char buf[sizeof(struct in6_addr)];
904 int s = inet_pton(AF_INET6, ip.c_str(), buf);
914 bool functions::isIPv6(const std::string & ip) throw() {
915 // Chequeo de digitos permitidos:
916 for(int k = 0; k < ip.length(); k++) {
917 bool digit = isdigit(ip[k]);
918 bool hex = ((ip[k] == 'a') ||
930 bool colon = (ip[k] == ':');
932 if(!digit && !hex && !colon)
936 return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
940 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
941 if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
942 throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
944 std::string result, pureIPv4;
945 bool firstDoubleColon = (ip.find("::") == 0);
947 if(firstDoubleColon) {
949 size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
950 pureIPv4 = ip.substr(ipv4_pos);
953 size_t posColon = ip.find(":");
955 if(posColon == 0) // first colon
956 throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
958 if(posColon != std::string::npos) // any colon
959 return ip; // seems to be IPv6 already?
961 throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
967 // Number of ocurrences for '.'
970 for(int k = 0; k < pureIPv4.length(); k++)
971 if(pureIPv4[k] == '.') n_dot++;
974 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
977 anna::Tokenizer::const_iterator tok_it;
979 tok.apply(pureIPv4, ".");
983 for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
984 token = anna::Tokenizer::data(tok_it);
985 v[cnt] = atoi(anna::Tokenizer::data(tok_it));
987 if(v[cnt] < 0 || v[cnt] > 255)
988 throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
993 if(isIPv4(ip, IPv4Type::Compatible))
994 result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
996 result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
1002 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
1003 std::string result = ip;
1004 // std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
1005 std::transform(result.begin(), result.end(), result.begin(), ::tolower);
1007 if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
1008 result = IPv4To6(result);
1010 size_t pos = result.find("::"); // zeroes simplification group
1011 size_t rpos = result.rfind("::"); // zeroes simplification group
1014 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
1016 if(pos != std::string::npos) { // zeroes exists
1017 // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
1018 // Number of ocurrences for ':'
1021 for(int k = 0; k < result.length(); k++)
1022 if(result[k] == ':') n_colon++;
1024 // Generate equivalent to '::'
1025 std::string equiv_str;
1027 for(int k = 0; k < (8 - n_colon); k++)
1031 // Replace with equivalent:
1032 result.replace(pos, 2, equiv_str);
1034 // Special case: IP began with '::'
1035 if(result[0] == ':') {
1036 result.insert(0, "0");
1039 // Special case: IP was only '::'
1040 if(result[result.length() - 1] == ':') {
1045 // Protection: it must be seven colons:
1048 for(int k = 0; k < result.length(); k++)
1049 if(result[k] == ':') n_colon++;
1052 throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1054 // Padding with zeroes at left
1055 anna::Tokenizer ipStr;
1056 anna::Tokenizer::const_iterator ipStr_it;
1058 ipStr.apply(result, ":");
1061 for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1062 token = anna::Tokenizer::data(ipStr_it);
1064 while(token.length() < 4) token.insert(0, "0");
1071 size_t lastPos = result.length() - 1;
1072 result.erase(lastPos, 1);
1074 // Chequeo de digitos permitidos:
1075 for(int k = 0; k < result.length(); k++) {
1076 bool digit = isdigit(result[k]);
1077 bool hex = ((result[k] == 'a') ||
1078 (result[k] == 'b') ||
1079 (result[k] == 'c') ||
1080 (result[k] == 'd') ||
1081 (result[k] == 'e') ||
1082 (result[k] == 'f'));
1083 bool colon = (result[k] == ':');
1085 if(!digit && !hex && !colon) {
1086 throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1094 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1095 //if (ip1 == ip2) return true; it should validate wrong-format addresses
1096 return (normalizeIP(ip1) == normalizeIP(ip2));
1100 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1101 size_t preffixPos = preffixedIpv6.find("/");
1103 if(preffixPos == std::string::npos)
1104 return (sameIP(_ipv6, preffixedIpv6));
1106 std::string ipv6 = _ipv6;
1108 if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1110 std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1111 std::string ipv6_2 = _ipv6_2;
1113 if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1115 std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1116 int ipv6_2_preffixLength = atoi(preffix.c_str());
1118 if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1119 throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1121 // No restriction, all ipv6_2 ignored (special and not usual case)
1122 if(ipv6_2_preffixLength == 0) return true;
1125 int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1126 int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1127 int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1128 char mask = 0xFF << (8 - spare);
1130 anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1131 anna::DataBlock restrictedIP1(true);
1132 restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1134 if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1137 anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1138 anna::DataBlock realIP2(true);
1139 realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1141 if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1144 int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1149 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1150 anna::DataBlock result(true);
1153 unsigned char buf[sizeof(struct in6_addr)];
1154 int s = inet_pton(AF_INET, ip.c_str(), buf);
1157 result += (S8)buf[0];
1158 result += (S8)buf[1];
1159 result += (S8)buf[2];
1160 result += (S8)buf[3];
1162 if(s < 0) perror("inet_pton");
1164 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1167 unsigned char buf[sizeof(struct in6_addr)];
1168 int s = inet_pton(AF_INET6, ip.c_str(), buf);
1171 result += (S8)buf[0];
1172 result += (S8)buf[1];
1173 result += (S8)buf[2];
1174 result += (S8)buf[3];
1175 result += (S8)buf[4];
1176 result += (S8)buf[5];
1177 result += (S8)buf[6];
1178 result += (S8)buf[7];
1179 result += (S8)buf[8];
1180 result += (S8)buf[9];
1181 result += (S8)buf[10];
1182 result += (S8)buf[11];
1183 result += (S8)buf[12];
1184 result += (S8)buf[13];
1185 result += (S8)buf[14];
1186 result += (S8)buf[15];
1188 if(s < 0) perror("inet_pton");
1190 throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1196 // anna::DataBlock result(true);
1199 // if (isIPv4(ip)) {
1201 // 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/)
1202 // sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1203 // result += (S8)dec1;
1204 // result += (S8)dec2;
1205 // result += (S8)dec3;
1206 // result += (S8)dec4;
1210 // 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/)
1211 // sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1212 // result += ((S8)(hex1 >> 8));
1213 // result += ((S8)(hex1 & 0x00FF));
1214 // result += ((S8)(hex2 >> 8));
1215 // result += ((S8)(hex2 & 0x00FF));
1216 // result += ((S8)(hex3 >> 8));
1217 // result += ((S8)(hex3 & 0x00FF));
1218 // result += ((S8)(hex4 >> 8));
1219 // result += ((S8)(hex4 & 0x00FF));
1220 // result += ((S8)(hex5 >> 8));
1221 // result += ((S8)(hex5 & 0x00FF));
1222 // result += ((S8)(hex6 >> 8));
1223 // result += ((S8)(hex6 & 0x00FF));
1224 // result += ((S8)(hex7 >> 8));
1225 // result += ((S8)(hex7 & 0x00FF));
1226 // result += ((S8)(hex8 >> 8));
1227 // result += ((S8)(hex8 & 0x00FF));
1235 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1236 std::string result = "";
1237 char str[INET6_ADDRSTRLEN];
1239 if(bufferLength == 4) {
1240 if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1242 } else if(bufferLength == 16) {
1243 if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1246 throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1249 throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1251 return (normalize ? normalizeIP(result) : result);
1253 // std::string result;
1256 // if (bufferLength == 4) { // IPv4
1257 // result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1259 // else if (bufferLength == 16) { // IPv6
1260 // result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1261 // ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1262 // (((U8)buffer[1]) & 0x00FF),
1263 // ((((U8)buffer[2]) << 8) & 0xFF00) +
1264 // (((U8)buffer[3]) & 0x00FF),
1265 // ((((U8)buffer[4]) << 8) & 0xFF00) +
1266 // (((U8)buffer[5]) & 0x00FF),
1267 // ((((U8)buffer[6]) << 8) & 0xFF00) +
1268 // (((U8)buffer[7]) & 0x00FF),
1269 // ((((U8)buffer[8]) << 8) & 0xFF00) +
1270 // (((U8)buffer[9]) & 0x00FF),
1271 // ((((U8)buffer[10]) << 8) & 0xFF00) +
1272 // (((U8)buffer[11]) & 0x00FF),
1273 // ((((U8)buffer[12]) << 8) & 0xFF00) +
1274 // (((U8)buffer[13]) & 0x00FF),
1275 // ((((U8)buffer[14]) << 8) & 0xFF00) +
1276 // (((U8)buffer[15]) & 0x00FF));
1279 // throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1282 // return (normalize ? normalizeIP(result):result);
1286 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1287 size_t pos = literal.find_last_of(":");
1288 size_t lastPos = literal.size() - 1;
1289 address = ""; port = -1; // assume error
1291 if((pos != std::string::npos) && (pos != lastPos)) {
1292 address = literal.substr(0, pos);
1293 port = atoi(literal.substr(pos + 1, lastPos).c_str());
1298 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1300 std::string address;
1302 anna::Tokenizer lst;
1303 lst.apply(list, ",");
1305 if(lst.size() < 1) return result;
1307 anna::Tokenizer::const_iterator tok_min(lst.begin());
1308 anna::Tokenizer::const_iterator tok_max(lst.end());
1309 anna::Tokenizer::const_iterator tok_iter;
1311 for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1312 getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1314 if(port == -1) { result.clear(); return result; }
1316 result.push_back(socket_t(address, port));
1322 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1325 socket_v_it it_min(socketVector.begin());
1326 socket_v_it it_max(socketVector.end());
1328 for(it = it_min; it != it_max; it++) {
1329 result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1332 result.erase(result.size() - 1, 1); // remove last comma
1336 bool functions::littleEndian()
1339 char *p = (char *) &i;
1340 if (p[0] == 1) return true;
1344 const char* functions::codeInteger(char* result, const int n)
1347 char* w((char*) &aux);
1349 *(result + 1) = *(w + 1);
1350 *(result + 2) = *(w + 2);
1351 *(result + 3) = *(w + 3);
1355 const char* functions::codeShort(char* result, const short int n)
1357 short int aux(htons(n));
1358 char* w((char*) &aux);
1360 *(result + 1) = *(w + 1);
1364 const char* functions::codeInteger64(char* result, const S64 n)
1366 S64 aux(0xffffffff);
1370 n2 = (aux >> 32) & 0xffffffff;
1371 codeInteger(result, n2);
1372 n2 = n & 0xffffffff;
1373 codeInteger(result + sizeof(int), n2);
1378 const char* functions::codeFloat(char* result, const float n)
1381 anna_memcpy(&ii, &n, sizeof(n));
1382 return functions::codeInteger(result, ii);
1386 const char* functions::codeDouble(char* result, const double n)
1389 anna_memcpy(&ii, &n, sizeof(n));
1390 return functions::codeInteger64(result, ii);
1393 int functions::decodeInteger(const char* data)
1396 char* w((char*) &result);
1398 *(w + 1) = *(data + 1);
1399 *(w + 2) = *(data + 2);
1400 *(w + 3) = *(data + 3);
1401 return ntohl(result);
1404 short int functions::decodeShort(const char* data)
1407 char* w((char*) &result);
1409 *(w + 1) = *(data + 1);
1410 return ntohs(result);
1413 S64 functions::decodeInteger64(const char* data)
1415 S64 result(decodeInteger(data));
1417 return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1421 float functions::decodeFloat(const char* data)
1424 int ii = functions::decodeInteger(data);
1425 anna_memcpy(&result, &ii, sizeof(result));
1430 double functions::decodeDouble(const char* data)
1433 S64 ii = functions::decodeInteger64(data);
1434 anna_memcpy(&result, &ii, sizeof(result));
1440 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1441 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1443 isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1444 bool filler = isupNumber.OddEven;
1446 if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1447 throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1449 isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1450 isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1452 if(calledOrCalling) {
1453 isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1455 isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1456 isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1457 isupNumber.Screening = (short)(buffer[1] & 0x03);
1461 isupNumber.Digits = "";
1464 for(int k = 2; k < length; k ++) {
1465 byte = (buffer [k] & 0x0f);
1466 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1467 byte = (buffer [k] & 0xf0) >> 4;
1468 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1471 if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler
1475 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1477 if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1478 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1480 bool odd = isupNumber.OddEven;
1481 bool oddDigits = (isupNumber.Digits.size() % 2);
1483 if(odd != oddDigits)
1484 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1486 if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1487 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1489 if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1490 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1492 if(calledOrCalling) {
1493 if(isupNumber.NumberIncomplete != 0)
1494 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1496 if(isupNumber.AddressPresentationRestricted != 0)
1497 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1499 if(isupNumber.Screening != 0)
1500 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1502 if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1503 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1505 if(isupNumber.InternalNetworkNumber != 0)
1506 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1508 if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1509 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1511 if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1512 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1514 if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1515 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1520 bool filler = isupNumber.OddEven;
1521 bool hasDigits = (isupNumber.Digits.size() > 0);
1522 byte = filler ? 0x80 : 0x00;
1523 byte = byte |= isupNumber.NatureOfAddress;
1526 if(calledOrCalling) {
1527 byte = isupNumber.InternalNetworkNumber << 7;
1528 byte = byte |= (isupNumber.NumberingPlan << 4);
1530 byte = isupNumber.NumberIncomplete << 7;
1531 byte = byte |= (isupNumber.NumberingPlan << 4);
1532 byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1533 byte = byte |= isupNumber.Screening;
1539 std::string dtlc = isupNumber.Digits; // digits to lower case
1540 //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1541 const char *digits = dtlc.c_str();
1543 for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1544 if(isxdigit(byte = digits [k - 1]) == 0)
1545 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1547 hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1549 if(isxdigit(byte = digits [k]) == 0)
1550 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1552 hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1556 if(hasDigits && filler) {
1557 if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1558 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1560 target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1565 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1567 codeIsupNumber(isupNumber, calledOrCalling, target);
1568 length = target.size();
1569 memcpy(buffer, target.c_str(), length);