Ensures normalization on waitfe/fc-xml operations
[anna.git] / source / core / functions.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <stdarg.h>
10 #include <ctype.h>
11 #include <poll.h>
12 #include <time.h>
13 #include <sys/time.h>
14 #include <pthread.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <regex.h>
19 #include <sys/utsname.h>
20 #include <arpa/inet.h>
21 #include <sys/socket.h> // extraccion de IP del hostname
22 #include <netinet/in.h> // extraccion de IP del hostname
23 #include <netdb.h> // extraccion de IP del hostname
24 #include <unistd.h> // gethostname
25
26 #include <anna/core/functions.hpp>
27 #include <anna/core/DataBlock.hpp>
28 #include <anna/core/tracing/Logger.hpp>
29 #include <anna/core/util/Second.hpp>
30 #include <anna/core/util/Tokenizer.hpp>
31
32 #include <algorithm>
33 #include <fstream>
34 #include <sstream>
35
36
37 using namespace anna;
38 using namespace std;
39
40 #define PAGE_WIDTH_LENGTH      80
41
42 static const std::string base64_chars =
43              "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
44              "abcdefghijklmnopqrstuvwxyz"
45              "0123456789+/";
46
47
48 string functions::getVersion() throw() {
49   static const int version = ANNA_VERSION;
50   string result;
51   int mainVersion = (version & 0xff00) >> 8;
52   int subVersion = (version & 0xff);
53   char aux [32];
54   sprintf(aux, "%d.%d", mainVersion, subVersion);
55   result = aux;
56   return result += getArchitecture();
57 }
58
59 /*
60 (1) Solo coge los dos primeros digitos del numero de release
61 */
62 string functions::getArchitecture() throw() {
63   string result;
64   WHEN_MULTITHREAD(result = "/MT");
65   WHEN_SINGLETHREAD(result = "/ST");
66 #ifdef _DEBUG
67   result += "/D";
68 #else
69   result += "/O";
70 #endif
71 #ifdef _PROFILE
72   result += 'P';
73 #endif
74   struct utsname un;
75   uname(&un);
76   result += '/';
77   result += un.sysname;
78   result += ' ';
79   char* release = anna_strchr(un.release, '.');               // (1)
80
81   if(release != NULL)
82     if((release = anna_strchr(release + 1, '.')) != NULL)
83       * release = 0;
84
85   result += un.release;
86   result += " (";
87   result += un.machine;
88   result += ")";
89   return result;
90 }
91
92 string functions::asString(const int number)
93 throw() {
94   char aux [16];
95   sprintf(aux, "%d", number);
96   return string(aux);
97 }
98
99 string functions::asString(const S64 number)
100 throw() {
101   char aux [24];
102   //sprintf(aux, "%lld", number);
103   #ifdef __anna64__
104      sprintf (aux, "%ld", number);
105   #else
106      sprintf (aux, "%lld", number);
107   #endif
108   return string(aux);
109 }
110
111 string functions::asString(const unsigned int number)
112 throw() {
113   char aux [16];
114   sprintf(aux, "%u", number);
115   return string(aux);
116 }
117
118 string functions::asString(const U64 number)
119 throw() {
120   char aux [16];
121   //sprintf(aux, "%llu", number);
122   #ifdef __anna64__
123      sprintf (aux, "%lu", number);
124   #else
125      sprintf (aux, "%llu", number);
126   #endif
127   return string(aux);
128 }
129
130 string functions::asString(const float number, const char* format)
131 throw() {
132   char aux [64];
133   sprintf(aux, format, number);
134   return string(aux);
135 }
136
137 string functions::asString(const double number, const char* format)
138 throw() {
139   char aux [64];
140   sprintf(aux, format, number);
141   return string(aux);
142 }
143
144 string functions::asDateTime(const Second &second)
145 throw() {
146   char aux [DateTimeSizeString];
147   return std::string(asDateTime(second, aux));
148 }
149
150 const char* functions::asDateTime(const Second &second, char* result)
151 throw() {
152   struct tm* tt = localtime((time_t*) & second);
153   sprintf(
154     result, "%02d/%02d/%4d %02d:%02d:%02d",
155     tt->tm_mday, tt->tm_mon + 1, tt->tm_year + 1900,
156     tt->tm_hour, tt->tm_min, tt->tm_sec
157   );
158   return result;
159 }
160
161 std::string functions::asString(const DataBlock& dataBlock, const int characterByLine)
162 throw() {
163   return dataBlock.asString(characterByLine);
164 }
165
166 string functions::asHexString(const int number)
167 throw() {
168   char aux [16];
169   sprintf(aux, "0x%x", number);
170   return string(aux);
171 }
172
173 string functions::asHexString(const S64 number)
174 throw() {
175   char aux [32];
176   //sprintf(aux, "0x%llx", number);
177   #ifdef __anna64__
178      sprintf (aux, "0x%lx", number);
179   #else
180      sprintf (aux, "0x%llx", number);
181   #endif
182   return string(aux);
183 }
184
185 // from a version by Allen Holub (see Andrew Binstock, "Hashing Revisited"
186 // Dr. Dobb's Journal, April 1996)
187 S64 functions::hash(const char* p)
188 throw() {
189   static const int long_bits = sizeof(S64) << 3;
190   static const int one_eighth = long_bits >> 3;
191   static const int three_fourths = long_bits * 3 / 4;
192   static const S64 high_bits = ((S64)(~0L)) << (long_bits - one_eighth);
193   S64 result = 0;
194   S64 temp;
195
196   while(*p != 0) {
197     result = (result << one_eighth) + *p ++;
198
199     if((temp = result & high_bits) != 0)
200       result = (result ^(temp >> three_fourths)) &~ high_bits;
201   }
202
203   return result;
204 }
205
206 //static
207 std::string functions::asHexString(const DataBlock& dataBlock)
208 throw() {
209   const char* buffer = dataBlock.getData();
210   const int size = dataBlock.getSize();
211   string result;
212   int byte;
213
214   for(int ii = 0; ii < size; ii ++) {
215     byte = (buffer [ii] & 0xf0) >> 4;
216     result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
217     byte = (buffer [ii] & 0x0f);
218     result += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
219   }
220
221   return result;
222 }
223
224 /**
225  * Gets the original value obtained with #asHexString (const DataBlock&).
226  * \param hexString String which contains the buffer. The format is an hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits).
227  * The input shall be preprocessed to comply with that format (e.g. colon or any other non-hex digit must be removed).
228  * \param target DataBlock for string decode.
229  * \return DataBlock corresponding to the provided string.
230  */
231 //static
232 DataBlock& functions::fromHexString(const std::string& hexString, DataBlock& target)
233 throw(RuntimeException) {
234
235   if((hexString.length() % 2) != 0)
236     throw RuntimeException("functions::fromHexString | Invalid string length", ANNA_FILE_LOCATION);
237
238   target.clear();
239   const char* src = hexString.data();
240   unsigned char hex;
241   int aux;
242
243   for(int ii = 1, maxii = hexString.length(); ii < maxii; ii += 2) {
244     if(isxdigit(aux = src [ii - 1]) == 0)
245       throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
246
247     hex = ((aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a)) << 4;
248
249     if(isxdigit(aux = src [ii]) == 0)
250       throw RuntimeException("Invalid HexString", ANNA_FILE_LOCATION);
251
252     hex |= (aux >= '0' && aux <= '9') ? (aux - '0') : ((aux - 'a') + 0x0a);
253     target += hex;
254   }
255
256   return target;
257 }
258
259 string functions::asString(const char* format, ...)
260 throw() {
261   va_list ap;
262   char aux [1024];
263   va_start(ap, format);
264   vsnprintf(aux, sizeof(aux), format, ap);
265   va_end(ap);
266   return string(aux);
267 }
268
269 void functions::sleep(const Millisecond &millisecond)
270 throw() {
271   timespec req;
272   timespec rem;
273   req.tv_sec = millisecond.getValue() / 1000;                          // segundos
274   req.tv_nsec = (millisecond.getValue() % 1000);                       // milisegundos
275   req.tv_nsec *= 1000000;                                   // mili = 10e-3, nano=10-9
276   int r;
277
278   while((r = nanosleep(&req, &rem)) != 0) {
279     if(errno == EINTR)
280       req = rem;
281     else {
282       string msg(asText("functions::sleep | timespec { sec: ", (int) req.tv_sec));
283       msg += functions::asText("| nsec: ", (int) req.tv_nsec);
284       msg += " }";
285       RuntimeException ex(msg, errno, ANNA_FILE_LOCATION);
286       ex.trace();
287       break;
288     }
289   }
290 }
291
292 bool functions::asBool(const char* str)
293 throw(RuntimeException) {
294   if(str == NULL)
295     return false;
296
297   if(strcasecmp(str, "true") == 0 || anna_strcmp(str, "1") == 0)
298     return true;
299
300   if(strcasecmp(str, "false") == 0 || anna_strcmp(str, "0") == 0)
301     return false;
302
303   string msg("anna::funcions::asBool | Cannot interpret '");
304   msg += str;
305   msg += "' as boolean";
306   throw RuntimeException(msg, ANNA_FILE_LOCATION);
307 }
308
309 S64 functions::asInteger64(const char* str)
310 throw() {
311   S64 number = 0;
312   //sscanf(str, "%lld", &number);
313   #ifdef __anna64__
314     sscanf (str, "%ld", &number);
315   #else
316      sscanf (str, "%lld", &number);
317   #endif
318   return number;
319 }
320
321 pthread_t functions::getCurrentThread()
322 throw() {
323   WHEN_MULTITHREAD(return pthread_self());
324   WHEN_SINGLETHREAD(return 0);
325 }
326
327 bool functions::isLike(const char* pattern, const std::string& _value)
328 throw(RuntimeException) {
329   const char* value = _value.c_str();
330   regex_t preg;
331   int ret;
332
333   if((ret = regcomp(&preg, pattern, REG_EXTENDED)) != 0) {
334     char err[256];
335     string msg("anna::functions::isLike | ");
336     msg += " | Pattern: ";
337     msg += pattern;
338     msg += " | Value: ";
339     msg += value;
340     msg += " | ";
341
342     if(regerror(ret, &preg, err, sizeof(err)))
343       msg += err;
344     else
345       msg += "Invalid pattern";
346
347     throw RuntimeException(msg, ANNA_FILE_LOCATION);
348   }
349
350   const bool result = (regexec(&preg, value, 0, NULL, 0) == 0) ? true : false;
351
352   regfree(&preg);
353   return result;
354 }
355
356 /*static*/
357 S64 functions::merge(const char* whatis, const int n1, const int n2, const int bitShift)
358 throw(RuntimeException) {
359   if(bitShift > intBitSize) {
360     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | bitShift must be less than %d", whatis, n1, n2, bitShift, intBitSize));
361     throw RuntimeException(msg, ANNA_FILE_LOCATION);
362   }
363
364   if((bitsize(n1) + bitShift) > int64BitSize) {
365     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N1 overload", whatis, n1, n2, bitShift));
366     throw RuntimeException(msg, ANNA_FILE_LOCATION);
367   }
368
369   if(bitsize(n2) > bitShift) {
370     string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | N2 overload", whatis, n1, n2, bitShift));
371     throw RuntimeException(msg, ANNA_FILE_LOCATION);
372   }
373
374   S64 result = n1;
375   result <<= bitShift;
376   result |= n2;
377
378   if(bitShift == intBitSize) {
379     LOGINFORMATION(
380       string msg(functions::asString("%s | N1: 0x%x | N2: 0x%x | bitShift: %d | ", whatis, n1, n2, bitShift));
381       msg += functions::asHexString(result);
382       Logger::information(msg, ANNA_FILE_LOCATION);
383     );
384   }
385
386   return result;
387 }
388
389 /*static*/
390 /*
391  * Basado en el algoritmo de http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
392  */
393 int functions::log2(const unsigned int v)
394 throw() {
395   static const signed char LogTable256[] = {
396     -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
397     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
398     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
399     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
400     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
401     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
402     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
403     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
404     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
405     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
406     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
407     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
408     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
409     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
410     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
411     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
412   };
413   int r = -1;     // r will be lg(v)
414   unsigned int t, tt; // temporaries
415
416   if((tt = v >> 16)) {
417     r = ((t = tt >> 8)) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
418   } else {
419     r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
420   }
421
422   return r;
423 }
424
425 std::string functions::entriesAsString(int number, const char * wordForSingular, const char * wordForPlural) throw() {
426   std::string result;
427   std::string singular = (wordForSingular ? wordForSingular : "entry");
428   std::string plural = (wordForPlural ? wordForPlural : "entries");
429
430   if(wordForSingular && !wordForPlural)
431     plural = singular + "s";
432
433   result += ((number != 0) ? anna::functions::asString(number) : "no");
434   result += " ";
435   result += ((number != 1) ? plural : singular);
436   return result;
437 }
438
439
440 std::string functions::justify(const std::string & title, TextJustifyMode::_v mode, char filler) throw() {
441   std::string result;
442   int d_size = title.size();
443   int repeat = PAGE_WIDTH_LENGTH - d_size - 1;
444   bool adjust = false;
445
446   if(mode == TextJustifyMode::Center) {
447     repeat = (repeat - 1) / 2;
448     adjust = (2 * (repeat + 1) + d_size != PAGE_WIDTH_LENGTH);
449   }
450
451   if((mode == TextJustifyMode::Right) || (mode == TextJustifyMode::Center)) {
452     for(int k = 0; k < (repeat + (adjust ? 1 : 0)); k++) result += filler;
453
454     result += " ";
455   }
456
457   result += title;
458
459   if((mode == TextJustifyMode::Left) || (mode == TextJustifyMode::Center)) {
460     result += " ";
461
462     for(int k = 0; k < repeat; k++) result += filler;
463   }
464
465   return result;
466 }
467
468
469 std::string functions::highlight(const std::string & title, TextHighlightMode::_v mode, char filler, bool appendCR) throw() {
470   std::string result;
471   int ou_repeat = title.size();
472   int lr_repeat = PAGE_WIDTH_LENGTH - ou_repeat - 1;
473   bool adjust = false;
474
475   if(mode == TextHighlightMode::LeftAndRightline) {
476     lr_repeat = (lr_repeat - 1) / 2;
477     adjust = (2 * (lr_repeat + 1) + ou_repeat != PAGE_WIDTH_LENGTH);
478   }
479
480   if((mode == TextHighlightMode::Leftline) || (mode == TextHighlightMode::LeftAndRightline)) {
481     for(int k = 0; k < (lr_repeat + (adjust ? 1 : 0)); k++) result += filler;
482
483     result += " ";
484   }
485
486   if((mode == TextHighlightMode::Overline) || (mode == TextHighlightMode::OverAndUnderline)) {
487     for(int k = 0; k < ou_repeat; k++) result += filler;
488
489     result += "\n";
490   }
491
492   result += title;
493
494   if((mode == TextHighlightMode::Underline) || (mode == TextHighlightMode::OverAndUnderline)) {
495     result += "\n";
496
497     for(int k = 0; k < ou_repeat; k++) result += filler;
498   }
499
500   if((mode == TextHighlightMode::Rightline) || (mode == TextHighlightMode::LeftAndRightline)) {
501     result += " ";
502
503     for(int k = 0; k < lr_repeat; k++) result += filler;
504   }
505
506   if(appendCR) result += "\n";
507
508   return result;
509 }
510
511
512 std::string functions::tab(const std::string & text, int tabSpaces) throw() {
513   std::string result;
514   size_t pos, from = 0;
515   std::string tab, crTab = "\n";
516
517   for(int k = 0; k < tabSpaces; k++) tab += " ";
518
519   crTab += tab;
520   result = tab;
521   result += text;
522
523   while(((pos = result.find('\n', from)) != std::string::npos) && (pos != (result.size() - 1)/*exclude last CR if exists*/)) {
524     result.replace(pos, 1, crTab);
525     from = pos + 1;
526   }
527
528   return result;
529 }
530
531
532 bool functions::endsWith(const std::string & pattern, const std::string & suffix, std::string & preffix) throw() {
533   preffix = "";
534
535   if(pattern.size() < suffix.size()) return false;
536
537   size_t pos = pattern.rfind(suffix);
538
539   if(pos == std::string::npos) return false;
540
541   preffix.assign(pattern.c_str(), pos);
542   return (pos == (pattern.size() - suffix.size()));
543 }
544
545
546 bool functions::startsWith(const std::string & pattern, const std::string & preffix, std::string & suffix) throw() {
547   suffix = "";
548
549   if(pattern.size() < preffix.size()) return false;
550
551   if(pattern.find(preffix) != 0) return false;
552
553   suffix.assign(pattern.c_str(), preffix.size(), pattern.size() - preffix.size());
554   return true;
555 }
556
557
558 std::string functions::replace(const std::string & text, const char *item, const char *target, bool all) throw() {
559   std::string result = text;
560
561   if(!item || !target) return result;  // protection for NULL strings provided
562
563   size_t lengthReplaced = strlen(item);
564   size_t pos = result.find(item);
565
566   while(pos != std::string::npos) {
567     result.replace(pos, lengthReplaced, target);
568
569     if(!all) break;
570
571     pos = result.find(item);
572   }
573
574   return result;
575 }
576
577
578 std::string functions::addQuotationMarks(const std::string & str) throw() {
579   std::string result = "'";
580   result += str;
581   result += "'";
582   return (result);
583 }
584
585
586 std::string functions::addQuotationMarks(const char * str) throw() {
587   std::string result = "'";
588   result += (str ? str : "<null>");
589   result += "'";
590   return (result);
591 }
592
593
594 std::string functions::addQuotationMarks(const int & integer) throw() {
595   std::string result = "'";
596   result += anna::functions::asString(integer);
597   result += "'";
598   return (result);
599 }
600
601
602 std::string functions::vectorToStringRepresentation(const std::vector<int> & v, const char separator) throw() {
603   std::string result = "";
604
605   if(v.size() != 0) {
606     std::vector<int>::const_iterator iter;
607     std::vector<int>::const_iterator iter_min(v.begin());
608     std::vector<int>::const_iterator iter_max(v.end());
609
610     for(iter = iter_min; iter != iter_max; iter++) {
611       result += anna::functions::asString(*iter);
612       result += separator;
613     }
614
615     // Delete the last space: starts at 'size()-1', take 1 caracter:
616     result.erase(result.size() - 1, 1);
617   }
618
619   return (result);
620 }
621
622
623 std::string functions::vectorToStringRepresentation(const std::vector<std::string> & v, const char separator) throw() {
624   std::string result = "";
625
626   if(v.size() != 0) {
627     std::vector<std::string>::const_iterator iter;
628     std::vector<std::string>::const_iterator iter_min(v.begin());
629     std::vector<std::string>::const_iterator iter_max(v.end());
630
631     for(iter = iter_min; iter != iter_max; iter++) {
632       result += (*iter);
633       result += separator;
634     }
635
636     // Delete the last space: starts at 'size()-1', take 1 caracter:
637     result.erase(result.size() - 1, 1);
638   }
639
640   return (result);
641 }
642
643
644 std::string functions::socketLiteralAsString(const std::string & address, int port) throw() {
645   std::string result = address;
646   result += ":";
647   result += anna::functions::asString(port);
648   return result;
649 }
650
651
652 std::string functions::asAsciiString(const char * buffer, int size, bool & isFullyPrintable) throw() {
653   std::string result;
654   // Supposed printable by default:
655   isFullyPrintable = true;
656
657   if(size == 0 || !buffer) {
658     result = "<null>";
659     isFullyPrintable = false;
660     return result;
661   }
662
663   for(int k = 0; k < size; k ++) {
664     unsigned char c = (unsigned char) buffer [k];
665     int printable = isprint(c);
666     result += (printable ? (char) c : '.');
667
668     if(!printable) isFullyPrintable = false;
669   }
670
671   return result;
672 }
673
674
675 std::string functions::getHostname() throw() {
676   char aux[255];
677   std::string result = "<hostname>";
678
679   if(gethostname(aux, sizeof aux) == 0 /*success*/)
680     result = aux;
681
682   return result;
683 }
684
685 std::string functions::getDomainname() throw() {
686   char aux[256];
687   std::string result = "<domainname>";
688
689   if(getdomainname(aux, sizeof aux) == 0 /*success*/)
690     result = aux;
691
692   return result;
693 }
694
695 std::string functions::getFQDN(const char *hostname, const char *domainname) throw() {
696   std::string hn = hostname ? hostname : (functions::getHostname());
697   std::string dn = domainname ? domainname : (functions::getDomainname());
698   // FQDN is limited to 255 bytes, with aditional restriction: 63 bytes label within a domain name.
699
700   if(hn == "") return dn;
701
702   if(dn == "") return hn;
703
704   std::string label(hn, 0, 63);
705   std::string fqdn(label + "." + dn, 0, 255);
706   return fqdn;
707 }
708
709 std::string functions::getHostnameIP() throw() {
710   std::string result = "";
711   struct hostent *he;
712   struct in_addr **addr_list;
713   char hostname[128];
714   gethostname(hostname, sizeof hostname);
715
716   if((he = gethostbyname(hostname)) != NULL) {
717     // Official name: he->h_name
718     // IP addresses:
719     addr_list = (struct in_addr **)he->h_addr_list;
720
721     for(int i = 0; addr_list[i] != NULL; i++) {
722       //printf("%s ", inet_ntoa(*addr_list[i]));
723       result = inet_ntoa(*addr_list[i]);
724       return result;
725     }
726   }
727
728   return result;
729 }
730
731
732 anna::DataBlock functions::rawIpPresentationAsRaw(const std::string & rawPresentation) throw(anna::RuntimeException) {
733   int length = rawPresentation.size();
734
735   if(length != 8 && length != 32)
736     throw anna::RuntimeException("functions::rawIpPresentationAsRaw | Expected 8 or 32-sized raw IP presentation provided", ANNA_FILE_LOCATION);
737
738   anna::DataBlock result(true);
739   int byte;
740   char rByte[3]; // readable byte
741   rByte[2] = 0;
742
743   for(int k = 0; k < length; k += 2) {
744     rByte[0] =  rawPresentation[k];
745     rByte[1] = rawPresentation[k + 1];
746     sscanf(rByte, "%x", &byte);
747     result += byte;
748   }
749
750   return result;
751 }
752
753
754 std::string functions::rawIpAsRawIpPresentation(const anna::DataBlock & db) throw(anna::RuntimeException) {
755   int length = db.getSize();
756
757   if(length != 4 && length != 16)
758     throw anna::RuntimeException("functions::rawIpAsRawIpPresentation | Expected 4 or 16-sized raw IP DataBlock provided", ANNA_FILE_LOCATION);
759
760   std::string result = "";
761   int byte;
762   char rByte[3]; // readable byte
763   rByte[2] = 0;
764
765   for(int k = 0; k < length; k++) {
766     byte = (unsigned char)db[k];
767     sprintf(rByte, "%.2X", byte);
768     result += rByte;
769   }
770
771   return result;
772 }
773
774
775
776 ////////////////////
777 // Address Format //
778 ////////////////////
779 //   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:
780 //   A typical example of an IPv6 address is
781 //   2001:0db8:85a3:0000:0000:8a2e:0370:7334
782 //   The hexadecimal digits are case-insensitive.
783 //
784 //   The 128-bit IPv6 address can be abbreviated with the following rules:
785 //   -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
786 //   -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
787 //   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.
788
789 //      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.
790 //      Así, las siguientes son representaciones posibles de una misma dirección:
791 //
792 //      2001:0DB8:0000:0000:0000:0000:1428:57ab
793 //      2001:0DB8:0000:0000:0000::1428:57ab
794 //      2001:0DB8:0:0:0:0:1428:57ab
795 //      2001:0DB8:0::0:1428:57ab
796 //      2001:0DB8::1428:57ab
797 //      son todas válidas y significan lo mismo, pero
798 //      2001::25de::cade
799 //          --    --
800 //      no es válida porque no queda claro cuántos grupos nulos hay en cada lado.
801 //
802 //      Los ceros iniciales en un grupo también se pueden omitir:
803 //      2001:0DB8:02de::0e13
804 //      2001:DB8:2de::e13
805 //
806 //      Si la dirección es una dirección IPv4 empotrada (mapped), los Ãºltimos 32 bits pueden escribirse en base decimal, así:
807 //      ::ffff:192.168.89.9
808 //      ::ffff:c0a8:5909
809 //
810 //      No se debe confundir con:
811 //      ::192.168.89.9
812 //      ::c0a8:5909
813 //
814 //      El formato ::ffff:1.2.3.4 se denomina dirección IPv4 mapeada, y el formato ::1.2.3.4 dirección IPv4 compatible.
815 //      Las direcciones IPv4 pueden ser transformadas fácilmente al formato IPv6. Por ejemplo, si la dirección decimal IPv4 es 135.75.43.52
816 //       (en hexadecimal, 0x874B2B34), puede ser convertida a 0000:0000:0000:0000:0000:0000:874B:2B34 o ::874B:2B34. Entonces, uno puede usar
817 //       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
818 //       casi no está siendo utilizada en la práctica, aunque los estándares no la han declarado obsoleta.
819 //
820 // http://tools.ietf.org/html/rfc5952: canonical text representation recommendation
821
822 bool functions::isIPv4(const std::string & ip, IPv4Type::_v ipv4Type) throw() {
823   if(ipv4Type == IPv4Type::Estrict) {
824     // La expresión regular no controla si hay mas de 3 puntos:
825     int n_dot = 0;
826
827     for(int k = 0; k < ip.length(); k++)
828       if(ip[k] == '.') n_dot++;
829
830     if(n_dot > 3)
831       return (false);
832
833     bool ipv4 = anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, ip);
834     bool colon = (ip.find(":") != std::string::npos);
835     return (ipv4 && !colon);
836   }
837
838   if(ipv4Type == IPv4Type::Compatible) {
839     std::string pureIPv4 = ip;
840     bool firstDoubleColon = (ip.find("::") == 0);
841
842     if(firstDoubleColon) {
843       pureIPv4.erase(0, 2);
844       bool anotherColon = (pureIPv4.find(":") != std::string::npos);
845
846       if(anotherColon) return (false);
847
848       return (anna::functions::isLike(s_REGEXP_IPv4_ADDRESSES, pureIPv4));
849     }
850   }
851
852   if(ipv4Type == IPv4Type::Mapped) {
853     size_t posLastColon = ip.rfind(":");
854
855     if(posLastColon == std::string::npos)
856       return (false);
857
858     if(!isIPv4(ip.substr(posLastColon + 1)))
859       return (false);
860
861     unsigned char buf[sizeof(struct in6_addr)];
862     int s = inet_pton(AF_INET6, ip.c_str(), buf);
863
864     if(s > 0)
865       return (true);
866   }
867
868   return false;
869 }
870
871
872 bool functions::isIPv6(const std::string & ip) throw() {
873   // Chequeo de digitos permitidos:
874   for(int k = 0; k < ip.length(); k++) {
875     bool digit = isdigit(ip[k]);
876     bool hex = ((ip[k] == 'a') ||
877                 (ip[k] == 'b') ||
878                 (ip[k] == 'c') ||
879                 (ip[k] == 'd') ||
880                 (ip[k] == 'e') ||
881                 (ip[k] == 'f') ||
882                 (ip[k] == 'A') ||
883                 (ip[k] == 'B') ||
884                 (ip[k] == 'C') ||
885                 (ip[k] == 'D') ||
886                 (ip[k] == 'E') ||
887                 (ip[k] == 'F'));
888     bool colon = (ip[k] == ':');
889
890     if(!digit && !hex && !colon)
891       return false;
892   }
893
894   return (anna::functions::isLike(s_REGEXP_IPv6_ADDRESSES, ip));
895 }
896
897
898 std::string functions::IPv4To6(const std::string & ip) throw(anna::RuntimeException) {
899   if(!isIPv4(ip, IPv4Type::Estrict) && !isIPv4(ip, IPv4Type::Compatible) && !isIPv4(ip, IPv4Type::Mapped))
900     throw anna::RuntimeException("functions::IPv4To6 | Expected IPv4, IPv4-compatible or IPv4-mapped address format", ANNA_FILE_LOCATION);
901
902   std::string result, pureIPv4;
903   bool firstDoubleColon = (ip.find("::") == 0);
904
905   if(firstDoubleColon) {
906     // Clean '::'
907     size_t ipv4_pos = ip.rfind(":") /* last ocurrence */ + 1;
908     pureIPv4 = ip.substr(ipv4_pos);
909   } else {
910     if(!isIPv4(ip)) {
911       size_t posColon = ip.find(":");
912
913       if(posColon == 0)  // first colon
914         throw anna::RuntimeException("functions::IPv4To6 | Invalid IPv4 address format", ANNA_FILE_LOCATION);
915
916       if(posColon != std::string::npos)  // any colon
917         return ip; // seems to be IPv6 already?
918
919       throw anna::RuntimeException("functions::IPv4To6 | Unreconized IPv4 address format", ANNA_FILE_LOCATION);
920     }
921
922     pureIPv4 = ip;
923   }
924
925   // Number of ocurrences for '.'
926   int n_dot = 0;
927
928   for(int k = 0; k < pureIPv4.length(); k++)
929     if(pureIPv4[k] == '.') n_dot++;
930
931   if(n_dot > 3)
932     throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (more than three dots!)", ANNA_FILE_LOCATION);
933
934   anna::Tokenizer tok;
935   anna::Tokenizer::const_iterator tok_it;
936   std::string token;
937   tok.apply(pureIPv4, ".");
938   int v[4];
939   int cnt = 0;
940
941   for(tok_it = tok.begin(); tok_it != tok.end(); tok_it ++) {
942     token = anna::Tokenizer::data(tok_it);
943     v[cnt] = atoi(anna::Tokenizer::data(tok_it));
944
945     if(v[cnt] < 0 || v[cnt] > 255)
946       throw anna::RuntimeException("functions::IPv4To6 | Wrong IPv4 address format (any value out of range 0-255)", ANNA_FILE_LOCATION);
947
948     cnt++;
949   }
950
951   if(isIPv4(ip, IPv4Type::Compatible))
952     result = anna::functions::asString("::%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
953   else
954     result = anna::functions::asString("::ffff:%04x:%04x", v[0] * 256 + v[1], v[2] * 256 + v[3]);
955
956   return result;
957 }
958
959
960 std::string functions::normalizeIP(const std::string & ip) throw(anna::RuntimeException) {
961   std::string result = ip;
962 //   std::transform(result.begin(), result.end(), result.begin(), (int (*)(int))std::tolower);
963   std::transform(result.begin(), result.end(), result.begin(), ::tolower);
964
965   if(isIPv4(ip, IPv4Type::Estrict) || isIPv4(ip, IPv4Type::Compatible) || isIPv4(ip, IPv4Type::Mapped))
966     result = IPv4To6(result);
967
968   size_t pos = result.find("::"); // zeroes simplification group
969   size_t rpos = result.rfind("::"); // zeroes simplification group
970
971   if(pos != rpos)
972     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (more than one simplification group '::')", ANNA_FILE_LOCATION);
973
974   if(pos != std::string::npos) {  // zeroes exists
975     // string ( size_t n, char c ) -> content is initialized as a string formed by a repetition of character c, n times.
976     // Number of ocurrences for ':'
977     int n_colon = 0;
978
979     for(int k = 0; k < result.length(); k++)
980       if(result[k] == ':') n_colon++;
981
982     // Generate equivalent to '::'
983     std::string equiv_str;
984
985     for(int k = 0; k < (8 - n_colon); k++)
986       equiv_str += ":0";
987
988     equiv_str += ":";
989     // Replace with equivalent:
990     result.replace(pos, 2, equiv_str);
991
992     // Special case: IP began with '::'
993     if(result[0] == ':') {
994       result.insert(0, "0");
995     }
996
997     // Special case: IP was only '::'
998     if(result[result.length() - 1] == ':') {
999       result += "0";
1000     }
1001   }
1002
1003   // Protection: it must be seven colons:
1004   int n_colon = 0;
1005
1006   for(int k = 0; k < result.length(); k++)
1007     if(result[k] == ':') n_colon++;
1008
1009   if(n_colon != 7)
1010     throw anna::RuntimeException("functions::normalizeIP | Wrong IPv6 address format (missing any 16-bit group)", ANNA_FILE_LOCATION);
1011
1012   // Padding with zeroes at left
1013   anna::Tokenizer ipStr;
1014   anna::Tokenizer::const_iterator ipStr_it;
1015   std::string token;
1016   ipStr.apply(result, ":");
1017   result = "";
1018
1019   for(ipStr_it = ipStr.begin(); ipStr_it != ipStr.end(); ipStr_it ++) {
1020     token = anna::Tokenizer::data(ipStr_it);
1021
1022     while(token.length() < 4) token.insert(0, "0");
1023
1024     result += token;
1025     result += ":";
1026   }
1027
1028   // Remove last ':'
1029   size_t lastPos = result.length() - 1;
1030   result.erase(lastPos, 1);
1031
1032   // Chequeo de digitos permitidos:
1033   for(int k = 0; k < result.length(); k++) {
1034     bool digit = isdigit(result[k]);
1035     bool hex = ((result[k] == 'a') ||
1036                 (result[k] == 'b') ||
1037                 (result[k] == 'c') ||
1038                 (result[k] == 'd') ||
1039                 (result[k] == 'e') ||
1040                 (result[k] == 'f'));
1041     bool colon = (result[k] == ':');
1042
1043     if(!digit && !hex && !colon) {
1044       throw anna::RuntimeException("functions::normalizeIP | Invalid address format (only digits (0-9) and hex digits are allowed)", ANNA_FILE_LOCATION);
1045     }
1046   }
1047
1048   return result;
1049 }
1050
1051
1052 bool functions::sameIP(const std::string & ip1, const std::string & ip2) throw(anna::RuntimeException) {
1053   //if (ip1 == ip2) return true; it should validate wrong-format addresses
1054   return (normalizeIP(ip1) == normalizeIP(ip2));
1055 }
1056
1057
1058 bool functions::matchIPv6(const std::string & _ipv6, const std::string & preffixedIpv6) throw(anna::RuntimeException) {
1059   size_t preffixPos = preffixedIpv6.find("/");
1060
1061   if(preffixPos == std::string::npos)
1062     return (sameIP(_ipv6, preffixedIpv6));
1063
1064   std::string ipv6 = _ipv6;
1065
1066   if(isIPv4(_ipv6, IPv4Type::Estrict) || isIPv4(_ipv6, IPv4Type::Compatible) || isIPv4(_ipv6, IPv4Type::Mapped)) ipv6 = IPv4To6(_ipv6);
1067
1068   std::string _ipv6_2 = preffixedIpv6.substr(0, preffixPos);
1069   std::string ipv6_2 = _ipv6_2;
1070
1071   if(isIPv4(_ipv6_2, IPv4Type::Estrict) || isIPv4(_ipv6_2, IPv4Type::Compatible) || isIPv4(_ipv6_2, IPv4Type::Mapped)) ipv6_2 = IPv4To6(_ipv6_2);
1072
1073   std::string preffix = preffixedIpv6.substr(preffixPos + 1);
1074   int ipv6_2_preffixLength = atoi(preffix.c_str());
1075
1076   if(ipv6_2_preffixLength < 0 || ipv6_2_preffixLength > 128)
1077     throw anna::RuntimeException("functions::matchIPv6 | Invalid Ipv6 preffix length: out of range [0,128]", ANNA_FILE_LOCATION);
1078
1079   // No restriction, all ipv6_2 ignored (special and not usual case)
1080   if(ipv6_2_preffixLength == 0) return true;
1081
1082   // Auxiliary data:
1083   int spare = ipv6_2_preffixLength /* bits */ % 8; // bytes
1084   int incompletedRestrictionBytes = ipv6_2_preffixLength / 8;
1085   int completedRestrictionBytes = incompletedRestrictionBytes + ((spare != 0) ? 1 : 0);
1086   char mask = 0xFF << (8 - spare);
1087   // Limit ipv6
1088   anna::DataBlock rawIP1 = ipAsRaw(ipv6);
1089   anna::DataBlock restrictedIP1(true);
1090   restrictedIP1.assign(rawIP1.getData(), incompletedRestrictionBytes);
1091
1092   if(spare != 0) restrictedIP1 += rawIP1[incompletedRestrictionBytes] & mask;
1093
1094   // Limit ipv6_2
1095   anna::DataBlock rawIP2 = ipAsRaw(ipv6_2);
1096   anna::DataBlock realIP2(true);
1097   realIP2.assign(rawIP2.getData(), incompletedRestrictionBytes);
1098
1099   if(spare != 0) realIP2 += rawIP2[incompletedRestrictionBytes] & mask;
1100
1101   // Comparison
1102   int n = memcmp(restrictedIP1.getData(), realIP2.getData(), completedRestrictionBytes);
1103   return (n == 0);
1104 }
1105
1106
1107 anna::DataBlock functions::ipAsRaw(const std::string & ip) throw(anna::RuntimeException) {
1108   anna::DataBlock result(true);
1109
1110   if(isIPv4(ip)) {
1111     unsigned char buf[sizeof(struct in6_addr)];
1112     int s = inet_pton(AF_INET, ip.c_str(), buf);
1113
1114     if(s > 0) {
1115       result += (S8)buf[0];
1116       result += (S8)buf[1];
1117       result += (S8)buf[2];
1118       result += (S8)buf[3];
1119     } else {
1120       if(s < 0) perror("inet_pton");
1121
1122       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv4 address format", ANNA_FILE_LOCATION);
1123     }
1124   } else {
1125     unsigned char buf[sizeof(struct in6_addr)];
1126     int s = inet_pton(AF_INET6, ip.c_str(), buf);
1127
1128     if(s > 0) {
1129       result += (S8)buf[0];
1130       result += (S8)buf[1];
1131       result += (S8)buf[2];
1132       result += (S8)buf[3];
1133       result += (S8)buf[4];
1134       result += (S8)buf[5];
1135       result += (S8)buf[6];
1136       result += (S8)buf[7];
1137       result += (S8)buf[8];
1138       result += (S8)buf[9];
1139       result += (S8)buf[10];
1140       result += (S8)buf[11];
1141       result += (S8)buf[12];
1142       result += (S8)buf[13];
1143       result += (S8)buf[14];
1144       result += (S8)buf[15];
1145     } else {
1146       if(s < 0) perror("inet_pton");
1147
1148       throw anna::RuntimeException("functions::ipAsRaw | Wrong IPv6 address format", ANNA_FILE_LOCATION);
1149     }
1150   }
1151
1152   return result;
1153   // Alternativa
1154   //   anna::DataBlock result(true);
1155   //
1156   //
1157   //   if (isIPv4(ip)) {
1158   //
1159   //      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/)
1160   //      sscanf(ip.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
1161   //      result += (S8)dec1;
1162   //      result += (S8)dec2;
1163   //      result += (S8)dec3;
1164   //      result += (S8)dec4;
1165   //   }
1166   //   else {
1167   //
1168   //      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/)
1169   //      sscanf(normalizeIP(ip).c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
1170   //      result += ((S8)(hex1 >> 8));
1171   //      result += ((S8)(hex1 & 0x00FF));
1172   //      result += ((S8)(hex2 >> 8));
1173   //      result += ((S8)(hex2 & 0x00FF));
1174   //      result += ((S8)(hex3 >> 8));
1175   //      result += ((S8)(hex3 & 0x00FF));
1176   //      result += ((S8)(hex4 >> 8));
1177   //      result += ((S8)(hex4 & 0x00FF));
1178   //      result += ((S8)(hex5 >> 8));
1179   //      result += ((S8)(hex5 & 0x00FF));
1180   //      result += ((S8)(hex6 >> 8));
1181   //      result += ((S8)(hex6 & 0x00FF));
1182   //      result += ((S8)(hex7 >> 8));
1183   //      result += ((S8)(hex7 & 0x00FF));
1184   //      result += ((S8)(hex8 >> 8));
1185   //      result += ((S8)(hex8 & 0x00FF));
1186   //   }
1187   //
1188   //
1189   //   return result;
1190 }
1191
1192
1193 std::string functions::rawIpAsString(const char *buffer, int bufferLength, bool normalize) throw(anna::RuntimeException) {
1194   std::string result = "";
1195   char str[INET6_ADDRSTRLEN];
1196
1197   if(bufferLength == 4) {
1198     if(inet_ntop(AF_INET, buffer, str, INET_ADDRSTRLEN) != NULL)
1199       result = str;
1200   } else if(bufferLength == 16) {
1201     if(inet_ntop(AF_INET6, buffer, str, INET6_ADDRSTRLEN) != NULL)
1202       result = str;
1203   } else
1204     throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1205
1206   if(result == "")
1207     throw anna::RuntimeException("functions::rawIpAsString | Wrong IP address serialization (check range value)", ANNA_FILE_LOCATION);
1208
1209   return (normalize ? normalizeIP(result) : result);
1210   // Alternativa:
1211   //   std::string result;
1212   //
1213   //
1214   //   if (bufferLength == 4) { // IPv4
1215   //      result = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[0], (U8)buffer[1], (U8)buffer[2], (U8)buffer[3]);
1216   //   }
1217   //   else if (bufferLength == 16) { // IPv6
1218   //      result = anna::functions::asString("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
1219   //                       ((((U8)buffer[0]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
1220   //                       (((U8)buffer[1])        & 0x00FF),
1221   //                       ((((U8)buffer[2]) << 8) & 0xFF00) +
1222   //                       (((U8)buffer[3])        & 0x00FF),
1223   //                       ((((U8)buffer[4]) << 8) & 0xFF00) +
1224   //                       (((U8)buffer[5])        & 0x00FF),
1225   //                       ((((U8)buffer[6]) << 8) & 0xFF00) +
1226   //                       (((U8)buffer[7])        & 0x00FF),
1227   //                       ((((U8)buffer[8]) << 8) & 0xFF00) +
1228   //                       (((U8)buffer[9])        & 0x00FF),
1229   //                       ((((U8)buffer[10]) << 8) & 0xFF00) +
1230   //                       (((U8)buffer[11])        & 0x00FF),
1231   //                       ((((U8)buffer[12]) << 8) & 0xFF00) +
1232   //                       (((U8)buffer[13])        & 0x00FF),
1233   //                       ((((U8)buffer[14]) << 8) & 0xFF00) +
1234   //                       (((U8)buffer[15])        & 0x00FF));
1235   //   }
1236   //   else
1237   //      throw anna::RuntimeException("functions::rawIpAsString | Unreconized IP address format (only 4-byte for IPv4, and 16-byte for IPv6 are allowed)", ANNA_FILE_LOCATION);
1238   //
1239   //
1240   //   return (normalize ? normalizeIP(result):result);
1241 }
1242
1243
1244 void functions::getAddressAndPortFromSocketLiteral(const std::string &literal, std::string &address, int &port) throw() {
1245   size_t pos = literal.find_last_of(":");
1246   size_t lastPos = literal.size() - 1;
1247   address = ""; port = -1; // assume error
1248
1249   if((pos != std::string::npos) && (pos != lastPos)) {
1250     address = literal.substr(0, pos);
1251     port = atoi(literal.substr(pos + 1, lastPos).c_str());
1252   }
1253 }
1254
1255
1256 socket_v functions::getSocketVectorFromString(const std::string & list) throw() {
1257   socket_v result;
1258   std::string address;
1259   int port;
1260   anna::Tokenizer lst;
1261   lst.apply(list, ",");
1262
1263   if(lst.size() < 1) return result;
1264
1265   anna::Tokenizer::const_iterator tok_min(lst.begin());
1266   anna::Tokenizer::const_iterator tok_max(lst.end());
1267   anna::Tokenizer::const_iterator tok_iter;
1268
1269   for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) {
1270     getAddressAndPortFromSocketLiteral(anna::Tokenizer::data(tok_iter), address, port);
1271
1272     if(port == -1) { result.clear(); return result; }
1273
1274     result.push_back(socket_t(address, port));
1275   }
1276
1277   return result;
1278 }
1279
1280 std::string functions::socketVectorAsString(const socket_v & socketVector) throw() {
1281   std::string result;
1282   socket_v_it it;
1283   socket_v_it it_min(socketVector.begin());
1284   socket_v_it it_max(socketVector.end());
1285
1286   for(it = it_min; it != it_max; it++) {
1287     result += anna::functions::asString("%s:%d,", (*it).first.c_str(), (*it).second);
1288   }
1289
1290   result.erase(result.size() - 1, 1);  // remove last comma
1291   return result;
1292 }
1293
1294 bool functions::littleEndian()
1295 throw() {
1296   int i = 1;
1297   char *p = (char *) &i;
1298   if (p[0] == 1) return true;
1299   return false;
1300 }
1301
1302 const char* functions::codeInteger(char* result, const int n)
1303 throw() {
1304   int aux(htonl(n));
1305   char* w((char*) &aux);
1306   *result = *w;
1307   *(result + 1) = *(w + 1);
1308   *(result + 2) = *(w + 2);
1309   *(result + 3) = *(w + 3);
1310   return result;
1311 }
1312
1313 const char* functions::codeShort(char* result, const short int n)
1314 throw() {
1315   short int aux(htons(n));
1316   char* w((char*) &aux);
1317   *result = *w;
1318   *(result + 1) = *(w + 1);
1319   return result;
1320 }
1321
1322 const char* functions::codeInteger64(char* result, const S64 n)
1323 throw() {
1324   S64 aux(0xffffffff);
1325   int n2;
1326   aux <<= 32;
1327   aux &= n;
1328   n2 = (aux >> 32) & 0xffffffff;
1329   codeInteger(result, n2);
1330   n2 = n & 0xffffffff;
1331   codeInteger(result + sizeof(int), n2);
1332   return result;
1333 }
1334
1335 /*static*/
1336 const char* functions::codeFloat(char* result, const float n)
1337 throw() {
1338   int ii;
1339   anna_memcpy(&ii, &n, sizeof(n));
1340   return functions::codeInteger(result, ii);
1341 }
1342
1343 /*static*/
1344 const char* functions::codeDouble(char* result, const double n)
1345 throw() {
1346   S64 ii;
1347   anna_memcpy(&ii, &n, sizeof(n));
1348   return functions::codeInteger64(result, ii);
1349 }
1350
1351 int functions::decodeInteger(const char* data)
1352 throw() {
1353   int result;
1354   char* w((char*) &result);
1355   *w  = *data;
1356   *(w + 1) = *(data + 1);
1357   *(w + 2) = *(data + 2);
1358   *(w + 3) = *(data + 3);
1359   return ntohl(result);
1360 }
1361
1362 short int functions::decodeShort(const char* data)
1363 throw() {
1364   short int result;
1365   char* w((char*) &result);
1366   *w  = *data;
1367   *(w + 1) = *(data + 1);
1368   return ntohs(result);
1369 }
1370
1371 S64 functions::decodeInteger64(const char* data)
1372 throw() {
1373   S64 result(decodeInteger(data));
1374   result <<= 32;
1375   return result |= (decodeInteger(data + sizeof(int)) & 0xffffffff);
1376 }
1377
1378 /*static*/
1379 float functions::decodeFloat(const char* data)
1380 throw() {
1381   float result;
1382   int ii = functions::decodeInteger(data);
1383   anna_memcpy(&result, &ii, sizeof(result));
1384   return result;
1385 }
1386
1387 /*static*/
1388 double functions::decodeDouble(const char* data)
1389 throw() {
1390   double result;
1391   S64 ii = functions::decodeInteger64(data);
1392   anna_memcpy(&result, &ii, sizeof(result));
1393   return result;
1394 }
1395
1396
1397
1398 void functions::decodeIsupNumber(const char *buffer, int length, isup_number_t & isupNumber, bool calledOrCalling) throw(anna::RuntimeException) {
1399 #define DECODE2BYTES_INDX_VALUETYPE(buffer,indx,value_type) ((((value_type)buffer[indx] << 8) & 0xFF00) + ((value_type)buffer[indx+1] & 0x00FF))
1400   isupNumber.reset();
1401   isupNumber.OddEven = (short)((buffer[0] >> 7) & 0x01);
1402   bool filler = isupNumber.OddEven;
1403
1404   if(filler && ((buffer [length - 1] & 0xf0) != 0x00))
1405     throw anna::RuntimeException("functions::decodeIsupNumber | Isup number filler must be '0000'", ANNA_FILE_LOCATION);
1406
1407   isupNumber.NatureOfAddress = (short)(buffer[0] & 0x7F);
1408   isupNumber.NumberingPlan = (short)((buffer[1] >> 4) & 0x07);
1409
1410   if(calledOrCalling) {
1411     isupNumber.InternalNetworkNumber = (short)((buffer[1] >> 7) & 0x01);
1412   } else {
1413     isupNumber.NumberIncomplete = (short)((buffer[1] >> 7) & 0x01);
1414     isupNumber.AddressPresentationRestricted = (short)((buffer[1] >> 2) & 0x03);
1415     isupNumber.Screening = (short)(buffer[1] & 0x03);
1416   }
1417
1418   // Digits:
1419   isupNumber.Digits = "";
1420   int byte;
1421
1422   for(int k = 2; k < length; k ++) {
1423     byte = (buffer [k] & 0x0f);
1424     isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1425     byte = (buffer [k] & 0xf0) >> 4;
1426     isupNumber.Digits += (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'a');
1427   }
1428
1429   if(filler) isupNumber.Digits.erase(isupNumber.Digits.size() - 1, 1);   // remove filler
1430 }
1431
1432
1433 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, std::string & target) throw(anna::RuntimeException) {
1434   // Checkings:
1435   if(isupNumber.OddEven < 0 || isupNumber.OddEven > 1)
1436     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field out of range [0,1]", ANNA_FILE_LOCATION);
1437
1438   bool odd = isupNumber.OddEven;
1439   bool oddDigits = (isupNumber.Digits.size() % 2);
1440
1441   if(odd != oddDigits)
1442     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'OddEven' field doesn't correspond to the number of digits on 'Digits' field", ANNA_FILE_LOCATION);
1443
1444   if(isupNumber.NatureOfAddress < 0 || isupNumber.NatureOfAddress > 127)
1445     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NatureOfAddress' field out of range [0,127]", ANNA_FILE_LOCATION);
1446
1447   if(isupNumber.NumberingPlan < 0 || isupNumber.NumberingPlan > 7)
1448     throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberingPlan' field out of range [0,7]", ANNA_FILE_LOCATION);
1449
1450   if(calledOrCalling) {
1451     if(isupNumber.NumberIncomplete != 0)
1452       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field present on Called Party Number !", ANNA_FILE_LOCATION);
1453
1454     if(isupNumber.AddressPresentationRestricted != 0)
1455       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field present on Called Party Number !", ANNA_FILE_LOCATION);
1456
1457     if(isupNumber.Screening != 0)
1458       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field present on Called Party Number !", ANNA_FILE_LOCATION);
1459
1460     if(isupNumber.InternalNetworkNumber < 0 || isupNumber.InternalNetworkNumber > 1)
1461       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field out of range [0,1]", ANNA_FILE_LOCATION);
1462   } else {
1463     if(isupNumber.InternalNetworkNumber != 0)
1464       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'InternalNetworkNumber' field present on Calling Party Number !", ANNA_FILE_LOCATION);
1465
1466     if(isupNumber.NumberIncomplete < 0 || isupNumber.NumberIncomplete > 1)
1467       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'NumberIncomplete' field out of range [0,1]", ANNA_FILE_LOCATION);
1468
1469     if(isupNumber.AddressPresentationRestricted < 0 || isupNumber.AddressPresentationRestricted > 3)
1470       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'AddressPresentationRestricted' field out of range [0,3]", ANNA_FILE_LOCATION);
1471
1472     if(isupNumber.Screening < 0 || isupNumber.Screening > 3)
1473       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Screening' field out of range [0,3]", ANNA_FILE_LOCATION);
1474   }
1475
1476   char byte;
1477   target = "";
1478   bool filler = isupNumber.OddEven;
1479   bool hasDigits = (isupNumber.Digits.size() > 0);
1480   byte = filler ? 0x80 : 0x00;
1481   byte |= isupNumber.NatureOfAddress;
1482   target += byte;
1483
1484   if(calledOrCalling) {
1485     byte = isupNumber.InternalNetworkNumber << 7;
1486     byte |= (isupNumber.NumberingPlan << 4);
1487   } else {
1488     byte = isupNumber.NumberIncomplete << 7;
1489     byte |= (isupNumber.NumberingPlan << 4);
1490     byte |= (isupNumber.AddressPresentationRestricted << 2);
1491     byte |= isupNumber.Screening;
1492   }
1493
1494   target += byte;
1495   //int byte;
1496   unsigned char hex;
1497   std::string dtlc = isupNumber.Digits; // digits to lower case
1498   //std::transform(dtlc.begin(), dtlc.end(), dtlc.begin(), std::tolower);
1499   const char *digits = dtlc.c_str();
1500
1501   for(int k = 1; k < isupNumber.Digits.size(); k += 2) {
1502     if(isxdigit(byte = digits [k - 1]) == 0)
1503       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1504
1505     hex = (byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a);
1506
1507     if(isxdigit(byte = digits [k]) == 0)
1508       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1509
1510     hex |= ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a)) << 4;
1511     target += hex;
1512   }
1513
1514   if(hasDigits && filler) {
1515     if(isxdigit(byte = digits [isupNumber.Digits.size() - 1]) == 0)
1516       throw anna::RuntimeException("functions::codeIsupNumber | Isup number 'Digits' field contains invalid digits (non hexadecimal)", ANNA_FILE_LOCATION);
1517
1518     target += ((byte >= '0' && byte <= '9') ? (byte - '0') : ((byte - 'a') + 0x0a));
1519   }
1520 }
1521
1522
1523 void functions::codeIsupNumber(const isup_number_t & isupNumber, bool calledOrCalling, char * buffer, int & length) throw(anna::RuntimeException) {
1524   std::string target;
1525   codeIsupNumber(isupNumber, calledOrCalling, target);
1526   length = target.size();
1527   memcpy(buffer, target.c_str(), length);
1528 }
1529
1530
1531 static inline bool is_base64(U8 c) {
1532   return (isalnum(c) || (c == '+') || (c == '/'));
1533 }
1534
1535 std::string functions::encodeBase64(const U8* buf, unsigned int bufLen) {
1536   std::string ret;
1537   int i = 0;
1538   int j = 0;
1539   U8 char_array_3[3];
1540   U8 char_array_4[4];
1541
1542   while (bufLen--) {
1543     char_array_3[i++] = *(buf++);
1544     if (i == 3) {
1545       char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
1546       char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
1547       char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
1548       char_array_4[3] = char_array_3[2] & 0x3f;
1549
1550       for(i = 0; (i <4) ; i++)
1551         ret += base64_chars[char_array_4[i]];
1552       i = 0;
1553     }
1554   }
1555
1556   if (i)
1557   {
1558     for(j = i; j < 3; j++)
1559       char_array_3[j] = '\0';
1560
1561     char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
1562     char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
1563     char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
1564     char_array_4[3] = char_array_3[2] & 0x3f;
1565
1566     for (j = 0; (j < i + 1); j++)
1567       ret += base64_chars[char_array_4[j]];
1568
1569     while((i++ < 3))
1570       ret += '=';
1571   }
1572
1573   return ret;
1574 }
1575
1576 std::string functions::decodeBase64(const std::string & encodedString) {
1577   int in_len = encodedString.size();
1578   int i = 0;
1579   int j = 0;
1580   int in_ = 0;
1581   U8 char_array_4[4], char_array_3[3];
1582   std::string ret;
1583
1584   while (in_len-- && ( encodedString[in_] != '=') && is_base64(encodedString[in_])) {
1585     char_array_4[i++] = encodedString[in_]; in_++;
1586     if (i ==4) {
1587       for (i = 0; i <4; i++)
1588         char_array_4[i] = base64_chars.find(char_array_4[i]);
1589
1590       char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
1591       char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
1592       char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
1593
1594       for (i = 0; (i < 3); i++)
1595           ret += char_array_3[i];
1596       i = 0;
1597     }
1598   }
1599
1600   if (i) {
1601     for (j = i; j <4; j++)
1602       char_array_4[j] = 0;
1603
1604     for (j = 0; j <4; j++)
1605       char_array_4[j] = base64_chars.find(char_array_4[j]);
1606
1607     char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
1608     char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
1609     char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
1610
1611     for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
1612   }
1613
1614   return ret;
1615 }
1616
1617 bool functions::getContentFromFile(const std::string &pathfile, std::string &content) throw(anna::RuntimeException) {
1618
1619   std::ifstream inFile(pathfile.c_str(), std::ifstream::in);
1620   if(!inFile.good()) {
1621     throw RuntimeException(anna::functions::asString("Unable to open file '%s'", pathfile.c_str()), ANNA_FILE_LOCATION);
1622   }
1623
1624   std::stringstream strStream;
1625   strStream << inFile.rdbuf(); //read the file
1626   content = strStream.str(); // holds the content of the file
1627   inFile.close();
1628
1629   return true;
1630 }
1631