Updated license
[anna.git] / source / core / functions.cpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
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
16 // distribution.
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.
20 //
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.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <stdarg.h>
38 #include <ctype.h>
39 #include <poll.h>
40 #include <time.h>
41 #include <sys/time.h>
42 #include <pthread.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <sys/types.h>
46 #include <regex.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
53
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>
59
60 #include <algorithm>
61
62
63 using namespace anna;
64 using namespace std;
65
66 #define PAGE_WIDTH_LENGTH      80
67
68 ExclusiveHash <std::string> functions::st_stringExclusiveHash;
69 ExclusiveHash <std::string, int> functions::st_string2intExclusiveHash;
70
71 string functions::getVersion() throw() {
72   static const int version = ANNA_VERSION;
73   string result;
74   int mainVersion = (version & 0xff00) >> 8;
75   int subVersion = (version & 0xff);
76   char aux [32];
77   sprintf(aux, "%d.%d", mainVersion, subVersion);
78   result = aux;
79   return result += getArchitecture();
80 }
81
82 /*
83 (1) Solo coge los dos primeros digitos del numero de release
84 */
85 string functions::getArchitecture() throw() {
86   string result;
87   WHEN_MULTITHREAD(result = "/MT");
88   WHEN_SINGLETHREAD(result = "/ST");
89 #ifdef _DEBUG
90   result += "/D";
91 #else
92   result += "/O";
93 #endif
94 #ifdef _PROFILE
95   result += 'P';
96 #endif
97   struct utsname un;
98   uname(&un);
99   result += '/';
100   result += un.sysname;
101   result += ' ';
102   char* release = anna_strchr(un.release, '.');               // (1)
103
104   if(release != NULL)
105     if((release = anna_strchr(release + 1, '.')) != NULL)
106       * release = 0;
107
108   result += un.release;
109   result += " (";
110   result += un.machine;
111   result += ")";
112   return result;
113 }
114
115 string functions::asString(const int number)
116 throw() {
117   char aux [16];
118   sprintf(aux, "%d", number);
119   return string(aux);
120 }
121
122 string functions::asString(const unsigned long number)
123 throw() {
124   return asString((U64)number);
125 }
126
127 string functions::asString(const S64 number)
128 throw() {
129   char aux [24];
130   sprintf(aux, "%lld", number);
131   /*#ifdef __anna64__
132      sprintf (aux, "%ld", number);
133   #else
134      sprintf (aux, "%lld", number);
135   #endif
136   */
137   return string(aux);
138 }
139
140 string functions::asString(const unsigned int number)
141 throw() {
142   char aux [16];
143   sprintf(aux, "%u", number);
144   return string(aux);
145 }
146
147 string functions::asString(const U64 number)
148 throw() {
149   char aux [16];
150   sprintf(aux, "%llu", number);
151   /*
152   #ifdef __anna64__
153      sprintf (aux, "%lu", number);
154   #else
155      sprintf (aux, "%llu", number);
156   #endif
157   */
158   return string(aux);
159 }
160
161 string functions::asString(const float number, const char* format)
162 throw() {
163   char aux [64];
164   sprintf(aux, format, number);
165   return string(aux);
166 }
167
168 string functions::asString(const double number, const char* format)
169 throw() {
170   char aux [64];
171   sprintf(aux, format, number);
172   return string(aux);
173 }
174
175 string functions::asDateTime(const Second &second)
176 throw() {
177   char aux [DateTimeSizeString];
178   return std::string(asDateTime(second, aux));
179 }
180
181 const char* functions::asDateTime(const Second &second, char* result)
182 throw() {
183   struct tm* tt = localtime((time_t*) & second);
184   sprintf(
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
188   );
189   return result;
190 }
191
192 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
193 throw() {
194   return dataBlock.asString(characterByLine);
195 }
196
197 string functions::asHexString(const int number)
198 throw() {
199   char aux [16];
200   sprintf(aux, "0x%x", number);
201   return string(aux);
202 }
203
204 string functions::asHexString(const long number)
205 throw() {
206   return asHexString((S64)number);
207 }
208
209 string functions::asHexString(const S64 number)
210 throw() {
211   char aux [32];
212   sprintf(aux, "0x%llx", number);
213   /*
214   #ifdef __anna64__
215      sprintf (aux, "0x%lx", number);
216   #else
217      sprintf (aux, "0x%llx", number);
218   #endif
219   */
220   return string(aux);
221 }
222
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)
226 throw() {
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);
231   S64 result = 0;
232   S64 temp;
233
234   while(*p != 0) {
235     result = (result << one_eighth) + *p ++;
236
237     if((temp = result & high_bits) != 0)
238       result = (result ^(temp >> three_fourths)) &~ high_bits;
239   }
240
241   return result;
242 }
243
244 //static
245 std::string functions::asHexString(const DataBlock& dataBlock)
246 throw() {
247   const char* buffer = dataBlock.getData();
248   const int size = dataBlock.getSize();
249   string result;
250   int byte;
251
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');
257   }
258
259   return result;
260 }
261
262 /**
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.
267  */
268 //static
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);
273
274   target.clear();
275   const char* src = hexString.data();
276   unsigned char hex;
277   int aux;
278   int j = 0;
279
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);
283
284     hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
285
286     if(isxdigit(aux = src [ii]) == 0)
287       throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
288
289     hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
290     target += hex;
291   }
292
293   return target;
294 }
295
296 string functions::asString(const char* format, ...)
297 throw() {
298   va_list ap;
299   char aux [1024];
300   va_start(ap, format);
301   vsnprintf(aux, sizeof(aux), format, ap);
302   va_end(ap);
303   return string(aux);
304 }
305
306 void functions::sleep(const Millisecond &millisecond)
307 throw() {
308   timespec req;
309   timespec rem;
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
313   int r;
314
315   while((r = nanosleep(&req, &rem)) != 0) {
316     if(errno == EINTR)
317       req = rem;
318     else {
319       string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
320       msg += functions::asText("| nsec: ", (int) req.tv_nsec);
321       msg += " }";
322       RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
323       ex.trace();
324       break;
325     }
326   }
327 }
328
329 bool functions::asBool(const char* str)
330 throw(RuntimeException) {
331   if(str == NULL)
332     return false;
333
334   if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
335     return true;
336
337   if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
338     return false;
339
340   string msg("anna::funcions::asBool | Cannot interpret '");
341   msg += str;
342   msg += "' as boolean";
343   throw RuntimeException(msg, ANNA_FILE_LOCATION);
344 }
345
346 S64 functions::asInteger64(const char* str)
347 throw() {
348   S64 number = 0;
349   sscanf(str, "%lld", &number);
350   /*
351   #ifdef __anna64__
352     sscanf (str, "%ld", &number);
353   #else
354      sscanf (str, "%lld", &number);
355   #endif
356   */
357   return number;
358 }
359
360 pthread_t functions::getCurrentThread()
361 throw() {
362   WHEN_MULTITHREAD(return pthread_self());
363   WHEN_SINGLETHREAD(return 0);
364 }
365
366 bool functions::isLike(const char* pattern, const std::string& _value)
367 throw(RuntimeException) {
368   const char* value = _value.c_str();
369   regex_t preg;
370   int ret;
371
372   if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
373     char err[256];
374     string msg("anna::functions::isLike | ");
375     msg += " | Pattern: ";
376     msg += pattern;
377     msg += " | Value: ";
378     msg += value;
379     msg += " | ";
380
381     if(regerror(ret, &preg, err, sizeof(err)))
382       msg += err;
383     else
384       msg += "Invalid pattern";
385
386     throw RuntimeException(msg, ANNA_FILE_LOCATION);
387   }
388
389   const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
390
391   regfree(&preg);
392   return result;
393 }
394
395 /*static*/
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);
401   }
402
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);
406   }
407
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);
411   }
412
413   S64 result = n1;
414   result <<= bitShift;
415   result |= n2;
416
417   if(bitShift == intBitSize) {
418     LOGINFORMATION(
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);
422     );
423   }
424
425   return result;
426 }
427
428 /*static*/
429 /*
430  * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
431  */
432 int functions::log2(const unsigned int v)
433 throw() {
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
451   };
452   int r = -1;     // r will be lg(v)
453   register unsigned int t, tt; // temporaries
454
455   if(tt = v >> 16) {
456     r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
457   } else {
458     r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
459   }
460
461   return r;
462 }
463
464 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
465   std::string result;
466   std::string singular = (wordForSingular ? wordForSingular : "entry");
467   std::string plural = (wordForPlural ? wordForPlural : "entries");
468
469   if(wordForSingular && !wordForPlural)
470     plural = singular + "s";
471
472   result += ((number != 0) ? anna::functions::asString(number) : "no");
473   result += " ";
474   result += ((number != 1) ? plural : singular);
475   return result;
476 }
477
478
479 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
480   std::string result;
481   int d_size = title.size();
482   int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
483   bool adjust = false;
484
485   if(mode == TextJustifyMode::Center) {
486     repeat = (repeat - 1) / 2;
487     adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
488   }
489
490   if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
491     for(register int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
492
493     result += " ";
494   }
495
496   result += title;
497
498   if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
499     result += " ";
500
501     for(register int k = 0; k < repeat; k++) result += filler;
502   }
503
504   return result;
505 }
506
507
508 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
509   std::string result;
510   int ou_repeat = title.size();
511   int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
512   bool adjust = false;
513
514   if(mode == TextHighlightMode::LeftAndRightline) {
515     lr_repeat = (lr_repeat - 1) / 2;
516     adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
517   }
518
519   if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
520     for(register int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
521
522     result += " ";
523   }
524
525   if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
526     for(register int k = 0; k < ou_repeat; k++) result += filler;
527
528     result += "\n";
529   }
530
531   result += title;
532
533   if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
534     result += "\n";
535
536     for(register int k = 0; k < ou_repeat; k++) result += filler;
537   }
538
539   if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
540     result += " ";
541
542     for(register int k = 0; k < lr_repeat; k++) result += filler;
543   }
544
545   if(appendCR) result += "\n";
546
547   return result;
548 }
549
550
551 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
552   std::string result;
553   size_t pos, from = 0;
554   std::string tab, crTab = "\n";
555
556   for(register int k = 0; k < tabSpaces; k++) tab += " ";
557
558   crTab += tab;
559   result = tab;
560   result += text;
561
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);
564     from = pos + 1;
565   }
566
567   return result;
568 }
569
570
571 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
572   preffix = "";
573
574   if(pattern.size() < suffix.size()) return false;
575
576   size_t pos = pattern.rfind(suffix);
577
578   if(pos == std::string::npos) return false;
579
580   preffix.assign(pattern.c_str(), pos);
581   return (pos == (pattern.size() - suffix.size()));
582 }
583
584
585 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
586   suffix = "";
587
588   if(pattern.size() < preffix.size()) return false;
589
590   if(pattern.find(preffix) != 0) return false;
591
592   suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
593   return true;
594 }
595
596
597 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
598   std::string result = text;
599
600   if(!item || !target) return result;  // protection for NULL strings provided
601
602   size_t lengthReplaced = strlen(item);
603   size_t pos = result.find(item);
604
605   while(pos != std::string::npos) {
606     result.replace(pos, lengthReplaced, target);
607
608     if(!all) break;
609
610     pos = result.find(item);
611   }
612
613   return result;
614 }
615
616
617 std::string functions::addQuotationMarks(const std::string & str) throw() {
618   std::string result = "'";
619   result += str;
620   result += "'";
621   return (result);
622 }
623
624
625 std::string functions::addQuotationMarks(const char * str) throw() {
626   std::string result = "'";
627   result += (str ? str : "<null>");
628   result += "'";
629   return (result);
630 }
631
632
633 std::string functions::addQuotationMarks(const int & integer) throw() {
634   std::string result = "'";
635   result += anna::functions::asString(integer);
636   result += "'";
637   return (result);
638 }
639
640
641 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
642   std::string result = "";
643
644   if(v.size() != 0) {
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());
648
649     for(iter = iter_min; iter != iter_max; iter++) {
650       result += anna::functions::asString(*iter);
651       result += separator;
652     }
653
654     // Delete the last space: starts at 'size()-1', take 1 caracter:
655     result.erase(result.size() - 1, 1);
656   }
657
658   return (result);
659 }
660
661
662 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
663   std::string result = "";
664
665   if(v.size() != 0) {
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());
669
670     for(iter = iter_min; iter != iter_max; iter++) {
671       result += (*iter);
672       result += separator;
673     }
674
675     // Delete the last space: starts at 'size()-1', take 1 caracter:
676     result.erase(result.size() - 1, 1);
677   }
678
679   return (result);
680 }
681
682
683 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
684   std::string result = address;
685   result += ":";
686   result += anna::functions::asString(port);
687   return result;
688 }
689
690
691 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
692   std::string result;
693   // Supposed printable by default:
694   isFullyPrintable = true;
695
696   if(size == 0 || !buffer) {
697     result = "<null>";
698     isFullyPrintable = false;
699     return result;
700   }
701
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 : '.');
706
707     if(!printable) isFullyPrintable = false;
708   }
709
710   return result;
711 }
712
713
714 std::string functions::getHostname() throw() {
715   char aux[255];
716   std::string result = "<hostname>";
717
718   if(gethostname(aux, sizeof aux) == 0 /*success*/)
719     result = aux;
720
721   return result;
722 }
723
724 std::string functions::getDomainname() throw() {
725   char aux[256];
726   std::string result = "<domainname>";
727
728   if(getdomainname(aux, sizeof aux) == 0 /*success*/)
729     result = aux;
730
731   return result;
732 }
733
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.
738
739   if(hn == "") return dn;
740
741   if(dn == "") return hn;
742
743   std::string label(hn, 0, 63);
744   std::string fqdn(label + "." + dn, 0, 255);
745   return fqdn;
746 }
747
748 std::string functions::getHostnameIP() throw() {
749   std::string result = "";
750   struct hostent *he;
751   struct in_addr **addr_list;
752   struct in_addr ipv4addr;
753   char hostname[128];
754   gethostname(hostname, sizeof hostname);
755
756   if((he = gethostbyname(hostname)) != NULL) {
757     // Official name: he->h_name
758     // IP addresses:
759     addr_list = (struct in_addr **)he->h_addr_list;
760
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]);
764       return result;
765     }
766   }
767
768   return result;
769 }
770
771
772 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
773   int length = rawPresentation.size();
774
775   if(length != 8 && length != 32)
776     throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
777
778   anna::DataBlock result(true);
779   int byte;
780   char rByte[3]; // readable byte
781   rByte[2] = 0;
782
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);
787     result += byte;
788   }
789
790   return result;
791 }
792
793
794 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
795   int length = db.getSize();
796
797   if(length != 4 && length != 16)
798     throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
799
800   std::string result = "";
801   int byte;
802   char rByte[3]; // readable byte
803   rByte[2] = 0;
804
805   for(register int k = 0; k < length; k++) {
806     byte = (unsigned char)db[k];
807     sprintf(rByte, "%.2X", byte);
808     result += rByte;
809   }
810
811   return result;
812 }
813
814
815
816 ////////////////////
817 // Address Format //
818 ////////////////////
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.
823 //
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.
828
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:
831 //
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
838 //      2001::25de::cade
839 //          --    --
840 //      no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
841 //
842 //      Los ceros iniciales en un grupo también se pueden omitir:
843 //      2001:0DB8:02de::0e13
844 //      2001:DB8:2de::e13
845 //
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
848 //      ::ffff:c0a8:5909
849 //
850 //      No se debe confundir con:
851 //      ::192.168.89.9
852 //      ::c0a8:5909
853 //
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.
859 //
860 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
861
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:
865     int n_dot = 0;
866
867     for(register int k = 0; k < ip.length(); k++)
868       if(ip[k] == '.') n_dot++;
869
870     if(n_dot > 3)
871       return (false);
872
873     bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
874     bool colon = (ip.find(":") != std::string::npos);
875     return (ipv4 && !colon);
876   }
877
878   if(ipv4Type == IPv4Type::Compatible) {
879     std::string pureIPv4 = ip;
880     bool firstDoubleColon = (ip.find("::") == 0);
881
882     if(firstDoubleColon) {
883       pureIPv4.erase(0, 2);
884       bool anotherColon = (pureIPv4.find(":") != std::string::npos);
885
886       if(anotherColon) return (false);
887
888       return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
889     }
890   }
891
892   if(ipv4Type == IPv4Type::Mapped) {
893     size_t posLastColon = ip.rfind(":");
894
895     if(posLastColon == std::string::npos)
896       return (false);
897
898     if(!isIPv4(ip.substr(posLastColon + 1)))
899       return (false);
900
901     unsigned char buf[sizeof(struct in6_addr)];
902     int s = inet_pton(AF_INET6, ip.c_str(), buf);
903
904     if(s > 0)
905       return (true);
906   }
907
908   return false;
909 }
910
911
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') ||
917                 (ip[k] == 'b') ||
918                 (ip[k] == 'c') ||
919                 (ip[k] == 'd') ||
920                 (ip[k] == 'e') ||
921                 (ip[k] == 'f') ||
922                 (ip[k] == 'A') ||
923                 (ip[k] == 'B') ||
924                 (ip[k] == 'C') ||
925                 (ip[k] == 'D') ||
926                 (ip[k] == 'E') ||
927                 (ip[k] == 'F'));
928     bool colon = (ip[k] == ':');
929
930     if(!digit && !hex && !colon)
931       return false;
932   }
933
934   return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
935 }
936
937
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);
941
942   std::string result, pureIPv4;
943   bool firstDoubleColon = (ip.find("::") == 0);
944
945   if(firstDoubleColon) {
946     // Clean '::'
947     size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
948     pureIPv4 = ip.substr(ipv4_pos);
949   } else {
950     if(!isIPv4(ip)) {
951       size_t posColon = ip.find(":");
952
953       if(posColon == 0)  // first colon
954         throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
955
956       if(posColon != std::string::npos)  // any colon
957         return ip; // seems to be IPv6 already?
958
959       throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
960     }
961
962     pureIPv4 = ip;
963   }
964
965   // Number of ocurrences for '.'
966   int n_dot = 0;
967
968   for(register int k = 0; k < pureIPv4.length(); k++)
969     if(pureIPv4[k] == '.') n_dot++;
970
971   if(n_dot > 3)
972     throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
973
974   anna::Tokenizer tok;
975   anna::Tokenizer::const_iterator tok_it;
976   std::string token;
977   tok.apply(pureIPv4, ".");
978   int v[4];
979   int cnt = 0;
980
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));
984
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);
987
988     cnt++;
989   }
990
991   if(isIPv4(ip, IPv4Type::Compatible))
992     result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
993   else
994     result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
995
996   return result;
997 }
998
999
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);
1004
1005   if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
1006     result = IPv4To6(result);
1007
1008   size_t pos = result.find("::"); // zeroes simplification group
1009   size_t rpos = result.rfind("::"); // zeroes simplification group
1010
1011   if(pos != rpos)
1012     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
1013
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 ':'
1017     int n_colon = 0;
1018
1019     for(register int k = 0; k < result.length(); k++)
1020       if(result[k] == ':') n_colon++;
1021
1022     // Generate equivalent to '::'
1023     std::string equiv_str;
1024
1025     for(register int k = 0; k < (8 - n_colon); k++)
1026       equiv_str += ":0";
1027
1028     equiv_str += ":";
1029     // Replace with equivalent:
1030     result.replace(pos, 2, equiv_str);
1031
1032     // Special case: IP began with '::'
1033     if(result[0] == ':') {
1034       result.insert(0, "0");
1035     }
1036
1037     // Special case: IP was only '::'
1038     if(result[result.length() - 1] == ':') {
1039       result += "0";
1040     }
1041   }
1042
1043   // Protection: it must be seven colons:
1044   int n_colon = 0;
1045
1046   for(register int k = 0; k < result.length(); k++)
1047     if(result[k] == ':') n_colon++;
1048
1049   if(n_colon != 7)
1050     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1051
1052   // Padding with zeroes at left
1053   anna::Tokenizer ipStr;
1054   anna::Tokenizer::const_iterator ipStr_it;
1055   std::string token;
1056   ipStr.apply(result, ":");
1057   result = "";
1058
1059   for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1060     token = anna::Tokenizer::data(ipStr_it);
1061
1062     while(token.length() < 4) token.insert(0, "0");
1063
1064     result += token;
1065     result += ":";
1066   }
1067
1068   // Remove last ':'
1069   size_t lastPos = result.length() - 1;
1070   result.erase(lastPos, 1);
1071
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] == ':');
1082
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);
1085     }
1086   }
1087
1088   return result;
1089 }
1090
1091
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));
1095 }
1096
1097
1098 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1099   size_t preffixPos = preffixedIpv6.find("/");
1100
1101   if(preffixPos == std::string::npos)
1102     return (sameIP(_ipv6, preffixedIpv6));
1103
1104   std::string ipv6 = _ipv6;
1105
1106   if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1107
1108   std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1109   std::string ipv6_2 = _ipv6_2;
1110
1111   if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1112
1113   std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1114   int ipv6_2_preffixLength = atoi(preffix.c_str());
1115
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);
1118
1119   // No restriction, all ipv6_2 ignored (special and not usual case)
1120   if(ipv6_2_preffixLength == 0) return true;
1121
1122   // Auxiliary data:
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);
1127   // Limit ipv6
1128   anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1129   anna::DataBlock restrictedIP1(true);
1130   restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1131
1132   if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1133
1134   // Limit ipv6_2
1135   anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1136   anna::DataBlock realIP2(true);
1137   realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1138
1139   if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1140
1141   // Comparison
1142   int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1143   return (n == 0);
1144 }
1145
1146
1147 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1148   anna::DataBlock result(true);
1149
1150   if(isIPv4(ip)) {
1151     unsigned char buf[sizeof(struct in6_addr)];
1152     int s = inet_pton(AF_INET, ip.c_str(), buf);
1153
1154     if(s > 0) {
1155       result += (S8)buf[0];
1156       result += (S8)buf[1];
1157       result += (S8)buf[2];
1158       result += (S8)buf[3];
1159     } else {
1160       if(s < 0) perror("inet_pton");
1161
1162       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1163     }
1164   } else {
1165     unsigned char buf[sizeof(struct in6_addr)];
1166     int s = inet_pton(AF_INET6, ip.c_str(), buf);
1167
1168     if(s > 0) {
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];
1185     } else {
1186       if(s < 0) perror("inet_pton");
1187
1188       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1189     }
1190   }
1191
1192   return result;
1193   // Alternativa
1194   //   anna::DataBlock result(true);
1195   //
1196   //
1197   //   if (isIPv4(ip)) {
1198   //
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;
1205   //   }
1206   //   else {
1207   //
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));
1226   //   }
1227   //
1228   //
1229   //   return result;
1230 }
1231
1232
1233 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1234   std::string result = "";
1235   char str[INET6_ADDRSTRLEN];
1236
1237   if(bufferLength == 4) {
1238     if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1239       result = str;
1240   } else if(bufferLength == 16) {
1241     if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1242       result = str;
1243   } else
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);
1245
1246   if(result == "")
1247     throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1248
1249   return (normalize ? normalizeIP(result) : result);
1250   // Alternativa:
1251   //   std::string result;
1252   //
1253   //
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]);
1256   //   }
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));
1275   //   }
1276   //   else
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);
1278   //
1279   //
1280   //   return (normalize ? normalizeIP(result):result);
1281 }
1282
1283
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
1288
1289   if((pos != std::string::npos) && (pos != lastPos)) {
1290     address = literal.substr(0, pos);
1291     port = atoi(literal.substr(pos + 1, lastPos).c_str());
1292   }
1293 }
1294
1295
1296 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1297   socket_v result;
1298   std::string address;
1299   int port;
1300   anna::Tokenizer lst;
1301   lst.apply(list, ",");
1302
1303   if(lst.size() < 1) return result;
1304
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;
1308
1309   for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1310     getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1311
1312     if(port == -1) { result.clear(); return result; }
1313
1314     result.push_back(socket_t(address, port));
1315   }
1316
1317   return result;
1318 }
1319
1320 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1321   std::string result;
1322   socket_v_it it;
1323   socket_v_it it_min(socketVector.begin());
1324   socket_v_it it_max(socketVector.end());
1325
1326   for(it = it_min; it != it_max; it++) {
1327     result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1328   }
1329
1330   result.erase(result.size() - 1, 1);  // remove last comma
1331   return result;
1332 }
1333
1334 bool functions::littleEndian()
1335 throw() {
1336   int i = 1;
1337   char *p = (char *) &i;
1338   if (p[0] == 1) return true;
1339   return false;
1340 }
1341
1342 const char* functions::codeInteger(char* result, const int n)
1343 throw() {
1344   int aux(htonl(n));
1345   register char* w((char*) &aux);
1346   *result = *w;
1347   *(result + 1) = *(w + 1);
1348   *(result + 2) = *(w + 2);
1349   *(result + 3) = *(w + 3);
1350   return result;
1351 }
1352
1353 const char* functions::codeShort(char* result, const short int n)
1354 throw() {
1355   short int aux(htons(n));
1356   register char* w((char*) &aux);
1357   *result = *w;
1358   *(result + 1) = *(w + 1);
1359   return result;
1360 }
1361
1362 const char* functions::codeInteger64(char* result, const S64 n)
1363 throw() {
1364   S64 aux(0xffffffff);
1365   int n2;
1366   aux <<= 32;
1367   aux &= n;
1368   n2 = (aux >> 32) & 0xffffffff;
1369   codeInteger(result, n2);
1370   n2 = n & 0xffffffff;
1371   codeInteger(result + sizeof(int), n2);
1372   return result;
1373 }
1374
1375 /*static*/
1376 const char* functions::codeFloat(char* result, const float n)
1377 throw() {
1378   int ii;
1379   anna_memcpy(&ii, &n, sizeof(n));
1380   return functions::codeInteger(result, ii);
1381 }
1382
1383 /*static*/
1384 const char* functions::codeDouble(char* result, const double n)
1385 throw() {
1386   S64 ii;
1387   anna_memcpy(&ii, &n, sizeof(n));
1388   return functions::codeInteger64(result, ii);
1389 }
1390
1391 int functions::decodeInteger(const char* data)
1392 throw() {
1393   int result;
1394   register char* w((char*) &result);
1395   *w  = *data;
1396   *(w + 1) = *(data + 1);
1397   *(w + 2) = *(data + 2);
1398   *(w + 3) = *(data + 3);
1399   return ntohl(result);
1400 }
1401
1402 short int functions::decodeShort(const char* data)
1403 throw() {
1404   short int result;
1405   register char* w((char*) &result);
1406   *w  = *data;
1407   *(w + 1) = *(data + 1);
1408   return ntohs(result);
1409 }
1410
1411 S64 functions::decodeInteger64(const char* data)
1412 throw() {
1413   S64 result(decodeInteger(data));
1414   result <<= 32;
1415   return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1416 }
1417
1418 /*static*/
1419 float functions::decodeFloat(const char* data)
1420 throw() {
1421   float result;
1422   int ii = functions::decodeInteger(data);
1423   anna_memcpy(&result, &ii, sizeof(result));
1424   return result;
1425 }
1426
1427 /*static*/
1428 double functions::decodeDouble(const char* data)
1429 throw() {
1430   double result;
1431   S64 ii = functions::decodeInteger64(data);
1432   anna_memcpy(&result, &ii, sizeof(result));
1433   return result;
1434 }
1435
1436
1437
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))
1440   isupNumber.reset();
1441   isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1442   bool filler = isupNumber.OddEven;
1443
1444   if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1445     throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1446
1447   isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1448   isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1449
1450   if(calledOrCalling) {
1451     isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1452   } else {
1453     isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1454     isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1455     isupNumber.Screening = (short)(buffer[1] & 0x03);
1456   }
1457
1458   // Digits:
1459   isupNumber.Digits = "";
1460   int byte;
1461
1462   for(register 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');
1467   }
1468
1469   if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1);   // remove filler
1470 }
1471
1472
1473 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1474   // Checkings:
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);
1477
1478   bool odd = isupNumber.OddEven;
1479   bool oddDigits = (isupNumber.Digits.size() % 2);
1480
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);
1483
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);
1486
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);
1489
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);
1493
1494     if(isupNumber.AddressPresentationRestricted != 0)
1495       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1496
1497     if(isupNumber.Screening != 0)
1498       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1499
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);
1502   } else {
1503     if(isupNumber.InternalNetworkNumber != 0)
1504       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1505
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);
1508
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);
1511
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);
1514   }
1515
1516   char byte;
1517   target = "";
1518   bool filler = isupNumber.OddEven;
1519   bool hasDigits = (isupNumber.Digits.size() > 0);
1520   byte = filler ? 0x80 : 0x00;
1521   byte = byte |= isupNumber.NatureOfAddress;
1522   target += byte;
1523
1524   if(calledOrCalling) {
1525     byte = isupNumber.InternalNetworkNumber << 7;
1526     byte = byte |= (isupNumber.NumberingPlan << 4);
1527   } else {
1528     byte = isupNumber.NumberIncomplete << 7;
1529     byte = byte |= (isupNumber.NumberingPlan << 4);
1530     byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1531     byte = byte |= isupNumber.Screening;
1532   }
1533
1534   target += byte;
1535   //int byte;
1536   unsigned char hex;
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();
1540
1541   for(register 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);
1544
1545     hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1546
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);
1549
1550     hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1551     target += hex;
1552   }
1553
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);
1557
1558     target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1559   }
1560 }
1561
1562
1563 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1564   std::string target;
1565   codeIsupNumber(isupNumber, calledOrCalling, target);
1566   length = target.size();
1567   memcpy(buffer, target.c_str(), length);
1568 }
1569