1a6a2910d926cb62e20d41af54f97d42559c6689
[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 // http://redmine.teslayout.com/projects/anna-suite
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 the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
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  * Gets the original value obtained with #asHexString (const DataBlock&).
264  * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
265  * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
266  * \param target DataBlock for string decode.
267  * \return DataBlock corresponding to the provided string.
268  */
269 //static
270 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
271 throw(RuntimeException) {
272
273   if((hexString.length() % 2) != 0)
274     throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
275
276   target.clear();
277   const char* src = hexString.data();
278   unsigned char hex;
279   int aux;
280   int j = 0;
281
282   for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
283     if(isxdigit(aux = src [ii - 1]) == 0)
284       throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
285
286     hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
287
288     if(isxdigit(aux = src [ii]) == 0)
289       throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
290
291     hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
292     target += hex;
293   }
294
295   return target;
296 }
297
298 string functions::asString(const char* format, ...)
299 throw() {
300   va_list ap;
301   char aux [1024];
302   va_start(ap, format);
303   vsnprintf(aux, sizeof(aux), format, ap);
304   va_end(ap);
305   return string(aux);
306 }
307
308 void functions::sleep(const Millisecond &millisecond)
309 throw() {
310   timespec req;
311   timespec rem;
312   req.tv_sec = millisecond.getValue() / 1000;                          // segundos
313   req.tv_nsec = (millisecond.getValue() % 1000);                       // milisegundos
314   req.tv_nsec *= 1000000;                                   // mili = 10e-3, nano=10-9
315   int r;
316
317   while((r = nanosleep(&req, &rem)) != 0) {
318     if(errno == EINTR)
319       req = rem;
320     else {
321       string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
322       msg += functions::asText("| nsec: ", (int) req.tv_nsec);
323       msg += " }";
324       RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
325       ex.trace();
326       break;
327     }
328   }
329 }
330
331 bool functions::asBool(const char* str)
332 throw(RuntimeException) {
333   if(str == NULL)
334     return false;
335
336   if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
337     return true;
338
339   if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
340     return false;
341
342   string msg("anna::funcions::asBool | Cannot interpret '");
343   msg += str;
344   msg += "' as boolean";
345   throw RuntimeException(msg, ANNA_FILE_LOCATION);
346 }
347
348 S64 functions::asInteger64(const char* str)
349 throw() {
350   S64 number = 0;
351   sscanf(str, "%lld", &number);
352   /*
353   #ifdef __anna64__
354     sscanf (str, "%ld", &number);
355   #else
356      sscanf (str, "%lld", &number);
357   #endif
358   */
359   return number;
360 }
361
362 pthread_t functions::getCurrentThread()
363 throw() {
364   WHEN_MULTITHREAD(return pthread_self());
365   WHEN_SINGLETHREAD(return 0);
366 }
367
368 bool functions::isLike(const char* pattern, const std::string& _value)
369 throw(RuntimeException) {
370   const char* value = _value.c_str();
371   regex_t preg;
372   int ret;
373
374   if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
375     char err[256];
376     string msg("anna::functions::isLike | ");
377     msg += " | Pattern: ";
378     msg += pattern;
379     msg += " | Value: ";
380     msg += value;
381     msg += " | ";
382
383     if(regerror(ret, &preg, err, sizeof(err)))
384       msg += err;
385     else
386       msg += "Invalid pattern";
387
388     throw RuntimeException(msg, ANNA_FILE_LOCATION);
389   }
390
391   const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
392
393   regfree(&preg);
394   return result;
395 }
396
397 /*static*/
398 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
399 throw(RuntimeException) {
400   if(bitShift > intBitSize) {
401     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
402     throw RuntimeException(msg, ANNA_FILE_LOCATION);
403   }
404
405   if((bitsize(n1) + bitShift) > int64BitSize) {
406     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
407     throw RuntimeException(msg, ANNA_FILE_LOCATION);
408   }
409
410   if(bitsize(n2) > bitShift) {
411     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
412     throw RuntimeException(msg, ANNA_FILE_LOCATION);
413   }
414
415   S64 result = n1;
416   result <<= bitShift;
417   result |= n2;
418
419   if(bitShift == intBitSize) {
420     LOGINFORMATION(
421       string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
422       msg += functions::asHexString(result);
423       Logger::information(msg, ANNA_FILE_LOCATION);
424     );
425   }
426
427   return result;
428 }
429
430 /*static*/
431 /*
432  * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
433  */
434 int functions::log2(const unsigned int v)
435 throw() {
436   static const char LogTable256[] = {
437     -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
438     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
439     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
440     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
441     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
442     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
443     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
444     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
445     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
446     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
447     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
448     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
449     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
450     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
451     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
452     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
453   };
454   int r = -1;     // r will be lg(v)
455   unsigned int t, tt; // temporaries
456
457   if(tt = v >> 16) {
458     r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
459   } else {
460     r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
461   }
462
463   return r;
464 }
465
466 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
467   std::string result;
468   std::string singular = (wordForSingular ? wordForSingular : "entry");
469   std::string plural = (wordForPlural ? wordForPlural : "entries");
470
471   if(wordForSingular && !wordForPlural)
472     plural = singular + "s";
473
474   result += ((number != 0) ? anna::functions::asString(number) : "no");
475   result += " ";
476   result += ((number != 1) ? plural : singular);
477   return result;
478 }
479
480
481 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
482   std::string result;
483   int d_size = title.size();
484   int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
485   bool adjust = false;
486
487   if(mode == TextJustifyMode::Center) {
488     repeat = (repeat - 1) / 2;
489     adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
490   }
491
492   if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
493     for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
494
495     result += " ";
496   }
497
498   result += title;
499
500   if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
501     result += " ";
502
503     for(int k = 0; k < repeat; k++) result += filler;
504   }
505
506   return result;
507 }
508
509
510 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
511   std::string result;
512   int ou_repeat = title.size();
513   int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
514   bool adjust = false;
515
516   if(mode == TextHighlightMode::LeftAndRightline) {
517     lr_repeat = (lr_repeat - 1) / 2;
518     adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
519   }
520
521   if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
522     for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
523
524     result += " ";
525   }
526
527   if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
528     for(int k = 0; k < ou_repeat; k++) result += filler;
529
530     result += "\n";
531   }
532
533   result += title;
534
535   if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
536     result += "\n";
537
538     for(int k = 0; k < ou_repeat; k++) result += filler;
539   }
540
541   if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
542     result += " ";
543
544     for(int k = 0; k < lr_repeat; k++) result += filler;
545   }
546
547   if(appendCR) result += "\n";
548
549   return result;
550 }
551
552
553 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
554   std::string result;
555   size_t pos, from = 0;
556   std::string tab, crTab = "\n";
557
558   for(int k = 0; k < tabSpaces; k++) tab += " ";
559
560   crTab += tab;
561   result = tab;
562   result += text;
563
564   while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
565     result.replace(pos, 1, crTab);
566     from = pos + 1;
567   }
568
569   return result;
570 }
571
572
573 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
574   preffix = "";
575
576   if(pattern.size() < suffix.size()) return false;
577
578   size_t pos = pattern.rfind(suffix);
579
580   if(pos == std::string::npos) return false;
581
582   preffix.assign(pattern.c_str(), pos);
583   return (pos == (pattern.size() - suffix.size()));
584 }
585
586
587 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
588   suffix = "";
589
590   if(pattern.size() < preffix.size()) return false;
591
592   if(pattern.find(preffix) != 0) return false;
593
594   suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
595   return true;
596 }
597
598
599 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
600   std::string result = text;
601
602   if(!item || !target) return result;  // protection for NULL strings provided
603
604   size_t lengthReplaced = strlen(item);
605   size_t pos = result.find(item);
606
607   while(pos != std::string::npos) {
608     result.replace(pos, lengthReplaced, target);
609
610     if(!all) break;
611
612     pos = result.find(item);
613   }
614
615   return result;
616 }
617
618
619 std::string functions::addQuotationMarks(const std::string & str) throw() {
620   std::string result = "'";
621   result += str;
622   result += "'";
623   return (result);
624 }
625
626
627 std::string functions::addQuotationMarks(const char * str) throw() {
628   std::string result = "'";
629   result += (str ? str : "<null>");
630   result += "'";
631   return (result);
632 }
633
634
635 std::string functions::addQuotationMarks(const int & integer) throw() {
636   std::string result = "'";
637   result += anna::functions::asString(integer);
638   result += "'";
639   return (result);
640 }
641
642
643 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
644   std::string result = "";
645
646   if(v.size() != 0) {
647     std::vector<int>::const_iterator iter;
648     std::vector<int>::const_iterator iter_min(v.begin());
649     std::vector<int>::const_iterator iter_max(v.end());
650
651     for(iter = iter_min; iter != iter_max; iter++) {
652       result += anna::functions::asString(*iter);
653       result += separator;
654     }
655
656     // Delete the last space: starts at 'size()-1', take 1 caracter:
657     result.erase(result.size() - 1, 1);
658   }
659
660   return (result);
661 }
662
663
664 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
665   std::string result = "";
666
667   if(v.size() != 0) {
668     std::vector<std::string>::const_iterator iter;
669     std::vector<std::string>::const_iterator iter_min(v.begin());
670     std::vector<std::string>::const_iterator iter_max(v.end());
671
672     for(iter = iter_min; iter != iter_max; iter++) {
673       result += (*iter);
674       result += separator;
675     }
676
677     // Delete the last space: starts at 'size()-1', take 1 caracter:
678     result.erase(result.size() - 1, 1);
679   }
680
681   return (result);
682 }
683
684
685 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
686   std::string result = address;
687   result += ":";
688   result += anna::functions::asString(port);
689   return result;
690 }
691
692
693 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
694   std::string result;
695   // Supposed printable by default:
696   isFullyPrintable = true;
697
698   if(size == 0 || !buffer) {
699     result = "<null>";
700     isFullyPrintable = false;
701     return result;
702   }
703
704   for(int k = 0; k < size; k ++) {
705     unsigned char c = (unsigned char) buffer [k];
706     int printable = isprint(c);
707     result += (printable ? (char) c : '.');
708
709     if(!printable) isFullyPrintable = false;
710   }
711
712   return result;
713 }
714
715
716 std::string functions::getHostname() throw() {
717   char aux[255];
718   std::string result = "<hostname>";
719
720   if(gethostname(aux, sizeof aux) == 0 /*success*/)
721     result = aux;
722
723   return result;
724 }
725
726 std::string functions::getDomainname() throw() {
727   char aux[256];
728   std::string result = "<domainname>";
729
730   if(getdomainname(aux, sizeof aux) == 0 /*success*/)
731     result = aux;
732
733   return result;
734 }
735
736 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
737   std::string hn = hostname ? hostname : (functions::getHostname());
738   std::string dn = domainname ? domainname : (functions::getDomainname());
739   // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
740
741   if(hn == "") return dn;
742
743   if(dn == "") return hn;
744
745   std::string label(hn, 0, 63);
746   std::string fqdn(label + "." + dn, 0, 255);
747   return fqdn;
748 }
749
750 std::string functions::getHostnameIP() throw() {
751   std::string result = "";
752   struct hostent *he;
753   struct in_addr **addr_list;
754   struct in_addr ipv4addr;
755   char hostname[128];
756   gethostname(hostname, sizeof hostname);
757
758   if((he = gethostbyname(hostname)) != NULL) {
759     // Official name: he->h_name
760     // IP addresses:
761     addr_list = (struct in_addr **)he->h_addr_list;
762
763     for(int i = 0; addr_list[i] != NULL; i++) {
764       //printf("%s ", inet_ntoa(*addr_list[i]));
765       result = inet_ntoa(*addr_list[i]);
766       return result;
767     }
768   }
769
770   return result;
771 }
772
773
774 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
775   int length = rawPresentation.size();
776
777   if(length != 8 && length != 32)
778     throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
779
780   anna::DataBlock result(true);
781   int byte;
782   char rByte[3]; // readable byte
783   rByte[2] = 0;
784
785   for(int k = 0; k < length; k += 2) {
786     rByte[0] =  rawPresentation[k];
787     rByte[1] = rawPresentation[k + 1];
788     sscanf(rByte, "%x", &byte);
789     result += byte;
790   }
791
792   return result;
793 }
794
795
796 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
797   int length = db.getSize();
798
799   if(length != 4 && length != 16)
800     throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
801
802   std::string result = "";
803   int byte;
804   char rByte[3]; // readable byte
805   rByte[2] = 0;
806
807   for(int k = 0; k < length; k++) {
808     byte = (unsigned char)db[k];
809     sprintf(rByte, "%.2X", byte);
810     result += rByte;
811   }
812
813   return result;
814 }
815
816
817
818 ////////////////////
819 // Address Format //
820 ////////////////////
821 //   IPv6 addresses have two logical parts: a 64-bit network prefix, and a 64-bit host address part. (The host address is often automatically generated from the interface MAC address.[34]) An IPv6 address is represented by 8 groups of 16-bit hexadecimal values separated by colons (:) shown as follows:
822 //   A typical example of an IPv6 address is
823 //   2001:0db8:85a3:0000:0000:8a2e:0370:7334
824 //   The hexadecimal digits are case-insensitive.
825 //
826 //   The 128-bit IPv6 address can be abbreviated with the following rules:
827 //   -Rule one: Leading zeroes within a 16-bit value may be omitted. For example, the address fe80:0000:0000:0000:0202:b3ff:fe1e:8329 may be written as fe80:0:0:0:202:b3ff:fe1e:8329
828 //   -Rule two: A single occurrence of consecutive groups of zeroes within an address may be replaced by a double colon. For example, fe80:0:0:0:202:b3ff:fe1e:8329 becomes fe80::202:b3ff:fe1e:8329
829 //   A single IPv6 address can be represented in several different ways, such as 2001:db8::1:0:0:1 and 2001:0DB8:0:0:1::1. RFC 5952 recommends a canonical textual representation.
830
831 //      Si la dirección tiene más de una serie de grupos nulos consecutivos la compresión sólo se permite en uno de ellos.
832 //      Así, las siguientes son representaciones posibles de una misma dirección:
833 //
834 //      2001:0DB8:0000:0000:0000:0000:1428:57ab
835 //      2001:0DB8:0000:0000:0000::1428:57ab
836 //      2001:0DB8:0:0:0:0:1428:57ab
837 //      2001:0DB8:0::0:1428:57ab
838 //      2001:0DB8::1428:57ab
839 //      son todas válidas y significan lo mismo, pero
840 //      2001::25de::cade
841 //          --    --
842 //      no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
843 //
844 //      Los ceros iniciales en un grupo también se pueden omitir:
845 //      2001:0DB8:02de::0e13
846 //      2001:DB8:2de::e13
847 //
848 //      Si la dirección es una dirección IPv4 empotrada (mapped), los Ãºltimos 32 bits pueden escribirse en base decimal, así:
849 //      ::ffff:192.168.89.9
850 //      ::ffff:c0a8:5909
851 //
852 //      No se debe confundir con:
853 //      ::192.168.89.9
854 //      ::c0a8:5909
855 //
856 //      El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
857 //      Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
858 //       (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
859 //       la notación mixta dirección IPv4 compatible, en cuyo caso la dirección debería ser ::135.75.43.52. Este tipo de dirección IPv4 compatible
860 //       casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
861 //
862 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
863
864 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
865   if(ipv4Type == IPv4Type::Estrict) {
866     // La expresión regular no controla si hay mas de 3 puntos:
867     int n_dot = 0;
868
869     for(int k = 0; k < ip.length(); k++)
870       if(ip[k] == '.') n_dot++;
871
872     if(n_dot > 3)
873       return (false);
874
875     bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
876     bool colon = (ip.find(":") != std::string::npos);
877     return (ipv4 && !colon);
878   }
879
880   if(ipv4Type == IPv4Type::Compatible) {
881     std::string pureIPv4 = ip;
882     bool firstDoubleColon = (ip.find("::") == 0);
883
884     if(firstDoubleColon) {
885       pureIPv4.erase(0, 2);
886       bool anotherColon = (pureIPv4.find(":") != std::string::npos);
887
888       if(anotherColon) return (false);
889
890       return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
891     }
892   }
893
894   if(ipv4Type == IPv4Type::Mapped) {
895     size_t posLastColon = ip.rfind(":");
896
897     if(posLastColon == std::string::npos)
898       return (false);
899
900     if(!isIPv4(ip.substr(posLastColon + 1)))
901       return (false);
902
903     unsigned char buf[sizeof(struct in6_addr)];
904     int s = inet_pton(AF_INET6, ip.c_str(), buf);
905
906     if(s > 0)
907       return (true);
908   }
909
910   return false;
911 }
912
913
914 bool functions::isIPv6(const std::string & ip) throw() {
915   // Chequeo de digitos permitidos:
916   for(int k = 0; k < ip.length(); k++) {
917     bool digit = isdigit(ip[k]);
918     bool hex = ((ip[k] == 'a') ||
919                 (ip[k] == 'b') ||
920                 (ip[k] == 'c') ||
921                 (ip[k] == 'd') ||
922                 (ip[k] == 'e') ||
923                 (ip[k] == 'f') ||
924                 (ip[k] == 'A') ||
925                 (ip[k] == 'B') ||
926                 (ip[k] == 'C') ||
927                 (ip[k] == 'D') ||
928                 (ip[k] == 'E') ||
929                 (ip[k] == 'F'));
930     bool colon = (ip[k] == ':');
931
932     if(!digit && !hex && !colon)
933       return false;
934   }
935
936   return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
937 }
938
939
940 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
941   if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
942     throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
943
944   std::string result, pureIPv4;
945   bool firstDoubleColon = (ip.find("::") == 0);
946
947   if(firstDoubleColon) {
948     // Clean '::'
949     size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
950     pureIPv4 = ip.substr(ipv4_pos);
951   } else {
952     if(!isIPv4(ip)) {
953       size_t posColon = ip.find(":");
954
955       if(posColon == 0)  // first colon
956         throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
957
958       if(posColon != std::string::npos)  // any colon
959         return ip; // seems to be IPv6 already?
960
961       throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
962     }
963
964     pureIPv4 = ip;
965   }
966
967   // Number of ocurrences for '.'
968   int n_dot = 0;
969
970   for(int k = 0; k < pureIPv4.length(); k++)
971     if(pureIPv4[k] == '.') n_dot++;
972
973   if(n_dot > 3)
974     throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
975
976   anna::Tokenizer tok;
977   anna::Tokenizer::const_iterator tok_it;
978   std::string token;
979   tok.apply(pureIPv4, ".");
980   int v[4];
981   int cnt = 0;
982
983   for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
984     token = anna::Tokenizer::data(tok_it);
985     v[cnt] = atoi(anna::Tokenizer::data(tok_it));
986
987     if(v[cnt] < 0 || v[cnt] > 255)
988       throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
989
990     cnt++;
991   }
992
993   if(isIPv4(ip, IPv4Type::Compatible))
994     result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
995   else
996     result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
997
998   return result;
999 }
1000
1001
1002 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
1003   std::string result = ip;
1004 //   std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
1005   std::transform(result.begin(), result.end(), result.begin(), ::tolower);
1006
1007   if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
1008     result = IPv4To6(result);
1009
1010   size_t pos = result.find("::"); // zeroes simplification group
1011   size_t rpos = result.rfind("::"); // zeroes simplification group
1012
1013   if(pos != rpos)
1014     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
1015
1016   if(pos != std::string::npos) {  // zeroes exists
1017     // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
1018     // Number of ocurrences for ':'
1019     int n_colon = 0;
1020
1021     for(int k = 0; k < result.length(); k++)
1022       if(result[k] == ':') n_colon++;
1023
1024     // Generate equivalent to '::'
1025     std::string equiv_str;
1026
1027     for(int k = 0; k < (8 - n_colon); k++)
1028       equiv_str += ":0";
1029
1030     equiv_str += ":";
1031     // Replace with equivalent:
1032     result.replace(pos, 2, equiv_str);
1033
1034     // Special case: IP began with '::'
1035     if(result[0] == ':') {
1036       result.insert(0, "0");
1037     }
1038
1039     // Special case: IP was only '::'
1040     if(result[result.length() - 1] == ':') {
1041       result += "0";
1042     }
1043   }
1044
1045   // Protection: it must be seven colons:
1046   int n_colon = 0;
1047
1048   for(int k = 0; k < result.length(); k++)
1049     if(result[k] == ':') n_colon++;
1050
1051   if(n_colon != 7)
1052     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1053
1054   // Padding with zeroes at left
1055   anna::Tokenizer ipStr;
1056   anna::Tokenizer::const_iterator ipStr_it;
1057   std::string token;
1058   ipStr.apply(result, ":");
1059   result = "";
1060
1061   for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1062     token = anna::Tokenizer::data(ipStr_it);
1063
1064     while(token.length() < 4) token.insert(0, "0");
1065
1066     result += token;
1067     result += ":";
1068   }
1069
1070   // Remove last ':'
1071   size_t lastPos = result.length() - 1;
1072   result.erase(lastPos, 1);
1073
1074   // Chequeo de digitos permitidos:
1075   for(int k = 0; k < result.length(); k++) {
1076     bool digit = isdigit(result[k]);
1077     bool hex = ((result[k] == 'a') ||
1078                 (result[k] == 'b') ||
1079                 (result[k] == 'c') ||
1080                 (result[k] == 'd') ||
1081                 (result[k] == 'e') ||
1082                 (result[k] == 'f'));
1083     bool colon = (result[k] == ':');
1084
1085     if(!digit && !hex && !colon) {
1086       throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1087     }
1088   }
1089
1090   return result;
1091 }
1092
1093
1094 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1095   //if (ip1 == ip2) return true; it should validate wrong-format addresses
1096   return (normalizeIP(ip1) == normalizeIP(ip2));
1097 }
1098
1099
1100 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1101   size_t preffixPos = preffixedIpv6.find("/");
1102
1103   if(preffixPos == std::string::npos)
1104     return (sameIP(_ipv6, preffixedIpv6));
1105
1106   std::string ipv6 = _ipv6;
1107
1108   if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1109
1110   std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1111   std::string ipv6_2 = _ipv6_2;
1112
1113   if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1114
1115   std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1116   int ipv6_2_preffixLength = atoi(preffix.c_str());
1117
1118   if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1119     throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1120
1121   // No restriction, all ipv6_2 ignored (special and not usual case)
1122   if(ipv6_2_preffixLength == 0) return true;
1123
1124   // Auxiliary data:
1125   int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1126   int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1127   int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1128   char mask = 0xFF << (8 - spare);
1129   // Limit ipv6
1130   anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1131   anna::DataBlock restrictedIP1(true);
1132   restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1133
1134   if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1135
1136   // Limit ipv6_2
1137   anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1138   anna::DataBlock realIP2(true);
1139   realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1140
1141   if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1142
1143   // Comparison
1144   int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1145   return (n == 0);
1146 }
1147
1148
1149 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1150   anna::DataBlock result(true);
1151
1152   if(isIPv4(ip)) {
1153     unsigned char buf[sizeof(struct in6_addr)];
1154     int s = inet_pton(AF_INET, ip.c_str(), buf);
1155
1156     if(s > 0) {
1157       result += (S8)buf[0];
1158       result += (S8)buf[1];
1159       result += (S8)buf[2];
1160       result += (S8)buf[3];
1161     } else {
1162       if(s < 0) perror("inet_pton");
1163
1164       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1165     }
1166   } else {
1167     unsigned char buf[sizeof(struct in6_addr)];
1168     int s = inet_pton(AF_INET6, ip.c_str(), buf);
1169
1170     if(s > 0) {
1171       result += (S8)buf[0];
1172       result += (S8)buf[1];
1173       result += (S8)buf[2];
1174       result += (S8)buf[3];
1175       result += (S8)buf[4];
1176       result += (S8)buf[5];
1177       result += (S8)buf[6];
1178       result += (S8)buf[7];
1179       result += (S8)buf[8];
1180       result += (S8)buf[9];
1181       result += (S8)buf[10];
1182       result += (S8)buf[11];
1183       result += (S8)buf[12];
1184       result += (S8)buf[13];
1185       result += (S8)buf[14];
1186       result += (S8)buf[15];
1187     } else {
1188       if(s < 0) perror("inet_pton");
1189
1190       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1191     }
1192   }
1193
1194   return result;
1195   // Alternativa
1196   //   anna::DataBlock result(true);
1197   //
1198   //
1199   //   if (isIPv4(ip)) {
1200   //
1201   //      int dec1, dec2, dec3, dec4; // U32 type is valid, 'int' better: argument for %d must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
1202   //      sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1203   //      result += (S8)dec1;
1204   //      result += (S8)dec2;
1205   //      result += (S8)dec3;
1206   //      result += (S8)dec4;
1207   //   }
1208   //   else {
1209   //
1210   //      int hex1, hex2, hex3, hex4, hex5, hex6, hex7, hex8; // U16 type is not valid: argument for %X must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
1211   //      sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1212   //      result += ((S8)(hex1 >> 8));
1213   //      result += ((S8)(hex1 & 0x00FF));
1214   //      result += ((S8)(hex2 >> 8));
1215   //      result += ((S8)(hex2 & 0x00FF));
1216   //      result += ((S8)(hex3 >> 8));
1217   //      result += ((S8)(hex3 & 0x00FF));
1218   //      result += ((S8)(hex4 >> 8));
1219   //      result += ((S8)(hex4 & 0x00FF));
1220   //      result += ((S8)(hex5 >> 8));
1221   //      result += ((S8)(hex5 & 0x00FF));
1222   //      result += ((S8)(hex6 >> 8));
1223   //      result += ((S8)(hex6 & 0x00FF));
1224   //      result += ((S8)(hex7 >> 8));
1225   //      result += ((S8)(hex7 & 0x00FF));
1226   //      result += ((S8)(hex8 >> 8));
1227   //      result += ((S8)(hex8 & 0x00FF));
1228   //   }
1229   //
1230   //
1231   //   return result;
1232 }
1233
1234
1235 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1236   std::string result = "";
1237   char str[INET6_ADDRSTRLEN];
1238
1239   if(bufferLength == 4) {
1240     if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1241       result = str;
1242   } else if(bufferLength == 16) {
1243     if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1244       result = str;
1245   } else
1246     throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1247
1248   if(result == "")
1249     throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1250
1251   return (normalize ? normalizeIP(result) : result);
1252   // Alternativa:
1253   //   std::string result;
1254   //
1255   //
1256   //   if (bufferLength == 4) { // IPv4
1257   //      result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1258   //   }
1259   //   else if (bufferLength == 16) { // IPv6
1260   //      result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1261   //                       ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1262   //                       (((U8)buffer[1])        & 0x00FF),
1263   //                       ((((U8)buffer[2]) << 8) & 0xFF00) +
1264   //                       (((U8)buffer[3])        & 0x00FF),
1265   //                       ((((U8)buffer[4]) << 8) & 0xFF00) +
1266   //                       (((U8)buffer[5])        & 0x00FF),
1267   //                       ((((U8)buffer[6]) << 8) & 0xFF00) +
1268   //                       (((U8)buffer[7])        & 0x00FF),
1269   //                       ((((U8)buffer[8]) << 8) & 0xFF00) +
1270   //                       (((U8)buffer[9])        & 0x00FF),
1271   //                       ((((U8)buffer[10]) << 8) & 0xFF00) +
1272   //                       (((U8)buffer[11])        & 0x00FF),
1273   //                       ((((U8)buffer[12]) << 8) & 0xFF00) +
1274   //                       (((U8)buffer[13])        & 0x00FF),
1275   //                       ((((U8)buffer[14]) << 8) & 0xFF00) +
1276   //                       (((U8)buffer[15])        & 0x00FF));
1277   //   }
1278   //   else
1279   //      throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1280   //
1281   //
1282   //   return (normalize ? normalizeIP(result):result);
1283 }
1284
1285
1286 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1287   size_t pos = literal.find_last_of(":");
1288   size_t lastPos = literal.size() - 1;
1289   address = ""; port = -1; // assume error
1290
1291   if((pos != std::string::npos) && (pos != lastPos)) {
1292     address = literal.substr(0, pos);
1293     port = atoi(literal.substr(pos + 1, lastPos).c_str());
1294   }
1295 }
1296
1297
1298 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1299   socket_v result;
1300   std::string address;
1301   int port;
1302   anna::Tokenizer lst;
1303   lst.apply(list, ",");
1304
1305   if(lst.size() < 1) return result;
1306
1307   anna::Tokenizer::const_iterator tok_min(lst.begin());
1308   anna::Tokenizer::const_iterator tok_max(lst.end());
1309   anna::Tokenizer::const_iterator tok_iter;
1310
1311   for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1312     getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1313
1314     if(port == -1) { result.clear(); return result; }
1315
1316     result.push_back(socket_t(address, port));
1317   }
1318
1319   return result;
1320 }
1321
1322 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1323   std::string result;
1324   socket_v_it it;
1325   socket_v_it it_min(socketVector.begin());
1326   socket_v_it it_max(socketVector.end());
1327
1328   for(it = it_min; it != it_max; it++) {
1329     result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1330   }
1331
1332   result.erase(result.size() - 1, 1);  // remove last comma
1333   return result;
1334 }
1335
1336 bool functions::littleEndian()
1337 throw() {
1338   int i = 1;
1339   char *p = (char *) &i;
1340   if (p[0] == 1) return true;
1341   return false;
1342 }
1343
1344 const char* functions::codeInteger(char* result, const int n)
1345 throw() {
1346   int aux(htonl(n));
1347   char* w((char*) &aux);
1348   *result = *w;
1349   *(result + 1) = *(w + 1);
1350   *(result + 2) = *(w + 2);
1351   *(result + 3) = *(w + 3);
1352   return result;
1353 }
1354
1355 const char* functions::codeShort(char* result, const short int n)
1356 throw() {
1357   short int aux(htons(n));
1358   char* w((char*) &aux);
1359   *result = *w;
1360   *(result + 1) = *(w + 1);
1361   return result;
1362 }
1363
1364 const char* functions::codeInteger64(char* result, const S64 n)
1365 throw() {
1366   S64 aux(0xffffffff);
1367   int n2;
1368   aux <<= 32;
1369   aux &= n;
1370   n2 = (aux >> 32) & 0xffffffff;
1371   codeInteger(result, n2);
1372   n2 = n & 0xffffffff;
1373   codeInteger(result + sizeof(int), n2);
1374   return result;
1375 }
1376
1377 /*static*/
1378 const char* functions::codeFloat(char* result, const float n)
1379 throw() {
1380   int ii;
1381   anna_memcpy(&ii, &n, sizeof(n));
1382   return functions::codeInteger(result, ii);
1383 }
1384
1385 /*static*/
1386 const char* functions::codeDouble(char* result, const double n)
1387 throw() {
1388   S64 ii;
1389   anna_memcpy(&ii, &n, sizeof(n));
1390   return functions::codeInteger64(result, ii);
1391 }
1392
1393 int functions::decodeInteger(const char* data)
1394 throw() {
1395   int result;
1396   char* w((char*) &result);
1397   *w  = *data;
1398   *(w + 1) = *(data + 1);
1399   *(w + 2) = *(data + 2);
1400   *(w + 3) = *(data + 3);
1401   return ntohl(result);
1402 }
1403
1404 short int functions::decodeShort(const char* data)
1405 throw() {
1406   short int result;
1407   char* w((char*) &result);
1408   *w  = *data;
1409   *(w + 1) = *(data + 1);
1410   return ntohs(result);
1411 }
1412
1413 S64 functions::decodeInteger64(const char* data)
1414 throw() {
1415   S64 result(decodeInteger(data));
1416   result <<= 32;
1417   return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1418 }
1419
1420 /*static*/
1421 float functions::decodeFloat(const char* data)
1422 throw() {
1423   float result;
1424   int ii = functions::decodeInteger(data);
1425   anna_memcpy(&result, &ii, sizeof(result));
1426   return result;
1427 }
1428
1429 /*static*/
1430 double functions::decodeDouble(const char* data)
1431 throw() {
1432   double result;
1433   S64 ii = functions::decodeInteger64(data);
1434   anna_memcpy(&result, &ii, sizeof(result));
1435   return result;
1436 }
1437
1438
1439
1440 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1441 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1442   isupNumber.reset();
1443   isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1444   bool filler = isupNumber.OddEven;
1445
1446   if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1447     throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1448
1449   isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1450   isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1451
1452   if(calledOrCalling) {
1453     isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1454   } else {
1455     isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1456     isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1457     isupNumber.Screening = (short)(buffer[1] & 0x03);
1458   }
1459
1460   // Digits:
1461   isupNumber.Digits = "";
1462   int byte;
1463
1464   for(int k = 2; k < length; k ++) {
1465     byte = (buffer [k] & 0x0f);
1466     isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1467     byte = (buffer [k] & 0xf0) >> 4;
1468     isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1469   }
1470
1471   if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1);   // remove filler
1472 }
1473
1474
1475 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1476   // Checkings:
1477   if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1478     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1479
1480   bool odd = isupNumber.OddEven;
1481   bool oddDigits = (isupNumber.Digits.size() % 2);
1482
1483   if(odd != oddDigits)
1484     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1485
1486   if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1487     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1488
1489   if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1490     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1491
1492   if(calledOrCalling) {
1493     if(isupNumber.NumberIncomplete != 0)
1494       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1495
1496     if(isupNumber.AddressPresentationRestricted != 0)
1497       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1498
1499     if(isupNumber.Screening != 0)
1500       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1501
1502     if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1503       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1504   } else {
1505     if(isupNumber.InternalNetworkNumber != 0)
1506       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1507
1508     if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1509       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1510
1511     if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1512       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1513
1514     if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1515       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1516   }
1517
1518   char byte;
1519   target = "";
1520   bool filler = isupNumber.OddEven;
1521   bool hasDigits = (isupNumber.Digits.size() > 0);
1522   byte = filler ? 0x80 : 0x00;
1523   byte = byte |= isupNumber.NatureOfAddress;
1524   target += byte;
1525
1526   if(calledOrCalling) {
1527     byte = isupNumber.InternalNetworkNumber << 7;
1528     byte = byte |= (isupNumber.NumberingPlan << 4);
1529   } else {
1530     byte = isupNumber.NumberIncomplete << 7;
1531     byte = byte |= (isupNumber.NumberingPlan << 4);
1532     byte = byte |= (isupNumber.AddressPresentationRestricted << 2);
1533     byte = byte |= isupNumber.Screening;
1534   }
1535
1536   target += byte;
1537   //int byte;
1538   unsigned char hex;
1539   std::string dtlc = isupNumber.Digits; // digits to lower case
1540   //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1541   const char *digits = dtlc.c_str();
1542
1543   for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1544     if(isxdigit(byte = digits [k - 1]) == 0)
1545       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1546
1547     hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1548
1549     if(isxdigit(byte = digits [k]) == 0)
1550       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1551
1552     hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1553     target += hex;
1554   }
1555
1556   if(hasDigits && filler) {
1557     if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1558       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1559
1560     target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1561   }
1562 }
1563
1564
1565 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1566   std::string target;
1567   codeIsupNumber(isupNumber, calledOrCalling, target);
1568   length = target.size();
1569   memcpy(buffer, target.c_str(), length);
1570 }
1571