Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

FP.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Fri Apr 22 16:37:05 EDT 2005 by irina.furman@intel.com 
00020 //      modified on Fri Dec 17 11:47:41 EST 2004 by ken@xorian.net         
00021 //      modified on Tue Feb  8 14:19:14 PST 2000 by mann  
00022 //      modified on Tue Dec 16 00:15:51 PST 1997 by heydon
00023 
00024 #include <Basics.H>
00025 #include <FS.H>
00026 #include <VestaLog.H>
00027 #include <Recovery.H>
00028 #include "FP.H"
00029 #include "Poly.H"
00030 #include "ByteModTable.H"
00031 
00032 using std::istream;
00033 using std::ostream;
00034 using std::ios;
00035 
00036 /* If defined, INLINE_POLYINC causes calls to PolyInc to be
00037    inlined; otherwise, actual calls are made to the PolyInc function. */
00038 #define INLINE_POLYINC
00039 
00040 /* If defined, UNROLL_LOOP uses a more efficient loop unrolling
00041    in the ExtendByWords function. */
00042 #define UNROLL_LOOP
00043 
00044 const int WordSize = sizeof(Word);
00045 const int WordBits = WordSize * 8;
00046 
00047 // This macro is used to make sure that a Word read from memory is
00048 // ordered correctly.  (Because the fingerprinting algorithm
00049 // conceptually processes data in a bit-sequential manner,
00050 // non-little-endian machines must do some byte swapping.)
00051 #if BYTE_ORDER == BIG_ENDIAN
00052 #define ORDER_WORD_BYTES(p_x) Basics::swab64(p_x)
00053 #elif BYTE_ORDER == LITTLE_ENDIAN
00054 #define ORDER_WORD_BYTES(p_x) (p_x)
00055 #else
00056 #error Unknown byte order
00057 #endif
00058 
00059 // Polynomial Extension Functions ---------------------------------------------
00060 
00061 #ifdef UNROLL_LOOP
00062 static Poly *ByteModTable0 = ByteModTable[0];
00063 static Poly *ByteModTable1 = ByteModTable[1];
00064 static Poly *ByteModTable2 = ByteModTable[2];
00065 static Poly *ByteModTable3 = ByteModTable[3];
00066 static Poly *ByteModTable4 = ByteModTable[4];
00067 static Poly *ByteModTable5 = ByteModTable[5];
00068 static Poly *ByteModTable6 = ByteModTable[6];
00069 #endif
00070 static Poly *ByteModTable7 = ByteModTable[7];
00071 
00072 static void ExtendByChar(/*INOUT*/ Poly& p, const unsigned char c) throw ()
00073 /* Change "p" to be the residue mod P of the polynomial represented by "p"
00074    followed by the character "c". This is the straightforward translation
00075    of the "ExtendByBytes" function below with "*source == c" and "n == 1". */
00076 {
00077     Poly temp = POLY_ZERO;
00078     unsigned char c0 = (unsigned char)(p.w[0]);
00079 #ifdef INLINE_POLYINC
00080     Poly *tblPoly = &(ByteModTable7[c0]);
00081     temp.w[0] ^= tblPoly->w[0];
00082     temp.w[1] ^= tblPoly->w[1];
00083 #else
00084     PolyInc(/*INOUT*/ temp, ByteModTable7[c0]);
00085 #endif
00086     p.w[0] = (p.w[0] >> 8) | (p.w[1] << (WordBits - 8));
00087     p.w[1] = (p.w[1] >> 8) | (((Word)c) << (WordBits - 8));
00088 #ifdef INLINE_POLYINC
00089     p.w[0] ^= temp.w[0];
00090     p.w[1] ^= temp.w[1];
00091 #else
00092     PolyInc(/*INOUT*/ p, temp);
00093 #endif
00094 }
00095 
00096 static void ExtendByBytes(/*INOUT*/ Poly& p,
00097   const unsigned char *source, int n) throw ()
00098 /* Change "p" to be the residue mod P of the polynomial represented by "p"
00099    followed by "n" chars starting from "source". "n" must be a number
00100    between 1 and 7. */
00101 {
00102     assert(0 < n && n < 8);
00103 
00104     const int bits = 8 * n;
00105     Poly temp = POLY_ZERO;
00106     Word mask = p.w[0];
00107     for (int i = 0; i < n; i++) {
00108         unsigned char c0 = (unsigned char)mask;
00109 #ifdef INLINE_POLYINC
00110         Poly *tblPoly = &(ByteModTable[i+8-n][c0]);
00111         temp.w[0] ^= tblPoly->w[0];
00112         temp.w[1] ^= tblPoly->w[1];
00113 #else
00114         PolyInc(/*INOUT*/ temp, ByteModTable[i+8-n][c0]);
00115 #endif
00116         mask >>= 8;
00117     }
00118 #if defined(VALGRIND_SUPPORT)
00119     // Lower performance but completely safe, even as far as paranoid
00120     // run-time checkers like valgrind are concerned.
00121     mask = 0;
00122     char *mask_c = (char *) &mask;
00123     for(int i = 0; i < n; i++)
00124       {
00125         mask_c[i] = source[i];
00126       }
00127     mask = ORDER_WORD_BYTES(mask);
00128 #else
00129     unsigned int align_mask = sizeof(Word) - 1;
00130     int align = ((PointerInt) source) & align_mask;
00131     if (align == 0) {
00132         mask = ORDER_WORD_BYTES(*(Word *)source);
00133     } else {
00134         /* The following is the same as "mask = *(Word *)source",
00135            but it avoids unaligned accesses. */
00136         Word *w1 = (Word *)(source - align);
00137         // We only need w2 if at least the first byte of it is part of
00138         // the source.  (If it's past the end of the source data,
00139         // there's no guarantee it's in a valid region of memory.)
00140         Word *w2 = ((WordSize - align) < n)
00141           ? (Word *)(source + (WordSize - align))
00142           : (Word *)0;
00143         align <<= 3; // align *= 8 (convert to bits)
00144         mask = (ORDER_WORD_BYTES(*w1) >> align);
00145         // If we have a second word, OR it into the mask.
00146         if(w2 != 0)
00147           {
00148             mask |= (ORDER_WORD_BYTES(*w2) << (WordBits - align));
00149           }
00150     }
00151 #endif
00152     p.w[0] = (p.w[0] >> bits) | (p.w[1] << (WordBits-bits));
00153     p.w[1] = (p.w[1] >> bits) | (mask << (WordBits-bits));
00154 #ifdef INLINE_POLYINC
00155     p.w[0] ^= temp.w[0];
00156     p.w[1] ^= temp.w[1];
00157 #else
00158     PolyInc(/*INOUT*/ p, temp);
00159 #endif
00160 }
00161 
00162 static void ExtendByWords(/*INOUT*/ Poly& p, const Word *source, int n)
00163   throw ()
00164 /* Change "p" to be the residue mod P of a polynomial represented by "p"
00165    followed by "n" words starting from "source". */
00166 {
00167     Poly temp;
00168 
00169     for (int i = 0; i < n; i++) {
00170         temp = POLY_ZERO;
00171 #ifdef UNROLL_LOOP
00172         {
00173             unsigned char *ptr = (unsigned char *) &(p.w[0]);
00174 #if BYTE_ORDER == BIG_ENDIAN
00175             Poly p7 = ByteModTable7[*ptr++];
00176             Poly p6 = ByteModTable6[*ptr++];
00177             Poly p5 = ByteModTable5[*ptr++];
00178             Poly p4 = ByteModTable4[*ptr++];
00179             Poly p3 = ByteModTable3[*ptr++];
00180             Poly p2 = ByteModTable2[*ptr++];
00181             Poly p1 = ByteModTable1[*ptr++];
00182             Poly p0 = ByteModTable0[*ptr];
00183 #elif BYTE_ORDER == LITTLE_ENDIAN
00184             Poly p0 = ByteModTable0[*ptr++];
00185             Poly p1 = ByteModTable1[*ptr++];
00186             Poly p2 = ByteModTable2[*ptr++];
00187             Poly p3 = ByteModTable3[*ptr++];
00188             Poly p4 = ByteModTable4[*ptr++];
00189             Poly p5 = ByteModTable5[*ptr++];
00190             Poly p6 = ByteModTable6[*ptr++];
00191             Poly p7 = ByteModTable7[*ptr];
00192 #else
00193 #error Unknown byte order
00194 #endif
00195             temp.w[0] ^= p0.w[0]; temp.w[1] ^= p0.w[1];
00196             temp.w[0] ^= p1.w[0]; temp.w[1] ^= p1.w[1];
00197             temp.w[0] ^= p2.w[0]; temp.w[1] ^= p2.w[1];
00198             temp.w[0] ^= p3.w[0]; temp.w[1] ^= p3.w[1];
00199             temp.w[0] ^= p4.w[0]; temp.w[1] ^= p4.w[1];
00200             temp.w[0] ^= p5.w[0]; temp.w[1] ^= p5.w[1];
00201             temp.w[0] ^= p6.w[0]; temp.w[1] ^= p6.w[1];
00202             temp.w[0] ^= p7.w[0]; temp.w[1] ^= p7.w[1];
00203         }
00204 #else /* original version */
00205         Word mask = p.w[0];
00206         for (int j = 0;  j < 8; j++) {
00207             unsigned char c0 = (unsigned char)mask;
00208 #ifdef INLINE_POLYINC
00209             Poly *tblPoly = &(ByteModTable[j][c0]);
00210             temp.w[0] ^= tblPoly->w[0];
00211             temp.w[1] ^= tblPoly->w[1];
00212 #else
00213             PolyInc(/*INOUT*/ temp, ByteModTable[j][c0]);
00214 #endif // USE_POLY_INC
00215             mask >>= 8;
00216         }
00217 #endif
00218         p.w[0] = p.w[1];
00219         p.w[1] = ORDER_WORD_BYTES(source[i]);
00220 #ifdef INLINE_POLYINC
00221         p.w[0] ^= temp.w[0];
00222         p.w[1] ^= temp.w[1];
00223 #else
00224         PolyInc(/*INOUT*/ p, temp);
00225 #endif
00226     }
00227 }
00228 
00229 // Fingerprint Extension Function ---------------------------------------------
00230 
00231 static void RawFPExtend(/*INOUT*/ RawFP& fp,
00232   const char *addr, int len) throw ()
00233 /* Given that "fp" is the fingerprint of a string "s", set "fp" to the
00234    fingerprint of "s" concatenated with the "len" chars starting at "addr". */
00235 {
00236     unsigned char *p = (unsigned char *) addr;
00237     int residue;
00238 
00239     // Do first residue bytes
00240     if (len >= WordSize) {
00241         residue = WordSize - (((PointerInt) p) % WordSize);
00242         if (residue != WordSize) {
00243             ExtendByBytes(/*INOUT*/ fp, p, residue);
00244             p += residue;
00245             len -= residue;
00246         }
00247     }
00248 
00249     // Do middle bytes, now starting from word boundary
00250     if (len >= WordSize) {
00251         ExtendByWords(/*INOUT*/ fp, (Word *) p, len / WordSize);
00252         p += (len / WordSize) * WordSize;
00253         len %= WordSize;
00254     }
00255 
00256     // Do last few bytes
00257     if (len != 0) {
00258         ExtendByBytes(/*INOUT*/ fp, p, len);
00259     }
00260 }
00261 
00262 // FP::Tag Methods ------------------------------------------------------------
00263 
00264 void FP::Tag::Init(const char *s, int len) throw ()
00265 {
00266     RawFP fp = POLY_ONE;
00267     RawFPExtend(/*INOUT*/ fp, s, len);
00268     Permute(fp);
00269 }
00270 
00271 FP::Tag& FP::Tag::Extend(const char *s, int len) throw ()
00272 {
00273     if (len < 0) len = strlen(s);
00274     RawFP fp;
00275     Unpermute(/*OUT*/ fp);
00276     RawFPExtend(/*INOUT*/ fp, s, len);
00277     Permute(fp);
00278     return *this;
00279 }
00280 
00281 FP::Tag& FP::Tag::Extend(char c) throw ()
00282 {
00283     RawFP fp;
00284     Unpermute(/*OUT*/ fp);
00285     ExtendByChar(/*INOUT*/ fp, c);
00286     Permute(fp);
00287     return *this;
00288 }
00289 
00290 void FP::Tag::ExtendRaw(/*INOUT*/ RawFP &fp, const char *s, int len)
00291   throw ()
00292 {
00293     if (len < 0) len = strlen(s);
00294     RawFPExtend(/*INOUT*/ fp, s, len);
00295 }
00296 
00297 void FP::Tag::ExtendRaw(/*INOUT*/ RawFP &fp, char c) throw ()
00298 {
00299     ExtendByChar(/*INOUT*/ fp, c);
00300 }
00301 
00302 Word FP::Tag::Hash() const throw ()
00303 {
00304     Word res = w[0];
00305     for (int i = 1; i < FP::WordCnt; i++) res ^= w[i];
00306     return res;
00307 }
00308 
00309 void FP::Tag::ToBytes(unsigned char *buffer) const throw ()
00310 {
00311   unsigned int i = 0;
00312   for(unsigned int word = 0; word < FP::WordCnt; word++)
00313     {
00314       for(unsigned int bit = 0; bit < WordBits; bit +=8)
00315         {
00316           buffer[i++] = (this->w[word] >> bit);
00317         }
00318     }
00319   assert(i == FP::ByteCnt);
00320 }
00321 
00322 void FP::Tag::FromBytes(const unsigned char *buffer) throw ()
00323 {
00324   unsigned int i = 0;
00325   for(unsigned int word = 0; word < FP::WordCnt; word++)
00326     {
00327       this->w[word] = 0;
00328       for(unsigned int bit = 0; bit < WordBits; bit +=8)
00329         {
00330           this->w[word] |= (((Word) buffer[i++]) << bit);
00331         }
00332     }
00333   assert(i == FP::ByteCnt);
00334 }
00335 
00336 bool FP::Tag::operator == (const FP::Tag& other) const throw ()
00337 {
00338     for (int i = 0; i < FP::WordCnt; i++) {
00339         if (this->w[i] != other.w[i]) return false;
00340     }
00341     return true;
00342 }
00343 
00344 bool FP::Tag::operator != (const FP::Tag& other) const throw ()
00345 {
00346     for (int i = 0; i < FP::WordCnt; i++) {
00347         if (this->w[i] != other.w[i]) return true;
00348     }
00349     return false;
00350 }
00351 
00352 void FP::Tag::Print(ostream &os, const char *word_separator)
00353   const throw ()
00354 {
00355   char buff[17];
00356   for (int i = 0; i < FP::WordCnt; i++) {
00357     sprintf(buff, "%016" FORMAT_LENGTH_INT_64 "x", this->w[i]);
00358     os << buff;
00359     if (i < FP::WordCnt - 1) os << word_separator;
00360   }
00361 }
00362 
00363 int Compare(const FP::Tag& fp1, const FP::Tag& fp2) throw ()
00364 {
00365     for (int i = 0; i < FP::WordCnt; i++) {
00366         if (fp1.w[i] != fp2.w[i]) {
00367             return ((fp1.w[i] < fp2.w[i]) ? -1 : 1);
00368         }
00369     }
00370     return 0;
00371 }
00372 
00373 /* Tags are produced from fingerprints as follows:
00374 
00375    1) Use a permutation "perm" on the byte values; that is, each byte value is
00376    individually permuted to a value in the interval [0..255].
00377 
00378    2) View the permuted result as a vector of two long unsigneds and
00379    multiply it by a non-singular matrix A with coefficients in
00380    [0..2^64-1] mod 2^64.
00381 
00382    To convert from a tag back into a fingerprint, we keep the
00383    inverse of "perm" in "perminv", and the inverse of A in B.
00384 */
00385 
00386 const Word
00387   A[2][2] = {{CONST_INT_64(0xce36f163f737a677),
00388               CONST_INT_64(0x431bf4ecc646b337)},
00389              {CONST_INT_64(0x1960326FA38D04D0),
00390               CONST_INT_64(0x10155F23A2F024F9)}},
00391   B[2][2] = {{CONST_INT_64(0x94033a389a279d77),
00392               CONST_INT_64(0xd79f3b15576598a7)},
00393              {CONST_INT_64(0x67f2d59b2369b1d0),
00394               CONST_INT_64(0x63e096e4228c019)}};
00395 
00396 const unsigned char
00397   perm[256] = {89, 171, 235, 183, 176, 181, 91, 54, 49,
00398     151, 11, 0, 73, 138, 118, 160, 172, 251, 255, 192, 102, 39, 15, 169,
00399     149, 110, 240, 133, 213, 196, 217, 199, 29, 43, 52, 153, 32, 2, 179,
00400     6, 211, 165, 161, 224, 194, 209, 8, 93, 197, 162, 207, 229, 83, 247,
00401     129, 188, 145, 186, 59, 147, 202, 109, 141, 78, 38, 92, 68, 190,
00402     252, 116, 85, 184, 34, 103, 88, 140, 123, 76, 131, 67, 26, 166, 185,
00403     63, 90, 86, 5, 246, 58, 238, 231, 232, 241, 106, 7, 225, 75, 45,
00404     146, 19, 23, 99, 9, 216, 96, 236, 95, 218, 182, 40, 124, 201, 82,
00405     230, 214, 206, 107, 137, 249, 212, 77, 119, 253, 1, 210, 35, 69,
00406     167, 79, 4, 198, 180, 226, 122, 128, 244, 163, 250, 121, 55, 135,
00407     14, 154, 100, 243, 187, 173, 3, 46, 33, 157, 42, 152, 51, 30, 142,
00408     98, 48, 148, 254, 223, 159, 41, 74, 155, 248, 205, 18, 175, 108, 56,
00409     228, 195, 17, 237, 104, 62, 47, 12, 72, 158, 25, 134, 234, 239, 242,
00410     80, 143, 101, 203, 81, 215, 10, 27, 204, 24, 37, 191, 105, 208, 132,
00411     126, 50, 156, 227, 125, 65, 130, 139, 136, 31, 44, 97, 94, 53, 127,
00412     233, 221, 84, 117, 220, 219, 200, 164, 120, 20, 113, 22, 168, 66,
00413     170, 87, 150, 70, 193, 189, 177, 28, 36, 114, 178, 13, 71, 64, 115,
00414     16, 144, 57, 245, 111, 222, 60, 174, 61, 112, 21},
00415   perminv[256] = {11, 123, 37, 147, 129, 86, 39, 94, 46, 102, 192, 10,
00416     178, 241, 141, 22, 245, 173, 167, 99, 225, 255, 227, 100, 195, 181,
00417     80, 193, 237, 32, 154, 210, 36, 149, 72, 125, 238, 196, 64, 21, 109,
00418     162, 151, 33, 211, 97, 148, 177, 157, 8, 202, 153, 34, 214, 7, 139,
00419     170, 247, 88, 58, 251, 253, 176, 83, 243, 206, 229, 79, 66, 126,
00420     233, 242, 179, 12, 163, 96, 77, 120, 63, 128, 186, 190, 112, 52,
00421     218, 70, 85, 231, 74, 0, 84, 6, 65, 47, 213, 106, 104, 212, 156,
00422     101, 143, 188, 20, 73, 175, 198, 93, 116, 169, 61, 25, 249, 254,
00423     226, 239, 244, 69, 219, 14, 121, 224, 138, 133, 76, 110, 205, 201,
00424     215, 134, 54, 207, 78, 200, 27, 182, 140, 209, 117, 13, 208, 75, 62,
00425     155, 187, 246, 56, 98, 59, 158, 24, 232, 9, 152, 35, 142, 164, 203,
00426     150, 180, 161, 15, 42, 49, 136, 223, 41, 81, 127, 228, 23, 230, 1,
00427     16, 146, 252, 168, 4, 236, 240, 38, 131, 5, 108, 3, 71, 82, 57, 145,
00428     55, 235, 67, 197, 19, 234, 44, 172, 29, 48, 130, 31, 222, 111, 60,
00429     189, 194, 166, 115, 50, 199, 45, 124, 40, 119, 28, 114, 191, 103,
00430     30, 107, 221, 220, 217, 250, 160, 43, 95, 132, 204, 171, 51, 113,
00431     90, 91, 216, 183, 2, 105, 174, 89, 184, 26, 92, 185, 144, 135, 248,
00432     87, 53, 165, 118, 137, 17, 68, 122, 159, 18};
00433 
00434 void FP::Tag::Permute(const RawFP &f) throw ()
00435 {
00436     unsigned char *p = (unsigned char *) &(f.w);
00437  
00438     // First use a permutation on the byte values
00439     int i;
00440     for (i=0;  i < FP::ByteCnt; i++, p++) {
00441         *p = perm[*p];
00442     }
00443 
00444     // Second, multiply by the matrix "A"
00445     this->w[0] = f.w[0] * A[0][0] + f.w[1] * A[1][0];
00446     this->w[1] = f.w[0] * A[0][1] + f.w[1] * A[1][1];
00447 }
00448 
00449 void FP::Tag::Unpermute(/*OUT*/ RawFP &res) const throw ()
00450 {
00451     // multiply the the inverse matrix "B"
00452     res.w[0] = w[0] * B[0][0] + w[1] * B[1][0];
00453     res.w[1] = w[0] * B[0][1] + w[1] * B[1][1];
00454  
00455     // permute bytes with inverse "perminv"
00456     int i;
00457     unsigned char *p = (unsigned char *) &(res.w);
00458     for (i=0;  i < FP::ByteCnt; i++, p++) {
00459         *p = perminv[*p];
00460     }
00461 }
00462 
00463 // FP::List Methods -----------------------------------------------------------
00464 
00465 void FP::List::Log(VestaLog& log) const throw (VestaLog::Error)
00466 {
00467     log.write((char *)(&(this->len)), sizeof(int));
00468     for (int i = 0; i < this->len; i++) {
00469         this->fp[i].Log(log);
00470     }
00471 }
00472 
00473 void FP::List::Recover(RecoveryReader &rd)
00474   throw (VestaLog::Error, VestaLog::Eof)
00475 {
00476     rd.readAll((char *)(&(this->len)), sizeof(int));
00477     if (this->len > 0) {
00478         this->fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00479         for (int i = 0; i < this->len; i++) {
00480             this->fp[i].Recover(rd);
00481         }
00482     } else {
00483         this->fp = (FP::Tag *)NULL;
00484     }
00485 }
00486 
00487 void FP::List::Write(ostream &ofs) const throw (FS::Failure)
00488 {
00489     FS::Write(ofs, (char *)(&(this->len)), sizeof(int));
00490     for (int i = 0; i < this->len; i++) {
00491         this->fp[i].Write(ofs);
00492     }
00493 }
00494 
00495 void FP::List::Read(istream &ifs) throw (FS::EndOfFile, FS::Failure)
00496 {
00497     FS::Read(ifs, (char *)(&(this->len)), sizeof(int));
00498     if (this->len > 0) {
00499         this->fp = NEW_PTRFREE_ARRAY(FP::Tag, this->len);
00500         for (int i = 0; i < this->len; i++) {
00501             this->fp[i].Read(ifs);
00502         }
00503     } else {
00504         this->fp = (FP::Tag *)NULL;
00505     }
00506 }
00507 
00508 void FP::List::Send(SRPC &srpc) const throw (SRPC::failure)
00509 {
00510     srpc.send_seq_start(this->len);
00511     for (int i = 0; i < this->len; i++) {
00512         this->fp[i].Send(srpc);
00513     }
00514     srpc.send_seq_end();
00515 }
00516 
00517 void FP::List::Recv(SRPC &srpc) throw (SRPC::failure)
00518 {
00519     srpc.recv_seq_start(&(this->len), NULL);
00520     this->fp = NEW_PTRFREE_ARRAY(FP::Tag, this->len);
00521     for (int i = 0; i < this->len; i++) {
00522         this->fp[i].Recv(srpc);
00523     }
00524     srpc.recv_seq_end();
00525 }
00526 
00527 inline void Indent(ostream &os, int indent) throw ()
00528 {
00529     for (int i = 0; i < indent; i++) os << " ";
00530 }
00531 
00532 void FP::List::Print(ostream &os, int indent) const throw ()
00533 {
00534     if (this->len > 0) {
00535         for (int i = 0; i < this->len; i++) {
00536             Indent(os, indent);
00537             os << "fp[" << i << "] = " << this->fp[i] << "\n";
00538         }
00539     } else {
00540         Indent(os, indent);
00541         os << "<< no fingerprints >>\n";
00542     }
00543 }
00544 
00545 // FP static Methods ----------------------------------------------------------
00546 
00547 void FP::FileContents(istream &ifs, /*INOUT*/ FP::Tag &fp)
00548   throw (FS::Failure)
00549 {
00550     const int BuffSize = 1024;
00551     char buff[BuffSize];
00552     while (true) {
00553         // try reading a full buffer's worth
00554         if (ifs.read(buff, BuffSize)) {
00555             // read completed successfully
00556             fp.Extend(buff, BuffSize);
00557         } else {
00558             // error or EOF
00559             int numRead = ifs.gcount();
00560             if (ifs.rdstate() & ios::failbit && numRead < BuffSize) {
00561                 // EOF was encountered
00562                 fp.Extend(buff, numRead);
00563                 // ifs.clear(0);  // so close() will succeed
00564                 break;
00565             } else {
00566                 // other error
00567                 throw (FS::Failure("FP::FileContents"));
00568             }
00569         }
00570     }
00571 }

Generated on Mon May 8 00:48:41 2006 for Vesta by  doxygen 1.4.2