1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
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 Google Inc. 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((Unsigned64)number);
127 string functions::asString(const Integer64 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 Unsigned64 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((Integer64)number);
209 string functions::asHexString(const Integer64 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 Integer64 functions::hash(const char* p)
227 static const int long_bits = sizeof(Integer64) << 3;
228 static const int one_eighth = long_bits >> 3;
229 static const int three_fourths = long_bits * 3 / 4;
230 static const Integer64 high_bits = ((Integer64)(~0L)) << (long_bits - one_eighth);
231 Integer64 result = 0;
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(register 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 Integer64 functions::asInteger64(const char* str)
348 Integer64 number = 0;
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 Integer64 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);
413 Integer64 result = n1;
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 register 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(register int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
498 if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
501 for(register 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(register int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
525 if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
526 for(register int k = 0; k < ou_repeat; k++) result += filler;
533 if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
536 for(register int k = 0; k < ou_repeat; k++) result += filler;
539 if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
542 for(register 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(register 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(register 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(register 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(register 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(register 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(register 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(register 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(register int k = 0; k < result.length(); k++)
1020 if(result[k] == ':') n_colon++;
1022 // Generate equivalent to '::'
1023 std::string equiv_str;
1025 for(register 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(register 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(register 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
1335 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1336 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1338 isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1339 bool filler = isupNumber.OddEven;
1341 if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1342 throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1344 isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1345 isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1347 if(calledOrCalling) {
1348 isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1350 isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1351 isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1352 isupNumber.Screening = (short)(buffer[1] & 0x03);
1356 isupNumber.Digits = "";
1359 for(register int k = 2; k < length; k ++) {
1360 byte = (buffer [k] & 0x0f);
1361 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1362 byte = (buffer [k] & 0xf0) >> 4;
1363 isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1366 if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1); // remove filler
1370 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1372 if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1373 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1375 bool odd = isupNumber.OddEven;
1376 bool oddDigits = (isupNumber.Digits.size() % 2);
1378 if(odd != oddDigits)
1379 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1381 if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1382 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1384 if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1385 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1387 if(calledOrCalling) {
1388 if(isupNumber.NumberIncomplete != 0)
1389 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1391 if(isupNumber.AddressPresentationRestricted != 0)
1392 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1394 if(isupNumber.Screening != 0)
1395 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1397 if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1398 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1400 if(isupNumber.InternalNetworkNumber != 0)
1401 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1403 if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1404 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1406 if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1407 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1409 if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1410 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1415 bool filler = isupNumber.OddEven;
1416 bool hasDigits = (isupNumber.Digits.size() > 0);
1417 byte = filler ? 0x80 : 0x00;
1418 byte = byte |= isupNumber.NatureOfAddress;
1421 if(calledOrCalling) {
1422 byte = isupNumber.InternalNetworkNumber << 7;
1423 byte = byte |= (isupNumber.NumberingPlan << 4);
1425 byte = isupNumber.NumberIncomplete << 7;
1426 byte = byte |= (isupNumber.NumberingPlan << 4);
1427 byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1428 byte = byte |= isupNumber.Screening;
1434 std::string dtlc = isupNumber.Digits; // digits to lower case
1435 //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1436 const char *digits = dtlc.c_str();
1438 for(register int k = 1; k < isupNumber.Digits.size(); k += 2) {
1439 if(isxdigit(byte = digits [k - 1]) == 0)
1440 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1442 hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1444 if(isxdigit(byte = digits [k]) == 0)
1445 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1447 hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1451 if(hasDigits && filler) {
1452 if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1453 throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1455 target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1460 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1462 codeIsupNumber(isupNumber, calledOrCalling, target);
1463 length = target.size();
1464 memcpy(buffer, target.c_str(), length);