Disk ARchive 2.7.16
Full featured and portable backup and archiving tool
Loading...
Searching...
No Matches
limitint.hpp
Go to the documentation of this file.
1/*********************************************************************/
2// dar - disk archive - a backup/restoration program
3// Copyright (C) 2002-2024 Denis Corbin
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 2
8// of the License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18//
19// to contact the author, see the AUTHOR file
20/*********************************************************************/
21
30
31
32#ifndef LIMITINT_HPP
33#define LIMITINT_HPP
34
35#include "../my_config.h"
36
37extern "C"
38{
39#if HAVE_SYS_TYPES_H
40#include <sys/types.h>
41#endif
42
43#if HAVE_UNISTD_H
44#include <unistd.h>
45#endif
46
47#if HAVE_STRING_H
48#include <string.h>
49#endif
50
51#if HAVE_STRINGS_H
52#include <strings.h>
53#endif
54} // end extern "C"
55
56#include <typeinfo>
57#include "integers.hpp"
58#include "erreurs.hpp"
59#include "int_tools.hpp"
61
62
63#define ZEROED_SIZE 50
64
65namespace libdar
66{
67
70
85
86
87 template<class B> class limitint
88 {
89 public :
90
91#if SIZEOF_OFF_T > SIZEOF_TIME_T
92#if SIZEOF_OFF_T > SIZEOF_SIZE_T
93 limitint(off_t a = 0)
94 { limitint_from(a); };
95#else
96 limitint(size_t a = 0)
97 { limitint_from(a); };
98#endif
99#else
100#if SIZEOF_TIME_T > SIZEOF_SIZE_T
101 limitint(time_t a = 0)
102 { limitint_from(a); };
103#else
104 limitint(size_t a = 0)
105 { limitint_from(a); };
106#endif
107#endif
108
109 // read an limitint from a file
111
112 limitint(const limitint & ref) = default;
113 limitint(limitint && ref) noexcept = default;
114 limitint & operator = (const limitint & ref) = default;
115 limitint & operator = (limitint && ref) noexcept = default;
116
117 // for coherent footprint with real infinint
118 ~limitint() = default;
119
120 void dump(proto_generic_file &x) const; // write byte sequence to file
121 void read(proto_generic_file &f) { build_from_file(f); };
122
123 limitint & operator += (const limitint & ref);
124 limitint & operator -= (const limitint & ref);
125 limitint & operator *= (const limitint & ref);
126 template <class T> limitint power(const T & exponent) const;
127 limitint & operator /= (const limitint & ref);
128 limitint & operator %= (const limitint & ref);
129 limitint & operator &= (const limitint & ref);
130 limitint & operator |= (const limitint & ref);
131 limitint & operator ^= (const limitint & ref);
132 limitint & operator >>= (U_32 bit);
133 limitint & operator >>= (limitint bit);
134 limitint & operator <<= (U_32 bit);
135 limitint & operator <<= (limitint bit);
136 limitint operator ++(int a)
137 { limitint ret = *this; ++(*this); return ret; };
138 limitint operator --(int a)
139 { limitint ret = *this; --(*this); return ret; };
140 limitint & operator ++()
141 { return *this += 1; };
142 limitint & operator --()
143 { return *this -= 1; };
144
145 U_32 operator % (U_32 arg) const;
146
147 // increment the argument up to a legal value for its storage type and decrement the object in consequence
148 // note that the initial value of the argument is not ignored !
149 // when the object is null the value of the argument stays the same as before
150 template <class T>void unstack(T &v)
151 { limitint_unstack_to(v); }
152
153 limitint get_storage_size() const;
154 // it returns number of byte of information necessary to store the integer
155
156 unsigned char operator [] (const limitint & position) const;
157 // return in little endian order the information bytes storing the integer
158
159 bool is_zero() const { return field == 0; };
160
161 bool operator < (const limitint &x) const { return field < x.field; };
162 bool operator == (const limitint &x) const { return field == x.field; };
163 bool operator > (const limitint &x) const { return field > x.field; };
164 bool operator <= (const limitint &x) const { return field <= x.field; };
165 bool operator != (const limitint &x) const { return field != x.field; };
166 bool operator >= (const limitint &x) const { return field >= x.field; };
167 static bool is_system_big_endian();
168
169 B debug_get_max() const { return max_value; };
170 B debug_get_bytesize() const { return bytesize; };
171 B debug_get_field() const { return field; };
172
173 private :
174
175 B field;
176
177 void build_from_file(proto_generic_file & x);
178 template <class T> void limitint_from(T a);
179 template <class T> T max_val_of(T x);
180 template <class T> void limitint_unstack_to(T &a);
181
183 // static statments
184 //
185 static const int TG = 4;
186 static const U_32 sizeof_field = sizeof(B); // number of bytes
187
188 enum endian { big_endian, little_endian, not_initialized };
189 using group = unsigned char[TG];
190
191 static endian used_endian;
192 static const U_I bytesize = sizeof(B);
193 static const B max_value = ~B(0) > 0 ? ~B(0) : ~(B(1) << (bytesize*8 - 1));
194 static U_8 zeroed_field[ZEROED_SIZE];
195
196 static void setup_endian();
197 };
198
199 template <class B> U_8 limitint<B>::zeroed_field[ZEROED_SIZE];
200
201 template <class B> limitint<B> operator + (const limitint<B> &, const limitint<B> &);
202 template <class B> inline limitint<B> operator + (const limitint<B> & a, U_I b)
203 { return a + limitint<B>(b); }
204 template <class B> limitint<B> operator - (const limitint<B> &, const limitint<B> &);
205 template <class B> inline limitint<B> operator - (const limitint<B> & a, U_I b)
206 { return a - limitint<B>(b); }
207 template <class B> limitint<B> operator * (const limitint<B> &, const limitint<B> &);
208 template <class B> inline limitint<B> operator * (const limitint<B> & a, U_I b)
209 { return a * limitint<B>(b); }
210 template <class B> limitint<B> operator / (const limitint<B> &, const limitint<B> &);
211 template <class B> limitint<B> operator / (const limitint<B> & a, U_I b)
212 { return a / limitint<B>(b); }
213 template <class B> limitint<B> operator % (const limitint<B> &, const limitint<B> &);
214 template <class B> limitint<B> operator >> (const limitint<B> & a, U_32 bit);
215 template <class B> limitint<B> operator >> (const limitint<B> & a, const limitint<B> & bit);
216 template <class B> limitint<B> operator << (const limitint<B> & a, U_32 bit);
217 template <class B> limitint<B> operator << (const limitint<B> & a, const limitint<B> & bit);
218 template <class B> limitint<B> operator & (const limitint<B> & a, U_32 bit);
219 template <class B> limitint<B> operator & (const limitint<B> & a, const limitint<B> & bit);
220 template <class B> limitint<B> operator | (const limitint<B> & a, U_32 bit);
221 template <class B> limitint<B> operator | (const limitint<B> & a, const limitint<B> & bit);
222 template <class B> limitint<B> operator ^ (const limitint<B> & a, U_32 bit);
223 template <class B> limitint<B> operator ^ (const limitint<B> & a, const limitint<B> & bit);
224
225 template <class T> inline void euclide(T a, T b, T & q, T &r)
226 {
227
228 q = a/b; r = a%b;
229 }
230
231 template <class B> inline void euclide(limitint<B> a, U_I b, limitint<B> & q, limitint<B> &r)
232 {
233 euclide(a, limitint<B>(b), q, r);
234 }
235
236#ifndef INFININT_BASE_TYPE
237#error INFININT_BASE_TYPE not defined cannot instantiate template
238#else
239 using infinint = limitint<INFININT_BASE_TYPE>;
240#endif
241} // end of namespace
245
246namespace libdar
247{
248
249 template <class B> typename limitint<B>::endian limitint<B>::used_endian = not_initialized;
250
251
252 template <class B> limitint<B>::limitint(proto_generic_file & x)
253 {
254 build_from_file(x);
255 }
256
257
258 template <class B> void limitint<B>::build_from_file(proto_generic_file & x)
259 {
260 unsigned char a;
261 bool fin = false;
262 limitint<B> skip = 0;
263 char *ptr = (char *)&field;
264 S_I lu;
265 int_tools_bitfield bf;
266
267 while(!fin)
268 {
269 lu = x.read((char *)&a, 1);
270
271 if(lu <= 0)
272 throw Erange("limitint::build_from_file(proto_generic_file)", gettext("Reached end of file before all data could be read"));
273
274 if(a == 0)
275 ++skip;
276 else // end of size field
277 {
278 // computing the size to read
279 U_I pos = 0;
280
281 int_tools_expand_byte(a, bf);
282 for(S_I i = 0; i < 8; ++i)
283 pos += bf[i];
284 if(pos != 1)
285 throw Erange("limitint::build_from_file(proto_generic_file)", gettext("Badly formed \"infinint\" or not supported format")); // more than 1 bit is set to 1
286
287 pos = 0;
288 while(bf[pos] == 0)
289 ++pos;
290 pos += 1; // bf starts at zero, but bit zero means 1 TG of length
291
292 skip *= 8;
293 skip += pos;
294 skip *= TG;
295
296 if(skip.field > bytesize)
297 throw Elimitint();
298
299 field = 0; // important to also clear "unread" bytes by this call
300 lu = x.read(ptr, skip.field);
301
302 if(used_endian == not_initialized)
303 setup_endian();
304 if(used_endian == little_endian)
305 int_tools_swap_bytes((unsigned char *)ptr, skip.field);
306 else
307 field >>= (bytesize - skip.field)*8;
308 fin = true;
309 }
310 }
311 }
312
313
314 template <class B> void limitint<B>::dump(proto_generic_file & x) const
315 {
316 B width = bytesize;
317 B pos;
318 unsigned char last_width;
319 B justification;
320 S_I direction = +1;
321 unsigned char *ptr, *fin;
322
323
324 if(used_endian == not_initialized)
325 setup_endian();
326
327 if(used_endian == little_endian)
328 {
329 direction = -1;
330 ptr = (unsigned char *)(&field) + (bytesize - 1);
331 fin = (unsigned char *)(&field) - 1;
332 }
333 else
334 {
335 direction = +1;
336 ptr = (unsigned char *)(&field);
337 fin = (unsigned char *)(&field) + bytesize;
338 }
339
340 while(ptr != fin && *ptr == 0)
341 {
342 ptr += direction;
343 --width;
344 }
345 if(width == 0)
346 width = 1; // minimum size of information is 1 byte
347
348 // "width" is the informational field size in byte
349 // TG is the width in TG, thus the number of bit that must have
350 // the preamble
351 euclide(width, (const B)(TG), width, justification);
352 if(justification != 0)
353 // in case we need to add some bytes to have a width multiple of TG
354 ++width; // we need then one more group to have a width multiple of TG
355
356 euclide(width, (const B)(8), width, pos);
357 if(pos == 0)
358 {
359 width--; // division is exact, only last bit of the preambule is set
360 last_width = 0x80 >> 7;
361 // as we add the last byte separately width gets shorter by 1 byte
362 }
363 else // division non exact, the last_width (last byte), make the rounding
364 {
365 U_16 pos_s = (U_16)(0xFFFF & pos);
366 last_width = 0x80 >> (pos_s - 1);
367 }
368
369 // now we write the preamble except the last byte. All these are zeros.
370
371 while(width != 0)
372 if(width > ZEROED_SIZE)
373 {
374 x.write((char *)zeroed_field, ZEROED_SIZE);
375 width -= ZEROED_SIZE;
376 }
377 else
378 {
379 x.write((char *)zeroed_field, width);
380 width = 0;
381 }
382
383 // now we write the last byte of the preambule, which has only one bit set
384
385 x.write((char *)&last_width, 1);
386
387 // we need now to write some justification byte to have an informational field multiple of TG
388
389 if(justification != 0)
390 {
391 justification = TG - justification;
392 if(justification > ZEROED_SIZE)
393 throw SRC_BUG;
394 else
395 x.write((char *)zeroed_field, justification);
396 }
397
398 // now we continue dumping the informational bytes:
399 if(ptr == fin) // field is equal to zero
400 x.write((char *)zeroed_field, 1);
401 else // we have some bytes to write down
402 while(ptr != fin)
403 {
404 x.write((char *)ptr, 1);
405 ptr += direction;
406 }
407 }
408
409 template<class B> limitint<B> & limitint<B>::operator += (const limitint & arg)
410 {
411 B res = field + arg.field;
412 if(res < field || res < arg.field)
413 throw Elimitint();
414 else
415 field = res;
416
417 return *this;
418 }
419
420 template <class B> limitint<B> & limitint<B>::operator -= (const limitint & arg)
421 {
422 if(field < arg.field)
423 throw Erange("limitint::operator", gettext("Subtracting an \"infinint\" greater than the first, \"infinint\" cannot be negative"));
424
425 // now processing the operation
426
427 field -= arg.field;
428 return *this;
429 }
430
431
432 template <class B> limitint<B> & limitint<B>::operator *= (const limitint & arg)
433 {
434 static const B max_power = bytesize*8 - 1;
435
436 B total = int_tools_higher_power_of_2(field) + int_tools_higher_power_of_2(arg.field) + 1; // for an explaination about "+2" see NOTES
437 if(total > max_power) // this is a bit too much restrictive, but unless remaking bit by bit, the operation,
438 // I don't see how to simply (and fast) know the result has not overflowed.
439 // of course, it would be fast and easy to access the CPU flag register to check for overflow,
440 // but that would not be portable, and unfortunately I haven't found any standart C++ expression that
441 // could transparently access to it.
442 throw Elimitint();
443
444 total = field*arg.field;
445 if(field != 0 && arg.field != 0)
446 if(total < field || total < arg.field)
447 throw Elimitint();
448 field = total;
449 return *this;
450 }
451
452 template <class B> template<class T> limitint<B> limitint<B>::power(const T & exponent) const
453 {
454 limitint ret = 1;
455 for(T count = 0; count < exponent; ++count)
456 ret *= *this;
457
458 return ret;
459 }
460
461 template <class B> limitint<B> & limitint<B>::operator /= (const limitint & arg)
462 {
463 if(arg == 0)
464 throw Einfinint("limitint.cpp : operator /=", gettext("Division by zero"));
465
466 field /= arg.field;
467 return *this;
468 }
469
470 template <class B> limitint<B> & limitint<B>::operator %= (const limitint & arg)
471 {
472 if(arg == 0)
473 throw Einfinint("limitint.cpp : operator %=", gettext("Division by zero"));
474
475 field %= arg.field;
476 return *this;
477 }
478
479 template <class B> limitint<B> & limitint<B>::operator >>= (U_32 bit)
480 {
481 if(bit >= sizeof_field*8)
482 field = 0;
483 else
484 field >>= bit;
485 return *this;
486 }
487
488 template <class B> limitint<B> & limitint<B>::operator >>= (limitint bit)
489 {
490 field >>= bit.field;
491 return *this;
492 }
493
494 template <class B> limitint<B> & limitint<B>::operator <<= (U_32 bit)
495 {
496 if(bit + int_tools_higher_power_of_2(field) >= bytesize*8)
497 throw Elimitint();
498 field <<= bit;
499 return *this;
500 }
501
502 template <class B> limitint<B> & limitint<B>::operator <<= (limitint bit)
503 {
504 if(bit.field + int_tools_higher_power_of_2(field) >= bytesize*8)
505 throw Elimitint();
506 field <<= bit.field;
507 return *this;
508 }
509
510 template <class B> limitint<B> & limitint<B>::operator &= (const limitint & arg)
511 {
512 field &= arg.field;
513 return *this;
514 }
515
516 template <class B> limitint<B> & limitint<B>::operator |= (const limitint & arg)
517 {
518 field |= arg.field;
519 return *this;
520 }
521
522 template <class B> limitint<B> & limitint<B>::operator ^= (const limitint & arg)
523 {
524 field ^= arg.field;
525 return *this;
526 }
527
528 template <class B> U_32 limitint<B>::operator % (U_32 arg) const
529 {
530 return U_32(field % arg);
531 }
532
533 template <class B> template <class T> void limitint<B>::limitint_from(T a)
534 {
535 if(sizeof(a) <= bytesize || a <= (T)(max_value))
536 field = B(a);
537 else
538 throw Elimitint();
539 }
540
541 template <class B> template <class T> T limitint<B>::max_val_of(T x)
542 {
543 x = 0;
544 x = ~x;
545
546 if(x < 1) // T is a signed integer type, we are not comparing to zero to avoid compiler warning when the template is used against unsigned integers
547 {
548 x = 1;
549 x = int_tools_rotate_right_one_bit(x);
550 x = ~x;
551 }
552
553 return x;
554 }
555
556 template <class B> template <class T> void limitint<B>::limitint_unstack_to(T &a)
557 {
558
559 // T is supposed to be an unsigned "integer"
560 // (ie.: sizeof returns the width of the storage bit field and no sign bit is present)
561 // Note : static here avoids the recalculation of max_T at each call
562 static const T max_T = max_val_of(a);
563 T step = max_T - a;
564
565 if(field < (B)(step) && (T)(field) < step)
566 {
567 a += field;
568 field = 0;
569 }
570 else
571 {
572 field -= step;
573 a = max_T;
574 }
575 }
576
577 template <class B> limitint<B> limitint<B>::get_storage_size() const
578 {
579 B tmp = field;
580 B ret = 0;
581
582 while(tmp != 0)
583 {
584 tmp >>= 8;
585 ret++;
586 }
587
588 return limitint<B>(ret);
589 }
590
591 template <class B> unsigned char limitint<B>::operator [] (const limitint & position) const
592 {
593 B tmp = field;
594 B index = position.field; // C++ has only class protection, not object protection
595
596 while(index > 0)
597 {
598 tmp >>= 8;
599 index--;
600 }
601
602 return (unsigned char)(tmp & 0xFF);
603 }
604
605 template <class B> void limitint<B>::setup_endian()
606 {
608 used_endian = big_endian;
609 else
610 used_endian = little_endian;
611
612 (void)memset(zeroed_field, 0, ZEROED_SIZE);
613 }
614
615
616 template <class B> bool limitint<B>::is_system_big_endian()
617 {
618 if(used_endian == not_initialized)
619 setup_endian();
620
621 switch(used_endian)
622 {
623 case big_endian:
624 return true;
625 case little_endian:
626 return false;
627 case not_initialized:
628 throw SRC_BUG;
629 default:
630 throw SRC_BUG;
631 }
632 }
633
634
638
639 template <class B> limitint<B> operator + (const limitint<B> & a, const limitint<B> & b)
640 {
641 limitint<B> ret = a;
642 ret += b;
643
644 return ret;
645 }
646
647 template <class B> limitint<B> operator - (const limitint<B> & a, const limitint<B> & b)
648 {
649 limitint<B> ret = a;
650 ret -= b;
651
652 return ret;
653 }
654
655 template <class B> limitint<B> operator * (const limitint<B> & a, const limitint<B> & b)
656 {
657 limitint<B> ret = a;
658 ret *= b;
659
660 return ret;
661 }
662
663 template <class B> limitint<B> operator / (const limitint<B> & a, const limitint<B> & b)
664 {
665 limitint<B> ret = a;
666 ret /= b;
667
668 return ret;
669 }
670
671 template <class B> limitint<B> operator % (const limitint<B> & a, const limitint<B> & b)
672 {
673 limitint<B> ret = a;
674 ret %= b;
675
676 return ret;
677 }
678
679 template <class B> limitint<B> operator >> (const limitint<B> & a, U_32 bit)
680 {
681 limitint<B> ret = a;
682 ret >>= bit;
683 return ret;
684 }
685
686 template <class B> limitint<B> operator >> (const limitint<B> & a, const limitint<B> & bit)
687 {
688 limitint<B> ret = a;
689 ret >>= bit;
690 return ret;
691 }
692
693 template <class B> limitint<B> operator << (const limitint<B> & a, U_32 bit)
694 {
695 limitint<B> ret = a;
696 ret <<= bit;
697 return ret;
698 }
699
700 template <class B> limitint<B> operator << (const limitint<B> & a, const limitint<B> & bit)
701 {
702 limitint<B> ret = a;
703 ret <<= bit;
704 return ret;
705 }
706
707 template <class B> limitint<B> operator & (const limitint<B> & a, U_32 bit)
708 {
709 limitint<B> ret = a;
710 ret &= bit;
711 return ret;
712 }
713
714 template <class B> limitint<B> operator & (const limitint<B> & a, const limitint<B> & bit)
715 {
716 limitint<B> ret = a;
717 ret &= bit;
718 return ret;
719 }
720
721 template <class B> limitint<B> operator | (const limitint<B> & a, U_32 bit)
722 {
723 limitint<B> ret = a;
724 ret |= bit;
725 return ret;
726 }
727
728 template <class B> limitint<B> operator | (const limitint<B> & a, const limitint<B> & bit)
729 {
730 limitint<B> ret = a;
731 ret |= bit;
732 return ret;
733 }
734
735 template <class B> limitint<B> operator ^ (const limitint<B> & a, U_32 bit)
736 {
737 limitint<B> ret = a;
738 ret ^= bit;
739 return ret;
740 }
741
742 template <class B> limitint<B> operator ^ (const limitint<B> & a, const limitint<B> & bit)
743 {
744 limitint<B> ret = a;
745 ret ^= bit;
746 return ret;
747 }
748
750
751} // end of namespace
752
753#endif
ancestor class of generic_file
contains all the excetion class thrown by libdar
std::ostream & operator<<(std::ostream &ref, const infinint &arg)
specific << operator to use infinint in std::ostream
elementary operation for infinint integers
are defined here basic integer types that tend to be portable
include macro defined by the configure script and some specific additional ones
libdar namespace encapsulate all libdar symbols
Definition archive.hpp:47
bool integers_system_is_big_endian()
returns true if the system is big endian, false else
precursor class of generic_file used to avoid cyclic dependencies with storage and infinint