00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00032
00033 #ifndef LIMITINT_HPP
00034 #define LIMITINT_HPP
00035
00036 #include "../my_config.h"
00037
00038 extern "C"
00039 {
00040 #if HAVE_SYS_TYPES_H
00041 #include <sys/types.h>
00042 #endif
00043
00044 #if HAVE_UNISTD_H
00045 #include <unistd.h>
00046 #endif
00047 }
00048
00049 #include <typeinfo>
00050 #include "integers.hpp"
00051 #include "erreurs.hpp"
00052 #include "special_alloc.hpp"
00053 #include "int_tools.hpp"
00054
00055 namespace libdar
00056 {
00057
00058 class generic_file;
00059 class user_interaction;
00060
00062
00072
00073 template<class B> class limitint
00074 {
00075 public :
00076
00077 #if SIZEOF_OFF_T > SIZEOF_TIME_T
00078 #if SIZEOF_OFF_T > SIZEOF_SIZE_T
00079 limitint(off_t a = 0)
00080 { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "off_t"); };
00081 #else
00082 limitint(size_t a = 0)
00083 { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "size_t"); };
00084 #endif
00085 #else
00086 #if SIZEOF_TIME_T > SIZEOF_SIZE_T
00087 limitint(time_t a = 0)
00088 { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "time_t"); };
00089 #else
00090 limitint(size_t a = 0)
00091 { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "size_t"); };
00092 #endif
00093 #endif
00094
00095 limitint(user_interaction & dialog, S_I *fd, generic_file *x);
00096
00097
00098 void dump(user_interaction & dialog, S_I fd) const;
00099 void dump(generic_file &x) const;
00100 void read(generic_file &f) { build_from_file(f); };
00101
00102 limitint & operator += (const limitint & ref);
00103 limitint & operator -= (const limitint & ref);
00104 limitint & operator *= (const limitint & ref);
00105 template <class T> limitint power(const T & exponent) const;
00106 limitint & operator /= (const limitint & ref);
00107 limitint & operator %= (const limitint & ref);
00108 limitint & operator &= (const limitint & ref);
00109 limitint & operator |= (const limitint & ref);
00110 limitint & operator ^= (const limitint & ref);
00111 limitint & operator >>= (U_32 bit);
00112 limitint & operator >>= (limitint bit);
00113 limitint & operator <<= (U_32 bit);
00114 limitint & operator <<= (limitint bit);
00115 limitint operator ++(int a)
00116 { E_BEGIN; limitint ret = *this; ++(*this); return ret; E_END("limitint::operator ++", "int"); };
00117 limitint operator --(int a)
00118 { E_BEGIN; limitint ret = *this; --(*this); return ret; E_END("limitint::operator --", "int"); };
00119 limitint & operator ++()
00120 { E_BEGIN; return *this += 1; E_END("limitint::operator ++", "()"); };
00121 limitint & operator --()
00122 { E_BEGIN; return *this -= 1; E_END("limitint::operator --", "()"); };
00123
00124 U_32 operator % (U_32 arg) const;
00125
00126
00127
00128
00129 template <class T>void unstack(T &v)
00130 { E_BEGIN; limitint_unstack_to(v); E_END("limitint::unstack", typeid(v).name()); }
00131
00132 limitint get_storage_size() const;
00133
00134
00135 unsigned char operator [] (const limitint & position) const;
00136
00137
00138
00139 bool operator < (const limitint &x) const { return field < x.field; };
00140 bool operator == (const limitint &x) const { return field == x.field; };
00141 bool operator > (const limitint &x) const { return field > x.field; };
00142 bool operator <= (const limitint &x) const { return field <= x.field; };
00143 bool operator != (const limitint &x) const { return field != x.field; };
00144 bool operator >= (const limitint &x) const { return field >= x.field; };
00145
00146 static bool is_system_big_endian();
00147
00148 #ifdef LIBDAR_SPECIAL_ALLOC
00149 USE_SPECIAL_ALLOC(limitint);
00150 #endif
00151
00152 B debug_get_max() const { return max_value; };
00153 B debug_get_bytesize() const { return bytesize; };
00154
00155 private :
00156 static const int TG = 4;
00157 static const U_32 sizeof_field = sizeof(B);
00158
00159 enum endian { big_endian, little_endian, not_initialized };
00160 typedef unsigned char group[TG];
00161
00162 B field;
00163
00164 void build_from_file(generic_file & x);
00165 template <class T> void limitint_from(T a);
00166 template <class T> void limitint_unstack_to(T &a);
00167
00169
00170
00171 static endian used_endian;
00172 static const U_I bytesize = sizeof(B);
00173 static const B max_value = ~B(0) > 0 ? ~B(0) : ~(B(1) << (bytesize*8 - 1));
00174 static void setup_endian();
00175 };
00176
00177 template <class B> limitint<B> operator + (const limitint<B> &, const limitint<B> &);
00178 template <class B> inline limitint<B> operator + (const limitint<B> & a, U_I b)
00179 { return a + limitint<B>(b); }
00180 template <class B> limitint<B> operator - (const limitint<B> &, const limitint<B> &);
00181 template <class B> inline limitint<B> operator - (const limitint<B> & a, U_I b)
00182 { return a - limitint<B>(b); }
00183 template <class B> limitint<B> operator * (const limitint<B> &, const limitint<B> &);
00184 template <class B> inline limitint<B> operator * (const limitint<B> & a, U_I b)
00185 { return a * limitint<B>(b); }
00186 template <class B> limitint<B> operator / (const limitint<B> &, const limitint<B> &);
00187 template <class B> limitint<B> operator / (const limitint<B> & a, U_I b)
00188 { return a / limitint<B>(b); }
00189 template <class B> limitint<B> operator % (const limitint<B> &, const limitint<B> &);
00190 template <class B> limitint<B> operator >> (const limitint<B> & a, U_32 bit);
00191 template <class B> limitint<B> operator >> (const limitint<B> & a, const limitint<B> & bit);
00192 template <class B> limitint<B> operator << (const limitint<B> & a, U_32 bit);
00193 template <class B> limitint<B> operator << (const limitint<B> & a, const limitint<B> & bit);
00194 template <class B> limitint<B> operator & (const limitint<B> & a, U_32 bit);
00195 template <class B> limitint<B> operator & (const limitint<B> & a, const limitint<B> & bit);
00196 template <class B> limitint<B> operator | (const limitint<B> & a, U_32 bit);
00197 template <class B> limitint<B> operator | (const limitint<B> & a, const limitint<B> & bit);
00198 template <class B> limitint<B> operator ^ (const limitint<B> & a, U_32 bit);
00199 template <class B> limitint<B> operator ^ (const limitint<B> & a, const limitint<B> & bit);
00200
00201 template <class T> inline void euclide(T a, T b, T & q, T &r)
00202 {
00203 E_BEGIN;
00204 q = a/b; r = a%b;
00205 E_END("euclide", "");
00206 }
00207
00208 template <class B> inline void euclide(limitint<B> a, U_I b, limitint<B> & q, limitint<B> &r)
00209 {
00210 euclide(a, limitint<B>(b), q, r);
00211 }
00212
00213 #ifndef INFININT_BASE_TYPE
00214 #error INFININT_BASE_TYPE not defined cannot instantiate template
00215 #else
00216 typedef limitint<INFININT_BASE_TYPE> infinint;
00217 #endif
00218 }
00222
00223 #include "generic_file.hpp"
00224 #include "user_interaction.hpp"
00225
00226 namespace libdar
00227 {
00228
00229 template <class B> typename limitint<B>::endian limitint<B>::used_endian = not_initialized;
00230
00231 template <class B> limitint<B>::limitint(user_interaction & dialog, S_I *fd, generic_file *x)
00232 {
00233 if(fd != NULL && x != NULL)
00234 throw Erange("limitint::limitint(file, file)", "Both arguments are not NULL, please choose one or the other, not both");
00235 if(fd != NULL)
00236 {
00237 fichier f = fichier(dialog, dup(*fd));
00238 build_from_file(f);
00239 }
00240 else
00241 if(x != NULL)
00242 build_from_file(*x);
00243 else
00244 throw Erange("limitint::limitint(file, file)", "Cannot read from file, both arguments are NULL");
00245 }
00246
00247 template <class B> void limitint<B>::dump(user_interaction & dialog, S_I fd) const
00248 {
00249 fichier f = fichier(dialog, dup(fd));
00250 dump(f);
00251 }
00252
00253 template <class B> void limitint<B>::build_from_file(generic_file & x)
00254 {
00255 E_BEGIN;
00256 unsigned char a;
00257 bool fin = false;
00258 limitint<B> skip = 0;
00259 char *ptr = (char *)&field;
00260 S_I lu;
00261 int_tools_bitfield bf;
00262
00263 while(!fin)
00264 {
00265 lu = x.read((char *)&a, 1);
00266
00267 if(lu <= 0)
00268 throw Erange("limitint::build_from_file(generic_file)", gettext("Reached end of file before all data could be read"));
00269
00270 if(a == 0)
00271 ++skip;
00272 else
00273 {
00274
00275 U_I pos = 0;
00276
00277 int_tools_expand_byte(a, bf);
00278 for(S_I i = 0; i < 8; ++i)
00279 pos += bf[i];
00280 if(pos != 1)
00281 throw Erange("limitint::build_from_file(generic_file)", gettext("Badly formed infinint or not supported format"));
00282
00283 pos = 0;
00284 while(bf[pos] == 0)
00285 ++pos;
00286 pos += 1;
00287
00288 skip *= 8;
00289 skip += pos;
00290 skip *= TG;
00291
00292 if(skip.field > bytesize)
00293 throw Elimitint();
00294
00295 field = 0;
00296 lu = x.read(ptr, skip.field);
00297
00298 if(used_endian == not_initialized)
00299 setup_endian();
00300 if(used_endian == big_endian)
00301 int_tools_swap_bytes((unsigned char *)ptr, skip.field);
00302 else
00303 field >>= (bytesize - skip.field)*8;
00304 fin = true;
00305 }
00306 }
00307 E_END("limitint::read_from_file", "generic_file");
00308 }
00309
00310
00311 template <class B> void limitint<B>::dump(generic_file & x) const
00312 {
00313 E_BEGIN;
00314 B width = bytesize;
00315 B pos;
00316 unsigned char last_width;
00317 B justification;
00318 S_I direction = +1;
00319 unsigned char *ptr, *fin;
00320
00321
00322 if(used_endian == not_initialized)
00323 setup_endian();
00324
00325 if(used_endian == big_endian)
00326 {
00327 direction = -1;
00328 ptr = (unsigned char *)(&field) + (bytesize - 1);
00329 fin = (unsigned char *)(&field) - 1;
00330 }
00331 else
00332 {
00333 direction = +1;
00334 ptr = (unsigned char *)(&field);
00335 fin = (unsigned char *)(&field) + bytesize;
00336 }
00337
00338 while(ptr != fin && *ptr == 0)
00339 {
00340 ptr += direction;
00341 --width;
00342 }
00343 if(width == 0)
00344 width = 1;
00345
00346
00347
00348
00349 euclide(width, (const B)(TG), width, justification);
00350 if(justification != 0)
00351
00352 ++width;
00353
00354 euclide(width, (const B)(8), width, pos);
00355 if(pos == 0)
00356 {
00357 width--;
00358 last_width = 0x80 >> 7;
00359
00360 }
00361 else
00362 {
00363 U_16 pos_s = (U_16)(0xFFFF & pos);
00364 last_width = 0x80 >> (pos_s - 1);
00365 }
00366
00367
00368
00369 unsigned char u = 0x00;
00370
00371 while(width-- > 0)
00372 if(x.write((char *)(&u), 1) < 1)
00373 throw Erange("limitint::dump(generic_file)", gettext("Cannot write data to file"));
00374
00375
00376
00377
00378 if(x.write((char *)&last_width, 1) < 1)
00379 throw Erange("limitint::dump(generic_file)", gettext("Cannot write data to file"));
00380
00381
00382
00383 if(justification != 0)
00384 {
00385 justification = TG - justification;
00386 while(justification-- > 0)
00387 if(x.write((char *)(&u), 1) < 1)
00388 throw Erange("limitint::dump(generic_file)", gettext("Cannot write data to file"));
00389 }
00390
00391
00392 if(ptr == fin)
00393 {
00394 if(x.write((char *)(&u), 1) < 1)
00395 throw Erange("limitint::dump(generic_file)", gettext("Cannot write data to file"));
00396 }
00397 else
00398 while(ptr != fin)
00399 {
00400 if(x.write((char *)ptr, 1) < 1)
00401 throw Erange("limitint::dump(generic_file)", gettext("Cannot write data to file"));
00402 else
00403 ptr += direction;
00404 }
00405
00406 E_END("limitint::dump", "generic_file");
00407 }
00408
00409 template<class B> limitint<B> & limitint<B>::operator += (const limitint & arg)
00410 {
00411 E_BEGIN;
00412 B res = field + arg.field;
00413 if(res < field || res < arg.field)
00414 throw Elimitint();
00415 else
00416 field = res;
00417
00418 return *this;
00419 E_END("limitint::operator +=", "");
00420 }
00421
00422 template <class B> limitint<B> & limitint<B>::operator -= (const limitint & arg)
00423 {
00424 E_BEGIN;
00425 if(field < arg.field)
00426 throw Erange("limitint::operator", gettext("Subtracting a infinint greater than the first, infinint cannot be negative"));
00427
00428
00429
00430 field -= arg.field;
00431 return *this;
00432 E_END("limitint::operator -=", "");
00433 }
00434
00435
00436 template <class B> limitint<B> & limitint<B>::operator *= (const limitint & arg)
00437 {
00438 E_BEGIN;
00439 static const B max_power = bytesize*8 - 1;
00440
00441 B total = int_tools_higher_power_of_2(field) + int_tools_higher_power_of_2(arg.field) + 1;
00442 if(total > max_power)
00443
00444
00445
00446
00447 throw Elimitint();
00448
00449 total = field*arg.field;
00450 if(field != 0 && arg.field != 0)
00451 if(total < field || total < arg.field)
00452 throw Elimitint();
00453 field = total;
00454 return *this;
00455 E_END("limitint::operator *=", "");
00456 }
00457
00458 template <class B> template<class T> limitint<B> limitint<B>::power(const T & exponent) const
00459 {
00460 limitint ret = 1;
00461 for(T count = 0; count < exponent; ++count)
00462 ret *= *this;
00463
00464 return ret;
00465 }
00466
00467 template <class B> limitint<B> & limitint<B>::operator /= (const limitint & arg)
00468 {
00469 E_BEGIN;
00470 if(arg == 0)
00471 throw Einfinint("limitint.cpp : operator /=", gettext("Division by zero"));
00472
00473 field /= arg.field;
00474 return *this;
00475 E_END("limitint::operator /=", "");
00476 }
00477
00478 template <class B> limitint<B> & limitint<B>::operator %= (const limitint & arg)
00479 {
00480 E_BEGIN;
00481 if(arg == 0)
00482 throw Einfinint("limitint.cpp : operator %=", gettext("Division by zero"));
00483
00484 field %= arg.field;
00485 return *this;
00486 E_END("limitint::operator /=", "");
00487 }
00488
00489 template <class B> limitint<B> & limitint<B>::operator >>= (U_32 bit)
00490 {
00491 E_BEGIN;
00492 if(bit >= sizeof_field)
00493 field = 0;
00494 else
00495 field >>= bit;
00496 return *this;
00497 E_END("limitint::operator >>=", "U_32");
00498 }
00499
00500 template <class B> limitint<B> & limitint<B>::operator >>= (limitint bit)
00501 {
00502 E_BEGIN;
00503 field >>= bit.field;
00504 return *this;
00505 E_END("limitint::operator >>=", "limitint");
00506 }
00507
00508 template <class B> limitint<B> & limitint<B>::operator <<= (U_32 bit)
00509 {
00510 E_BEGIN;
00511 if(bit + int_tools_higher_power_of_2(field) >= bytesize*8)
00512 throw Elimitint();
00513 field <<= bit;
00514 return *this;
00515 E_END("limitint::operator <<=", "U_32");
00516 }
00517
00518 template <class B> limitint<B> & limitint<B>::operator <<= (limitint bit)
00519 {
00520 E_BEGIN;
00521 if(bit.field + int_tools_higher_power_of_2(field) >= bytesize*8)
00522 throw Elimitint();
00523 field <<= bit.field;
00524 return *this;
00525 E_END("limitint::operator <<=", "limitint");
00526 }
00527
00528 template <class B> limitint<B> & limitint<B>::operator &= (const limitint & arg)
00529 {
00530 E_BEGIN;
00531 field &= arg.field;
00532 return *this;
00533 E_END("limitint::operator &=", "");
00534 }
00535
00536 template <class B> limitint<B> & limitint<B>::operator |= (const limitint & arg)
00537 {
00538 E_BEGIN;
00539 field |= arg.field;
00540 return *this;
00541 E_END("limitint::operator |=", "");
00542 }
00543
00544 template <class B> limitint<B> & limitint<B>::operator ^= (const limitint & arg)
00545 {
00546 E_BEGIN;
00547 field ^= arg.field;
00548 return *this;
00549 E_END("limitint::operator ^=", "");
00550 }
00551
00552 template <class B> U_32 limitint<B>::operator % (U_32 arg) const
00553 {
00554 E_BEGIN;
00555 return U_32(field % arg);
00556 E_END("limitint::modulo", "");
00557 }
00558
00559 template <class B> template <class T> void limitint<B>::limitint_from(T a)
00560 {
00561 E_BEGIN;
00562 if(sizeof(a) <= bytesize || a <= (T)(max_value))
00563 field = B(a);
00564 else
00565 throw Elimitint();
00566 E_END("limitint::limitint_from", "");
00567 }
00568
00569 template <class B> template <class T> void limitint<B>::limitint_unstack_to(T &a)
00570 {
00571 E_BEGIN;
00572
00573
00574
00575 static const T max_T = ~T(0) > 0 ? ~T(0) : ~int_tools_rotate_right_one_bit(T(1));
00576 T step = max_T - a;
00577
00578 if(field < (B)(step) && (T)(field) < step)
00579 {
00580 a += field;
00581 field = 0;
00582 }
00583 else
00584 {
00585 field -= step;
00586 a = max_T;
00587 }
00588
00589 E_END("limitint::limitint_unstack_to", "");
00590 }
00591
00592 template <class B> limitint<B> limitint<B>::get_storage_size() const
00593 {
00594 B tmp = field;
00595 B ret = 0;
00596
00597 while(tmp != 0)
00598 {
00599 tmp >>= 8;
00600 ret++;
00601 }
00602
00603 return limitint<B>(ret);
00604 }
00605
00606 template <class B> unsigned char limitint<B>::operator [] (const limitint & position) const
00607 {
00608 B tmp = field;
00609 B index = position.field;
00610
00611 while(index > 0)
00612 {
00613 tmp >>= 8;
00614 index--;
00615 }
00616
00617 return (unsigned char)(tmp & 0xFF);
00618 }
00619
00620 template <class B> void limitint<B>::setup_endian()
00621 {
00622 E_BEGIN;
00623 U_16 u = 1;
00624 unsigned char *ptr = (unsigned char *)(&u);
00625
00626 if(ptr[0] == 1)
00627 used_endian = big_endian;
00628 else
00629 used_endian = little_endian;
00630 E_END("limitint::setup_endian", "");
00631 }
00632
00633
00634 template <class B> bool limitint<B>::is_system_big_endian()
00635 {
00636 if(used_endian == not_initialized)
00637 setup_endian();
00638
00639 switch(used_endian)
00640 {
00641 case big_endian:
00642 return true;
00643 case little_endian:
00644 return false;
00645 case not_initialized:
00646 throw SRC_BUG;
00647 default:
00648 throw SRC_BUG;
00649 }
00650 }
00651
00652
00656
00657 template <class B> limitint<B> operator + (const limitint<B> & a, const limitint<B> & b)
00658 {
00659 E_BEGIN;
00660 limitint<B> ret = a;
00661 ret += b;
00662
00663 return ret;
00664 E_END("operator +", "limitint");
00665 }
00666
00667 template <class B> limitint<B> operator - (const limitint<B> & a, const limitint<B> & b)
00668 {
00669 E_BEGIN;
00670 limitint<B> ret = a;
00671 ret -= b;
00672
00673 return ret;
00674 E_END("operator -", "limitint");
00675 }
00676
00677 template <class B> limitint<B> operator * (const limitint<B> & a, const limitint<B> & b)
00678 {
00679 E_BEGIN;
00680 limitint<B> ret = a;
00681 ret *= b;
00682
00683 return ret;
00684 E_END("operator *", "limitint");
00685 }
00686
00687 template <class B> limitint<B> operator / (const limitint<B> & a, const limitint<B> & b)
00688 {
00689 E_BEGIN;
00690 limitint<B> ret = a;
00691 ret /= b;
00692
00693 return ret;
00694 E_END("operator / ", "limitint");
00695 }
00696
00697 template <class B> limitint<B> operator % (const limitint<B> & a, const limitint<B> & b)
00698 {
00699 E_BEGIN;
00700 limitint<B> ret = a;
00701 ret %= b;
00702
00703 return ret;
00704 E_END("operator %", "limitint");
00705 }
00706
00707 template <class B> limitint<B> operator >> (const limitint<B> & a, U_32 bit)
00708 {
00709 E_BEGIN;
00710 limitint<B> ret = a;
00711 ret >>= bit;
00712 return ret;
00713 E_END("operator >>", "limitint, U_32");
00714 }
00715
00716 template <class B> limitint<B> operator >> (const limitint<B> & a, const limitint<B> & bit)
00717 {
00718 E_BEGIN;
00719 limitint<B> ret = a;
00720 ret >>= bit;
00721 return ret;
00722 E_END("operator >>", "limitint");
00723 }
00724
00725 template <class B> limitint<B> operator << (const limitint<B> & a, U_32 bit)
00726 {
00727 E_BEGIN;
00728 limitint<B> ret = a;
00729 ret <<= bit;
00730 return ret;
00731 E_END("operator <<", "limitint, U_32");
00732 }
00733
00734 template <class B> limitint<B> operator << (const limitint<B> & a, const limitint<B> & bit)
00735 {
00736 E_BEGIN;
00737 limitint<B> ret = a;
00738 ret <<= bit;
00739 return ret;
00740 E_END("operator <<", "limitint");
00741 }
00742
00743 template <class B> limitint<B> operator & (const limitint<B> & a, U_32 bit)
00744 {
00745 E_BEGIN;
00746 limitint<B> ret = a;
00747 ret &= bit;
00748 return ret;
00749 E_END("operator &", "limitint");
00750 }
00751
00752 template <class B> limitint<B> operator & (const limitint<B> & a, const limitint<B> & bit)
00753 {
00754 E_BEGIN;
00755 limitint<B> ret = a;
00756 ret &= bit;
00757 return ret;
00758 E_END("operator &", "limitint");
00759 }
00760
00761 template <class B> limitint<B> operator | (const limitint<B> & a, U_32 bit)
00762 {
00763 E_BEGIN;
00764 limitint<B> ret = a;
00765 ret |= bit;
00766 return ret;
00767 E_END("operator |", "U_32");
00768 }
00769
00770 template <class B> limitint<B> operator | (const limitint<B> & a, const limitint<B> & bit)
00771 {
00772 E_BEGIN;
00773 limitint<B> ret = a;
00774 ret |= bit;
00775 return ret;
00776 E_END("operator |", "limitint");
00777 }
00778
00779 template <class B> limitint<B> operator ^ (const limitint<B> & a, U_32 bit)
00780 {
00781 E_BEGIN;
00782 limitint<B> ret = a;
00783 ret ^= bit;
00784 return ret;
00785 E_END("operator ^", "U_32");
00786 }
00787
00788 template <class B> limitint<B> operator ^ (const limitint<B> & a, const limitint<B> & bit)
00789 {
00790 E_BEGIN;
00791 limitint<B> ret = a;
00792 ret ^= bit;
00793 return ret;
00794 E_END("operator ^", "limitint");
00795 }
00796
00797
00798 }
00799
00800 #endif