1 /* $Id: checksum.cpp 619609 2020-11-06 20:26:34Z ivanov $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Eugene Vasilchenko, Vladimir Ivanov
27 *
28 * File Description: Checksum and hash calculation classes.
29 *
30 */
31
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistd.hpp>
34 #include <corelib/ncbifile.hpp>
35 #include <util/checksum.hpp>
36
37 // Use builtin versions of CityHash and FarmHash libraries,
38 // that compiles as separate files to avoid name clashing.
39 #include "checksum/cityhash/city.h"
40 #include "checksum/farmhash/config.h" // need for farmhash.h
41 #include "checksum/farmhash/farmhash.h"
42 // And include MurmurHash directly
43 #include "checksum/murmurhash/MurmurHash2.cxx"
44 #include "checksum/murmurhash/MurmurHash3.cxx"
45
46
47 #define USE_CRC32C_INTEL // try to use Intel CRC32C instructions
48
49 #ifdef USE_CRC32C_INTEL
50 # undef USE_CRC32C_INTEL // we'll define it again where available
51 # if defined(NCBI_COMPILER_GCC) || defined(NCBI_COMPILER_ICC) \
52 || defined(NCBI_COMPILER_ANY_CLANG)
53 # if defined(__x86_64__) || defined(__i386__)
54 # ifdef HAVE_CPUID_H
55 # include <cpuid.h>
56 # endif
57 # define USE_CRC32C_INTEL
58 # endif
59 # if defined(__x86_64__)
60 # define HAVE_CRC32C_64
61 # endif
62 # elif defined(NCBI_COMPILER_MSVC)
63 # if defined(_M_X64) || defined(_M_IX86)
64 # include <intrin.h>
65 # define USE_CRC32C_INTEL
66 # endif
67 # if defined(_M_X64)
68 # define HAVE_CRC32C_64
69 # endif
70 # endif
71 #endif
72
73
74 BEGIN_NCBI_SCOPE
75
76
77 static const size_t kCRC32Size = 256;
78 typedef Uint4 TCRC32Table[kCRC32Size];
79
80 // Defines
81
82 #define TABLES_COUNT 8
83 #define NCBI_USE_PRECOMPILED_CRC32_TABLES 1
84
85 // sx_Start must begin with "/* O" (see ValidChecksumLine() in checksum.hpp)
86 static const char sx_Start[] = "/* Original file checksum: ";
87 static const char sx_End[] = " */";
88 static const char sx_LineCount[] = "lines: ";
89 static const char sx_CharCount[] = "chars: ";
90
91 // Forward declarations
92
93 #ifdef NCBI_USE_PRECOMPILED_CRC32_TABLES
s_InitTableCRC32Forward()94 static inline void s_InitTableCRC32Forward() {}
s_InitTableCRC32Reverse()95 static inline void s_InitTableCRC32Reverse() {}
s_InitTableCRC32CReverse()96 static inline void s_InitTableCRC32CReverse() {}
97 #else
98 static void s_InitTableCRC32Forward();
99 static void s_InitTableCRC32Reverse();
100 static void s_InitTableCRC32CReverse();
101 #endif //NCBI_USE_PRECOMPILED_CRC32_TABLES
102
103 #ifdef USE_CRC32C_INTEL
104 static bool s_IsCRC32CIntelEnabled(void);
105 #endif
106
107
108
CChecksumBase(EMethodDef method)109 CChecksumBase::CChecksumBase(EMethodDef method)
110 : m_Method(eNone)
111 {
112 x_Reset(method);
113 }
114
115
~CChecksumBase()116 CChecksumBase::~CChecksumBase()
117 {
118 x_Free();
119 }
120
121
CChecksumBase(const CChecksumBase & other)122 CChecksumBase::CChecksumBase(const CChecksumBase& other)
123 : m_Method(other.m_Method),
124 m_CharCount(other.m_CharCount)
125 {
126 if ( m_Method == eMD5 ) {
127 m_Value.md5 = new CMD5(*other.m_Value.md5);
128 } else {
129 m_Value.v64 = other.m_Value.v64;
130 }
131 }
132
133
operator =(const CChecksumBase & other)134 CChecksumBase& CChecksumBase::operator= (const CChecksumBase& other)
135 {
136 if (&other == this){
137 return *this;
138 }
139 x_Free();
140
141 m_Method = other.m_Method;
142 m_CharCount = other.m_CharCount;
143
144 if ( m_Method == eMD5 ) {
145 m_Value.md5 = new CMD5(*other.m_Value.md5);
146 } else {
147 m_Value.v64 = other.m_Value.v64;
148 }
149 return *this;
150 }
151
152
GetResultHex(void) const153 string CChecksumBase::GetResultHex(void) const
154 {
155 switch (m_Method ) {
156 case eMD5:
157 return m_Value.md5->GetHexSum();
158 default:
159 if (GetBits() == 64) {
160 return NStr::NumericToString(GetResult64(), 0, 16);
161 }
162 if (GetBits() == 32) {
163 return NStr::NumericToString(GetResult32(), 0, 16);
164 }
165 _ASSERT(0);
166 return kEmptyStr;
167 }
168 }
169
170
x_Reset(EMethodDef method)171 void CChecksumBase::x_Reset(EMethodDef method)
172 {
173 x_Free();
174
175 m_Method = method;
176 m_Value.v64 = 0;
177 m_CharCount = 0;
178
179 switch ( method ) {
180 case eCRC32:
181 case eCRC32CKSUM:
182 s_InitTableCRC32Forward();
183 break;
184 case eCRC32ZIP:
185 case eCRC32INSD:
186 m_Value.v32 = ~0;
187 s_InitTableCRC32Reverse();
188 break;
189 case eCRC32C:
190 m_Value.v32 = ~0;
191 #ifdef USE_CRC32C_INTEL
192 if ( s_IsCRC32CIntelEnabled() ) {
193 break;
194 }
195 #endif
196 s_InitTableCRC32CReverse();
197 break;
198 case eAdler32:
199 m_Value.v32 = 1;
200 break;
201 case eMD5:
202 m_Value.md5 = new CMD5;
203 break;
204 case eCityHash32:
205 case eCityHash64:
206 case eFarmHash32:
207 case eFarmHash64:
208 case eMurmurHash2_32:
209 case eMurmurHash2_64:
210 case eMurmurHash3_32:
211 break;
212 default:
213 _ASSERT(0);
214 }
215 }
216
217
CHash(EMethod method)218 CHash::CHash(EMethod method)
219 : CChecksumBase((EMethodDef)method)
220 {
221 }
222
223
CHash(const CHash & other)224 CHash::CHash(const CHash& other)
225 : CChecksumBase(other)
226 {
227 }
228
229
operator =(const CHash & other)230 CHash& CHash::operator= (const CHash& other)
231 {
232 CChecksumBase::operator=(other);
233 return *this;
234 }
235
236
237 /// @sa CHash::SetSeed()
238 Uint8 CChecksumBase::m_Seed = 0;
239
240
SetSeed(Uint8 seed)241 void CHash::SetSeed(Uint8 seed)
242 {
243 m_Seed = seed;
244 }
245
246
Calculate(const CTempString str,EMethod method,Uint4 & hash)247 void CHash::Calculate(const CTempString str, EMethod method, Uint4& hash)
248 {
249 CHash h(method);
250 h.Calculate(str);
251 hash = h.GetResult32();
252 }
253
254
Calculate(const CTempString str,EMethod method,Uint8 & hash)255 void CHash::Calculate(const CTempString str, EMethod method, Uint8& hash)
256 {
257 CHash h(method);
258 h.Calculate(str);
259 hash = h.GetResult64();
260 }
261
262
Calculate(const char * str,size_t len,EMethod method,Uint4 & hash)263 void CHash::Calculate(const char* str, size_t len, EMethod method, Uint4& hash)
264 {
265 CHash h(method);
266 h.Calculate(str, len);
267 hash = h.GetResult32();
268 }
269
270
Calculate(const char * str,size_t len,EMethod method,Uint8 & hash)271 void CHash::Calculate(const char* str, size_t len, EMethod method, Uint8& hash)
272 {
273 CHash h(method);
274 h.Calculate(str, len);
275 hash = h.GetResult64();
276 }
277
278
CChecksum(EMethod method)279 CChecksum::CChecksum(EMethod method)
280 : CChecksumBase((EMethodDef)method),
281 m_LineCount(0)
282 {
283 }
284
285
CChecksum(const CChecksum & other)286 CChecksum::CChecksum(const CChecksum& other)
287 : CChecksumBase(other),
288 m_LineCount(other.m_LineCount)
289 {
290 }
291
292
operator =(const CChecksum & other)293 CChecksum& CChecksum::operator= (const CChecksum& other)
294 {
295 CChecksumBase::operator=(other);
296 m_LineCount = other.m_LineCount;
297 return *this;
298 }
299
300
WriteChecksum(CNcbiOstream & out) const301 CNcbiOstream& CChecksum::WriteChecksum(CNcbiOstream& out) const
302 {
303 if (!out.good()) {
304 return out;
305 }
306 out << sx_Start
307 << sx_LineCount << m_LineCount << ", "
308 << sx_CharCount << m_CharCount << ", ";
309 WriteChecksumData(out);
310 return out << sx_End << '\n';
311 }
312
313
ValidChecksumLineLong(const char * line,size_t len) const314 bool CChecksum::ValidChecksumLineLong(const char* line, size_t len) const
315 {
316 CNcbiOstrstream buffer;
317 WriteChecksum(buffer);
318 string buffer_str = CNcbiOstrstreamToString(buffer);
319 if ( buffer_str.size() != len + 1 ) { // account for '\n'
320 return false;
321 }
322 return memcmp(line, buffer_str.data(), len) == 0;
323 }
324
325
WriteHexSum(CNcbiOstream & out) const326 CNcbiOstream& CChecksum::WriteHexSum(CNcbiOstream& out) const
327 {
328 if ( GetMethod() == eMD5 ) {
329 out << m_Value.md5->GetHexSum();
330 } else {
331 IOS_BASE::fmtflags flags = out.setf(IOS_BASE::hex, IOS_BASE::basefield);
332 out << setprecision(8);
333 out << GetChecksum();
334 out.flags(flags);
335 }
336 return out;
337 }
338
339
WriteChecksumData(CNcbiOstream & out) const340 CNcbiOstream& CChecksum::WriteChecksumData(CNcbiOstream& out) const
341 {
342 switch ( GetMethod() ) {
343 case eMD5:
344 out << "MD5: ";
345 break;
346 case eAdler32:
347 out << "Adler32: ";
348 break;
349 case eCRC32:
350 case eCRC32ZIP:
351 case eCRC32INSD:
352 case eCRC32CKSUM:
353 case eCRC32C:
354 out << "CRC32: ";
355 break;
356 default:
357 _ASSERT(0);
358 return out;
359 }
360 WriteHexSum(out);
361 return out;
362 }
363
364
NextLine(void)365 void CChecksum::NextLine(void)
366 {
367 char eol = '\n';
368 x_Update(&eol, 1);
369 ++m_LineCount;
370 }
371
372
AddFile(const string & file_path)373 void CChecksum::AddFile(const string& file_path)
374 {
375 CFileIO f;
376 try {
377 f.Open(file_path, CFileIO::eOpen, CFileIO::eRead);
378 CChecksum tmp(*this);
379 size_t n;
380 char buf[1024 * 8];
381 while ((n = f.Read(buf, sizeof(buf))) > 0) {
382 tmp.AddChars(buf, n);
383 }
384 f.Close();
385 *this = tmp;
386 }
387 catch (CFileException& e) {
388 f.Close();
389 NCBI_RETHROW(e, CChecksumException, eFileIO, "Error add checksum for file: " + file_path);
390 throw;
391 }
392 }
393
394
AddStream(CNcbiIstream & is)395 void CChecksum::AddStream(CNcbiIstream& is)
396 {
397 if ( is.eof() ) {
398 return;
399 }
400 if ( !is.good() ) {
401 NCBI_THROW(CChecksumException, eStreamIO, "Input stream is not good()");
402 return;
403 }
404 CChecksum tmp(*this);
405
406 while ( !is.eof() ) {
407 char buf[1024 * 8];
408 is.read(buf, sizeof(buf));
409 size_t n = (size_t)is.gcount();
410 if (n) {
411 tmp.AddChars(buf, n);
412 } else {
413 if (is.fail() && !is.eof()) {
414 NCBI_THROW(CChecksumException, eStreamIO, "Error reading from input stream");
415 return;
416 }
417 }
418 }
419 *this = tmp;
420 }
421
422
423 // @deprecated
ComputeFileChecksum_deprecated(const string & path,CChecksum & checksum)424 CChecksum& ComputeFileChecksum_deprecated(const string& path, CChecksum& checksum)
425 {
426 CNcbiIfstream is(path.c_str(), IOS_BASE::in | IOS_BASE::binary);
427 if ( !is.is_open() ) {
428 return checksum;
429 }
430 while ( !is.eof() ) {
431 char buf[1024*8];
432 is.read(buf, sizeof(buf));
433 size_t count = (size_t)is.gcount();
434 if ( count ) {
435 checksum.AddChars(buf, count);
436 }
437 }
438 is.close();
439 return checksum;
440 }
441
442 // @deprecated
ComputeFileChecksum(const string & path,CChecksum::EMethod method)443 CChecksum ComputeFileChecksum(const string& path, CChecksum::EMethod method)
444 {
445 CChecksum checksum(method);
446 return ComputeFileChecksum_deprecated(path, checksum);
447 }
448
449 // @deprecated
ComputeFileChecksum(const string & path,CChecksum & checksum)450 CChecksum& ComputeFileChecksum(const string& path, CChecksum& checksum)
451 {
452 return ComputeFileChecksum_deprecated(path, checksum);
453 }
454
455 // @deprecated
ComputeFileCRC32(const string & path)456 Uint4 ComputeFileCRC32(const string& path)
457 {
458 CChecksum checksum(CChecksum::eCRC32);
459 return ComputeFileChecksum_deprecated(path, checksum).GetChecksum();
460 }
461
462
InitTables(void)463 void CChecksumBase::InitTables(void)
464 {
465 s_InitTableCRC32Forward();
466 s_InitTableCRC32Reverse();
467 s_InitTableCRC32CReverse();
468 }
469
470
471 template<size_t kCRC32Tables>
472 static inline
s_PrintTable(CNcbiOstream & out,const char * name,const TCRC32Table (& table)[kCRC32Tables])473 void s_PrintTable(CNcbiOstream& out, const char* name,
474 const TCRC32Table (&table)[kCRC32Tables])
475 {
476 const size_t kLineSize = 4;
477 out << "static const TCRC32Table " << name << "["<<kCRC32Tables<<"] = {";
478 for ( size_t k = 0; k < kCRC32Tables; ++k ) {
479 if ( k ) {
480 out << ',';
481 }
482 out << "\n {";
483 for ( size_t i = 0; i < kCRC32Size; ++i ) {
484 if ( i != 0 ) {
485 out << ',';
486 }
487 if ( i % kLineSize == 0 ) {
488 out << "\n ";
489 } else {
490 out << ' ';
491 }
492 out << "0x" << hex << setw(8) << setfill('0') << table[k][i];
493 }
494 out << "\n }";
495 }
496 out << dec << "\n};\n" << endl;
497 }
498
499
500 #ifdef NCBI_USE_PRECOMPILED_CRC32_TABLES
501
502 # include "crc32tables.c"
503
504 #else
505
506 static TCRC32Table s_CRC32TableForward[TABLES_COUNT];
507 static TCRC32Table s_CRC32TableReverse[TABLES_COUNT];
508 static TCRC32Table s_CRC32CTableReverse[TABLES_COUNT];
509
510 /////////////////////////////////////////////////////////////////////////////
511 // Implementation of CRC32 algorithm.
512 /////////////////////////////////////////////////////////////////////////////
513 //
514 // This code assumes that an unsigned is at least 32 bits wide and
515 // that the predefined type char occupies one 8-bit byte of storage.
516
517 // The polynomial used is
518 // x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
519 #define CRC32_POLYNOMIAL 0x04c11db7
520 // CRC32C (Castagnoli) polynomial is
521 // x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+x^8+x^6+x^0
522 #define CRC32C_POLYNOMIAL 0x1edc6f41
523
524 // CRC32 is linear meaning that for any texts t1 & t2:
525 // CRC32[t1 XOR t2] = CRC32[t1] XOR CRC32[t2].
526 // This allows to speed up calculation of CRC32 tables by first
527 // calculating CRC32 for bytes with only one bit set,
528 // and then xoring all CRC32 of lowest bit and CRC32 of remaining bits
529 // to get CRC32 of whole number.
530 // First part is done by calling s_CalcByteCRC32Forward or
531 // s_CalcByteCRC32Reverse for each bit.
532 // Second pass is universal for any CRC32 and is performed by function
533 // s_FillMultiBitsCRC().
534
535
536 static inline
s_CalcByteCRC32Forward(size_t byte,Uint4 polynomial)537 Uint4 s_CalcByteCRC32Forward(size_t byte, Uint4 polynomial)
538 {
539 Uint4 byteCRC = byte << 24;
540 for ( int j = 0; j < 8; ++j ) {
541 if ( byteCRC & 0x80000000U )
542 byteCRC = (byteCRC << 1) ^ polynomial;
543 else
544 byteCRC = (byteCRC << 1);
545 }
546 return byteCRC;
547 }
548
549
550 static inline
s_CalcByteCRC32Reverse(size_t byte,Uint4 reversed_polynomial)551 Uint4 s_CalcByteCRC32Reverse(size_t byte, Uint4 reversed_polynomial)
552 {
553 Uint4 byteCRC = byte;
554 for ( int j = 0; j < 8; ++j ) {
555 if ( byteCRC & 1 )
556 byteCRC = (byteCRC >> 1) ^ reversed_polynomial;
557 else
558 byteCRC = (byteCRC >> 1);
559 }
560 return byteCRC;
561 }
562
563
564 static inline
s_FillMultiBitsCRC(Uint4 * table,size_t size)565 void s_FillMultiBitsCRC(Uint4* table, size_t size)
566 {
567 // Preconditions:
568 // Entries at one-bit indexes (1<<k), are calculated.
569 for ( size_t i = 1; i < size; ++i ) { // order is significant
570 // Split bits of i into two parts:
571 // lobit contains lowest bit set, or zero if no bits are set,
572 // hibits contains all other bits.
573 size_t hibits = i & (i-1);
574 size_t lobit = i & ~(i-1);
575 // Because of:
576 // 1. i = lobit ^ hibits
577 // 2. lobit <= i
578 // 3. hibits <= i
579 // we can calculate entry at i by xoring entries at lobit and hibits
580 // There are 3 possible cases:
581 // A. i = 0
582 // In this case lobit = 0 and hibits = 0.
583 // As a result table[0] will become 0, which is correct for CRC.
584 // B. i = 1<<k
585 // In this case lobit = i, and hibits = 0.
586 // table[i] will become table[i] ^ table[0].
587 // Because table[0] is 0 (see case A above),
588 // table[i] will not change and will preserve precalculated value
589 // (see Preconditions above).
590 // C. all other i
591 // In this case lobit < i, and hibits < i
592 // It means the entries at lobit and hibits are calculated already
593 // because of the order of iteration by i.
594 table[i] = table[lobit] ^ table[hibits];
595 }
596 }
597
598
599 template<size_t kCRC32Tables>
600 static inline
s_InitTableCRC32Forward(TCRC32Table (& table)[kCRC32Tables],Uint4 polynomial)601 void s_InitTableCRC32Forward(TCRC32Table (&table)[kCRC32Tables],
602 Uint4 polynomial)
603 {
604 // check the last element to make sure we minimize chances of races
605 // in MT programs.
606 if ( table[kCRC32Tables-1][kCRC32Size-1] ) {
607 return;
608 }
609 // Initialize CRC32 for bytes with only one bit set
610 for ( size_t i = 1; i < kCRC32Size; i <<= 1 ) {
611 table[0][i] = s_CalcByteCRC32Forward(i, polynomial);
612 }
613 // Fill the rest of the main table
614 s_FillMultiBitsCRC(table[0], kCRC32Size);
615 // Fill secondary tables
616 for ( size_t k = 1; k < kCRC32Tables; ++k ) {
617 for ( size_t i = 0; i < kCRC32Size; ++i ) {
618 Uint4 checksum = table[k-1][i];
619 checksum = (checksum << 8) ^ table[0][checksum >> 24];
620 table[k][i] = checksum;
621 }
622 }
623 }
624
625
626 template<size_t kCRC32Tables>
627 static inline
s_InitTableCRC32Reverse(TCRC32Table (& table)[kCRC32Tables],Uint4 polynomial)628 void s_InitTableCRC32Reverse(TCRC32Table (&table)[kCRC32Tables],
629 Uint4 polynomial)
630 {
631 Uint4 reversed_polynomial = 0;
632 for ( size_t i = 0; i < 32; ++i ) {
633 reversed_polynomial = (reversed_polynomial << 1)|(polynomial & 1);
634 polynomial >>= 1;
635 }
636 // check the last element to make sure we minimize chances of races
637 // in MT programs.
638 if ( table[kCRC32Tables-1][kCRC32Size-1] ) {
639 return;
640 }
641 // Initialize CRC32 for bytes with only one bit set
642 for ( size_t i = 1; i < kCRC32Size; i <<= 1 ) {
643 table[0][i] = s_CalcByteCRC32Reverse(i, reversed_polynomial);
644 }
645 // Fill the rest of the table
646 s_FillMultiBitsCRC(table[0], kCRC32Size);
647 // Fill secondary tables
648 for ( size_t k = 1; k < kCRC32Tables; ++k ) {
649 for ( size_t i = 0; i < kCRC32Size; ++i ) {
650 Uint4 checksum = table[k-1][i];
651 checksum = (checksum >> 8) ^ table[0][checksum & 0xff];
652 table[k][i] = checksum;
653 }
654 }
655 }
656
657
s_InitTableCRC32Forward(void)658 void s_InitTableCRC32Forward(void)
659 {
660 s_InitTableCRC32Forward(s_CRC32TableForward, CRC32_POLYNOMIAL);
661 }
662
663
s_InitTableCRC32Reverse(void)664 void s_InitTableCRC32Reverse(void)
665 {
666 s_InitTableCRC32Reverse(s_CRC32TableReverse, CRC32_POLYNOMIAL);
667 }
668
669
s_InitTableCRC32CReverse(void)670 void s_InitTableCRC32CReverse(void)
671 {
672 s_InitTableCRC32Reverse(s_CRC32CTableReverse, CRC32C_POLYNOMIAL);
673 }
674
675
676 #endif //NCBI_USE_PRECOMPILED_CRC32_TABLES
677
678
679 #define s_UpdateCRC32Forward_1(crc, str, table) \
680 do { \
681 Uint4 v = *(const Uint1*)(str) ^ ((crc) >> 24); \
682 (crc) = ((crc) << 8) ^ (table)[0][v]; \
683 } while(0)
684
685 #define s_UpdateCRC32Forward_2(crc, str, table) \
686 do { \
687 Uint4 v = *(const Uint2*)(str); \
688 /* index bytes are in wrong order */ \
689 (crc) = ((crc) << 16) ^ \
690 (table)[0][(((crc)>>16)^(v>>8)) & 0xff] ^ \
691 (table)[1][(((crc)>>24)^(v )) & 0xff]; \
692 } while(0)
693
694 #define s_UpdateCRC32Forward_4(crc, str, table) \
695 do { \
696 Uint4 v = *(const Uint4*)(str); \
697 /* index bytes are in wrong order */ \
698 (crc) = \
699 (table)[0][(((crc) )^(v>>24)) & 0xff] ^ \
700 (table)[1][(((crc)>> 8)^(v>>16)) & 0xff] ^ \
701 (table)[2][(((crc)>>16)^(v>> 8)) & 0xff] ^ \
702 (table)[3][(((crc)>>24)^(v )) & 0xff]; \
703 } while(0)
704
705 #define s_UpdateCRC32Forward_8(crc, str, table) \
706 do { \
707 Uint4 v0 = ((const Uint4*)(str))[0]; \
708 Uint4 v1 = ((const Uint4*)(str))[1]; \
709 /* index bytes are in wrong order */ \
710 (crc) = \
711 (table)[0][( (v1>>24)) ] ^ \
712 (table)[1][( (v1>>16)) & 0xff] ^ \
713 (table)[2][( (v1>> 8)) & 0xff] ^ \
714 (table)[3][( (v1 )) & 0xff] ^ \
715 (table)[4][(((crc) )^(v0>>24)) & 0xff] ^ \
716 (table)[5][(((crc)>> 8)^(v0>>16)) & 0xff] ^ \
717 (table)[6][(((crc)>>16)^(v0>> 8)) & 0xff] ^ \
718 (table)[7][(((crc)>>24)^(v0 )) & 0xff]; \
719 } while(0)
720
721
722 #define s_UpdateCRC32Reverse_1(crc, str, table) \
723 do { \
724 Uint4 v = *(const Uint1*)(str); \
725 v ^= (crc); \
726 (crc) = ((crc) >> 8) ^ \
727 (table)[0][v & 0xff]; \
728 } while(0)
729
730 #define s_UpdateCRC32Reverse_2(crc, str, table) \
731 do { \
732 Uint4 v = *(const Uint2*)(str); \
733 v ^= (crc); \
734 (crc) = ((crc) >> 16) ^ \
735 (table)[1][(v ) & 0xff] ^ \
736 (table)[0][(v>>8) & 0xff]; \
737 } while(0)
738
739 #define s_UpdateCRC32Reverse_4(crc, str, table) \
740 do { \
741 Uint4 v = *(const Uint4*)(str); \
742 v ^= (crc); \
743 (crc) = \
744 (table)[3][(v ) & 0xff] ^ \
745 (table)[2][(v>> 8) & 0xff] ^ \
746 (table)[1][(v>>16) & 0xff] ^ \
747 (table)[0][(v>>24) ]; \
748 } while(0)
749
750 #define s_UpdateCRC32Reverse_8(crc, str, table) \
751 do { \
752 Uint4 v0 = ((const Uint4*)(str))[0]; \
753 Uint4 v1 = ((const Uint4*)(str))[1]; \
754 v0 ^= (crc); \
755 (crc) = \
756 (table)[7][(v0 ) & 0xff] ^ \
757 (table)[6][(v0>> 8) & 0xff] ^ \
758 (table)[5][(v0>>16) & 0xff] ^ \
759 (table)[4][(v0>>24) ] ^ \
760 (table)[3][(v1 ) & 0xff] ^ \
761 (table)[2][(v1>> 8) & 0xff] ^ \
762 (table)[1][(v1>>16) & 0xff] ^ \
763 (table)[0][(v1>>24) ]; \
764 } while(0)
765
766
767 template<size_t kCRC32Tables>
768 static inline
s_UpdateCRC32Forward(Uint4 checksum,const char * str,size_t count,const TCRC32Table (& table)[kCRC32Tables])769 Uint4 s_UpdateCRC32Forward(Uint4 checksum, const char *str, size_t count,
770 const TCRC32Table (&table)[kCRC32Tables])
771 {
772 #if TABLES_COUNT >= 2
773 if ( (uintptr_t(str)&1) && count >= 1 ) {
774 s_UpdateCRC32Forward_1(checksum, str, table);
775 count -= 1;
776 str += 1;
777 }
778 # if TABLES_COUNT >= 4
779 if ( (uintptr_t(str)&2) && count >= 2 ) {
780 s_UpdateCRC32Forward_2(checksum, str, table);
781 count -= 2;
782 str += 2;
783 }
784 # if TABLES_COUNT >= 8
785 while ( count >= 8 ) {
786 s_UpdateCRC32Forward_8(checksum, str, table);
787 count -= 8;
788 str += 8;
789 }
790 if ( count >= 4 ) {
791 s_UpdateCRC32Forward_4(checksum, str, table);
792 count -= 4;
793 str += 4;
794 }
795 # else // < 8
796 while ( count >= 4 ) {
797 s_UpdateCRC32Forward_4(checksum, str, table);
798 count -= 4;
799 str += 4;
800 }
801 # endif // done 4
802 if ( count >= 2 ) {
803 s_UpdateCRC32Forward_2(checksum, str, table);
804 count -= 2;
805 str += 2;
806 }
807 # else // < 4
808 while ( count >= 2 ) {
809 s_UpdateCRC32Forward_2(checksum, str, table);
810 count -= 2;
811 str += 2;
812 }
813 # endif // done 2
814 if ( count ) {
815 s_UpdateCRC32Forward_1(checksum, str, table);
816 }
817 #else // < 2
818 while ( count ) {
819 s_UpdateCRC32Forward_1(checksum, str, table);
820 count -= 1;
821 str += 1;
822 }
823 #endif // done 1
824 return checksum;
825 }
826
827
828 template<size_t kCRC32Tables>
829 static inline
s_UpdateCRC32Reverse(Uint4 checksum,const char * str,size_t count,const TCRC32Table (& table)[kCRC32Tables])830 Uint4 s_UpdateCRC32Reverse(Uint4 checksum, const char *str, size_t count,
831 const TCRC32Table (&table)[kCRC32Tables])
832 {
833 #if TABLES_COUNT >= 2
834 if ( (uintptr_t(str)&1) && count >= 1 ) {
835 s_UpdateCRC32Reverse_1(checksum, str, table);
836 count -= 1;
837 str += 1;
838 }
839 # if TABLES_COUNT >= 4
840 if ( (uintptr_t(str)&2) && count >= 2 ) {
841 s_UpdateCRC32Reverse_2(checksum, str, table);
842 count -= 2;
843 str += 2;
844 }
845 # if TABLES_COUNT >= 8
846 while ( count >= 8 ) {
847 s_UpdateCRC32Reverse_8(checksum, str, table);
848 count -= 8;
849 str += 8;
850 }
851 if ( count >= 4 ) {
852 s_UpdateCRC32Reverse_4(checksum, str, table);
853 count -= 4;
854 str += 4;
855 }
856 # else // < 8
857 while ( count >= 4 ) {
858 s_UpdateCRC32Reverse_4(checksum, str, table);
859 count -= 4;
860 str += 4;
861 }
862 # endif // done 4
863 if ( count >= 2 ) {
864 s_UpdateCRC32Reverse_2(checksum, str, table);
865 count -= 2;
866 str += 2;
867 }
868 # else // < 4
869 while ( count >= 2 ) {
870 s_UpdateCRC32Reverse_2(checksum, str, table);
871 count -= 2;
872 str += 2;
873 }
874 # endif // done 2
875 if ( count ) {
876 s_UpdateCRC32Reverse_1(checksum, str, table);
877 }
878 #else // < 2
879 while ( count ) {
880 s_UpdateCRC32Reverse_1(checksum, str, table);
881 count -= 1;
882 str += 1;
883 }
884 #endif // done 1
885 return checksum;
886 }
887
888
889 #ifdef USE_CRC32C_INTEL
890
891 #if !defined(NCBI_COMPILER_MSVC) && !defined(bit_SSE4_2)
892 // our Darwin GCC doesn't have cpuid.h :(
893 // we have to reimplement cpuid functionality, luckily it's not too big
894 static inline
call_cpuid(unsigned level,unsigned * a,unsigned * b,unsigned * c,unsigned * d)895 void call_cpuid(unsigned level,
896 unsigned* a, unsigned* b, unsigned* c, unsigned* d)
897 {
898 #if defined(__i386__) && defined(__PIC__)
899 // ebx may be the PIC register and some old GCC versions fail to take care
900 __asm__("xchgl %%ebx, %k1;"
901 "cpuid;"
902 "xchgl %%ebx, %k1;"
903 : "=a" (*a), "=&r" (*b), "=c" (*c), "=d" (*d)
904 : "0" (level));
905 #elif defined(__x86_64__) && defined(__PIC__)
906 // rbx may be the PIC register and some old GCC versions fail to take care
907 __asm__("xchgq %%rbx, %q1;"
908 "cpuid;"
909 "xchgq %%rbx, %q1;"
910 : "=a" (*a), "=&r" (*b), "=c" (*c), "=d" (*d)
911 : "0" (level));
912 #else
913 __asm__("cpuid"
914 : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
915 : "0" (level));
916 #endif
917 }
918 static inline
get_cpuid_max(unsigned extended)919 unsigned get_cpuid_max(unsigned extended)
920 {
921 unsigned a, b, c, d;
922 #ifdef __i386__
923 // on 32-bit processors we test special flag to check CPUID support
924 const unsigned HAS_CPUID_FLAG = 0x00200000;
925 __asm__(
926 "pushfl;"
927 "pushfl;"
928 "popl %0;"
929 "movl %0, %1;"
930 "xorl %2, %0;"
931 "pushl %0;"
932 "popfl;"
933 "pushfl;"
934 "popl %0;"
935 "popfl;"
936 : "=&r" (a), "=&r" (b)
937 : "i" (HAS_CPUID_FLAG));
938 if ( !((a ^ b) & HAS_CPUID_FLAG) )
939 return 0;
940 #endif
941 call_cpuid(extended, &a, &b, &c, &d);
942 return a;
943 }
944 static inline
get_cpuid(unsigned level,unsigned * a,unsigned * b,unsigned * c,unsigned * d)945 bool get_cpuid(unsigned level,
946 unsigned *a, unsigned *b, unsigned *c, unsigned *d)
947 {
948 if ( get_cpuid_max(level & 0x80000000U) < level) {
949 return false;
950 }
951 call_cpuid (level, a, b, c, d);
952 return true;
953 }
954 # define __get_cpuid get_cpuid
955 # define bit_SSE4_2 (1<<20)
956 #endif
957
s_IsCRC32CIntelEnabled(void)958 bool s_IsCRC32CIntelEnabled(void)
959 {
960 static volatile bool enabled, initialized;
961 if ( !initialized ) {
962 #ifdef NCBI_COMPILER_MSVC
963 int a[4];
964 __cpuid(a, 0);
965 if ( a[0] >= 1 ) {
966 __cpuid(a, 1);
967 enabled = (a[2] & (1<<20)) != 0;
968 }
969 #else
970 unsigned a, b, c, d;
971 enabled = __get_cpuid(1, &a, &b, &c, &d) && (c & bit_SSE4_2);
972 #endif
973 initialized = true;
974 }
975 return enabled;
976 }
977
978 static inline
s_CRC32C(Uint4 checksum,const char * data)979 Uint4 s_CRC32C(Uint4 checksum, const char* data)
980 {
981 #ifdef NCBI_COMPILER_MSVC
982 return _mm_crc32_u8(checksum, *data);
983 #else
984 // We cannot rely on _mm_crc32_u8() as it's available only when
985 // -msse4_2 compiler option is specified.
986 __asm__("crc32b %1, %0"
987 : "+r" (checksum)
988 : "m" (*data));
989 return checksum;
990 #endif
991 }
992
993 static inline
s_CRC32C(Uint4 checksum,const Uint2 * data)994 Uint4 s_CRC32C(Uint4 checksum, const Uint2* data)
995 {
996 #ifdef NCBI_COMPILER_MSVC
997 return _mm_crc32_u16(checksum, *data);
998 #else
999 // We cannot rely on _mm_crc32_u16() as it's available only when
1000 // -msse4_2 compiler option is specified.
1001 __asm__("crc32w %1, %0"
1002 : "+r" (checksum)
1003 : "m" (*data));
1004 return checksum;
1005 #endif
1006 }
1007
1008 static inline
s_CRC32C(Uint4 checksum,const Uint4 * data)1009 Uint4 s_CRC32C(Uint4 checksum, const Uint4* data)
1010 {
1011 #ifdef NCBI_COMPILER_MSVC
1012 return _mm_crc32_u32(checksum, *data);
1013 #else
1014 // We cannot rely on _mm_crc32_u32() as it's available only when
1015 // -msse4_2 compiler option is specified.
1016 __asm__("crc32l %1, %0"
1017 : "+r" (checksum)
1018 : "m" (*data));
1019 return checksum;
1020 #endif
1021 }
1022
1023 #ifdef HAVE_CRC32C_64
1024 static inline
s_CRC32C(Uint8 checksum,const Uint8 * data)1025 Uint8 s_CRC32C(Uint8 checksum, const Uint8* data)
1026 {
1027 #ifdef NCBI_COMPILER_MSVC
1028 return _mm_crc32_u64(checksum, *data);
1029 #else
1030 // We cannot rely on _mm_crc32_u64() as it's available only when
1031 // -msse4_2 compiler option is specified.
1032 __asm__("crc32q %1, %0"
1033 : "+r" (checksum)
1034 : "m" (*data));
1035 #endif
1036 return checksum;
1037 }
1038 #endif // HAVE_CRC32C_64
1039
1040 static inline
s_UpdateCRC32CIntel(Uint4 checksum,const char * str,size_t count)1041 Uint4 s_UpdateCRC32CIntel(Uint4 checksum, const char *str, size_t count)
1042 {
1043 // Newer Intel CPUs with SSE 4.2 have instructions for CRC32C polynomial.
1044 // Since byte order is little-endian on Intel there is no need to bswap.
1045
1046 // Align buffer
1047 if ( (uintptr_t(str)&1) && count >= 1 ) {
1048 checksum = s_CRC32C(checksum, str);
1049 count -= 1;
1050 str += 1;
1051 }
1052 if ( (uintptr_t(str)&2) && count >= 2 ) {
1053 checksum = s_CRC32C(checksum, (const Uint2*)str);
1054 count -= 2;
1055 str += 2;
1056 }
1057 #ifdef HAVE_CRC32C_64
1058 // Main loop processes by 8 bytes
1059 if ( count >= 4 ) {
1060 if ( (uintptr_t(str)&4) ) {
1061 checksum = s_CRC32C(checksum, (const Uint4*)str);
1062 count -= 4;
1063 str += 4;
1064 }
1065 Uint8 crc = checksum;
1066 while ( count >= 8 ) {
1067 crc = s_CRC32C(crc, (const Uint8*)str);
1068 count -= 8;
1069 str += 8;
1070 }
1071 checksum = Uint4(crc);
1072 if ( count >= 4 ) {
1073 checksum = s_CRC32C(checksum, (const Uint4*)str);
1074 count -= 4;
1075 str += 4;
1076 }
1077 }
1078 #else
1079 // Main loop processes by 4 bytes
1080 while ( count >= 4 ) {
1081 checksum = s_CRC32C(checksum, (const Uint4*)str);
1082 count -= 4;
1083 str += 4;
1084 }
1085 #endif
1086 // Process remainder smaller than 8 bytes
1087 if ( count >= 2 ) {
1088 checksum = s_CRC32C(checksum, (const Uint2*)str);
1089 count -= 2;
1090 str += 2;
1091 }
1092 if ( count >= 1 ) {
1093 checksum = s_CRC32C(checksum, str);
1094 //last count and str updates aren't necessary
1095 //count -= 1;
1096 //str += 1;
1097 }
1098 return checksum;
1099 }
1100
1101 #endif //USE_CRC32C_INTEL
1102
1103
1104 static inline
s_UpdateAdler32(Uint4 sum,const char * data,size_t len)1105 Uint4 s_UpdateAdler32(Uint4 sum, const char* data, size_t len)
1106 {
1107 const Uint4 MOD_ADLER = 65521;
1108
1109 #define ADJUST_ADLER(a) a = (a & 0xffff) + (a >> 16) * (0x10000-MOD_ADLER)
1110 #define FINALIZE_ADLER(a) if (a >= MOD_ADLER) a -= MOD_ADLER
1111
1112 Uint4 a = sum & 0xffff, b = sum >> 16;
1113
1114 const size_t kMaxLen = 5548u;
1115 while (len) {
1116 if ( len >= kMaxLen ) {
1117 len -= kMaxLen;
1118 for ( size_t i = 0; i < kMaxLen/4; ++i ) {
1119 b += a += Uint1(data[0]);
1120 b += a += Uint1(data[1]);
1121 b += a += Uint1(data[2]);
1122 b += a += Uint1(data[3]);
1123 data += 4;
1124 }
1125 } else {
1126 for ( size_t i = len >> 2; i; --i ) {
1127 b += a += Uint1(data[0]);
1128 b += a += Uint1(data[1]);
1129 b += a += Uint1(data[2]);
1130 b += a += Uint1(data[3]);
1131 data += 4;
1132 }
1133 for ( len &= 3; len; --len ) {
1134 b += a += Uint1(data[0]);
1135 data += 1;
1136 }
1137 }
1138 ADJUST_ADLER(a);
1139 ADJUST_ADLER(b);
1140 }
1141 // It can be shown that a <= 0x1013a here, so a single subtract will do.
1142 FINALIZE_ADLER(a);
1143 // It can be shown that b can reach 0xffef1 here.
1144 ADJUST_ADLER(b);
1145 FINALIZE_ADLER(b);
1146 return (b << 16) | a;
1147 }
1148
1149
PrintTables(CNcbiOstream & out)1150 void CChecksumBase::PrintTables(CNcbiOstream& out)
1151 {
1152 InitTables();
1153 s_PrintTable(out, "s_CRC32TableForward", s_CRC32TableForward);
1154 s_PrintTable(out, "s_CRC32TableReverse", s_CRC32TableReverse);
1155 s_PrintTable(out, "s_CRC32CTableReverse", s_CRC32CTableReverse);
1156 }
1157
1158
x_Update(const char * str,size_t count)1159 void CChecksumBase::x_Update(const char* str, size_t count)
1160 {
1161 switch ( m_Method ) {
1162 case eCRC32:
1163 case eCRC32CKSUM:
1164 m_Value.v32 = s_UpdateCRC32Forward(m_Value.v32, str, count, s_CRC32TableForward);
1165 break;
1166 case eCRC32ZIP:
1167 case eCRC32INSD:
1168 m_Value.v32 = s_UpdateCRC32Reverse(m_Value.v32, str, count, s_CRC32TableReverse);
1169 break;
1170 case eCRC32C:
1171 #ifdef USE_CRC32C_INTEL
1172 if ( s_IsCRC32CIntelEnabled() ) {
1173 m_Value.v32 = s_UpdateCRC32CIntel(m_Value.v32, str, count);
1174 break;
1175 }
1176 #endif
1177 m_Value.v32 = s_UpdateCRC32Reverse(m_Value.v32, str, count, s_CRC32CTableReverse);
1178 break;
1179 case eAdler32:
1180 m_Value.v32 = s_UpdateAdler32(m_Value.v32, str, count);
1181 break;
1182 case eMD5:
1183 m_Value.md5->Update(str, count);
1184 break;
1185 case eCityHash32:
1186 _ASSERT(!m_CharCount);
1187 m_Value.v32 = CityHash32(str, count);
1188 break;
1189 case eCityHash64:
1190 _ASSERT(!m_CharCount);
1191 m_Value.v64 = CityHash64(str, count);
1192 break;
1193 case eFarmHash32:
1194 _ASSERT(!m_CharCount);
1195 m_Value.v32 = farmhash::Hash32(str, count);
1196 break;
1197 case eFarmHash64:
1198 _ASSERT(!m_CharCount);
1199 m_Value.v64 = farmhash::Hash64(str, count);
1200 break;
1201 case eMurmurHash2_32:
1202 {{
1203 _ASSERT(!m_CharCount);
1204 int n = count > kMax_Int ? kMax_Int : (int)count;
1205 m_Value.v32 = MurmurHash2(str, n, (uint32_t)m_Seed);
1206 }}
1207 break;
1208 case eMurmurHash2_64:
1209 {{
1210 _ASSERT(!m_CharCount);
1211 int n = count > kMax_Int ? kMax_Int : (int)count;
1212 m_Value.v64 = MurmurHash64A(str, n, m_Seed);
1213 }}
1214 break;
1215 case eMurmurHash3_32:
1216 {{
1217 _ASSERT(!m_CharCount);
1218 int n = count > kMax_Int ? kMax_Int : (int)count;
1219 MurmurHash3_x86_32(str, n, (uint32_t)m_Seed, &m_Value.v32);
1220 }}
1221 break;
1222 default:
1223 _ASSERT(0);
1224 break;
1225 }
1226 }
1227
1228
1229 //////////////////////////////////////////////////////////////////////////////
1230 //
1231 // NHash
1232 //
1233
CityHash32(const CTempString str)1234 Uint4 NHash::CityHash32(const CTempString str)
1235 {
1236 return ::CityHash32(str.data(), str.length());
1237 }
1238
CityHash32(const char * str,size_t len)1239 Uint4 NHash::CityHash32(const char* str, size_t len)
1240 {
1241 return ::CityHash32(str, len);
1242 }
1243
CityHash64(const CTempString str)1244 Uint8 NHash::CityHash64(const CTempString str)
1245 {
1246 return ::CityHash64(str.data(), str.length());
1247 }
1248
CityHash64(const char * str,size_t len)1249 Uint8 NHash::CityHash64(const char* str, size_t len)
1250 {
1251 return ::CityHash64(str, len);
1252 }
1253
FarmHash32(const CTempString str)1254 Uint4 NHash::FarmHash32(const CTempString str)
1255 {
1256 return farmhash::Hash32(str.data(), str.length());
1257
1258 }
1259
FarmHash32(const char * str,size_t len)1260 Uint4 NHash::FarmHash32(const char* str, size_t len)
1261 {
1262 return farmhash::Hash32(str, len);
1263 }
1264
FarmHash64(const CTempString str)1265 Uint8 NHash::FarmHash64(const CTempString str)
1266 {
1267 return farmhash::Hash64(str.data(), str.length());
1268 }
1269
FarmHash64(const char * str,size_t len)1270 Uint8 NHash::FarmHash64(const char* str, size_t len)
1271 {
1272 return farmhash::Hash64(str, len);
1273 }
1274
MurmurHash2(const CTempString str,Uint4 seed)1275 Uint4 NHash::MurmurHash2(const CTempString str, Uint4 seed)
1276 {
1277 _ASSERT(str.length() <= kMax_Int);
1278 return ::MurmurHash2(str.data(), (int)str.length(), seed);
1279 }
1280
MurmurHash2(const char * str,size_t len,Uint4 seed)1281 Uint4 NHash::MurmurHash2(const char* str, size_t len, Uint4 seed)
1282 {
1283 _ASSERT(len <= kMax_Int);
1284 return ::MurmurHash2(str, (int)len, seed);
1285 }
1286
MurmurHash64A(const CTempString str,Uint8 seed)1287 Uint8 NHash::MurmurHash64A(const CTempString str, Uint8 seed)
1288 {
1289 _ASSERT(str.length() <= kMax_Int);
1290 return ::MurmurHash64A(str.data(), (int)str.length(), seed);
1291 }
1292
MurmurHash64A(const char * str,size_t len,Uint8 seed)1293 Uint8 NHash::MurmurHash64A(const char* str, size_t len, Uint8 seed)
1294 {
1295 _ASSERT(len <= kMax_Int);
1296 return ::MurmurHash64A(str, (int)len, seed);
1297 }
1298
MurmurHash3_x86_32(const CTempString str,Uint4 seed)1299 Uint4 NHash::MurmurHash3_x86_32(const CTempString str, Uint4 seed)
1300 {
1301 _ASSERT(str.length() <= kMax_Int);
1302 Uint4 result;
1303 ::MurmurHash3_x86_32(str.data(), (int)str.length(), seed, &result);
1304 return result;
1305 }
1306
MurmurHash3_x86_32(const char * str,size_t len,Uint4 seed)1307 Uint4 NHash::MurmurHash3_x86_32(const char* str, size_t len, Uint4 seed)
1308 {
1309 _ASSERT(len <= kMax_Int);
1310 Uint4 result;
1311 ::MurmurHash3_x86_32(str, (int)len, seed, &result);
1312 return result;
1313 }
1314
1315
1316
1317 //////////////////////////////////////////////////////////////////////////////
1318 //
1319 // CChecksumException
1320 //
1321
GetErrCodeString(void) const1322 const char* CChecksumException::GetErrCodeString(void) const
1323 {
1324 switch (GetErrCode()) {
1325 case eStreamIO: return "eStreamError";
1326 case eFileIO: return "eFileError";
1327 default: return CException::GetErrCodeString();
1328 }
1329 }
1330
1331
1332 /////////////////////////////////////////////////////////////////////////////
1333 //
1334 // CChecksumStreamWriter
1335 //
1336
CChecksumStreamWriter(CChecksum::EMethod method)1337 CChecksumStreamWriter::CChecksumStreamWriter(CChecksum::EMethod method)
1338 : m_Checksum(method)
1339 {
1340 }
1341
1342
~CChecksumStreamWriter(void)1343 CChecksumStreamWriter::~CChecksumStreamWriter(void)
1344 {
1345 }
1346
1347
Write(const void * buf,size_t count,size_t * bytes_written)1348 ERW_Result CChecksumStreamWriter::Write(const void* buf, size_t count,
1349 size_t* bytes_written)
1350 {
1351 m_Checksum.AddChars((const char*)buf, count);
1352 if (bytes_written) {
1353 *bytes_written = count;
1354 }
1355 return eRW_Success;
1356 }
1357
1358
Flush(void)1359 ERW_Result CChecksumStreamWriter::Flush(void)
1360 {
1361 return eRW_Success;
1362 }
1363
1364
1365 END_NCBI_SCOPE
1366