├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── pymmh3.py └── test ├── MurmurHash3.h ├── MurmurHash3.inc ├── pg1260.txt ├── pymmh3_test.py ├── solution_hash128_x64_seed0.txt ├── solution_hash128_x64_seed1234ABCD.txt ├── solution_hash128_x86_seed0.txt ├── solution_hash128_x86_seed1234ABCD.txt ├── solution_hash32_seed0.txt ├── solution_hash32_seed1234ABCD.txt └── unitest_solution_gen.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.5" 5 | - "3.6" 6 | - "3.7" 7 | - "3.8" 8 | - "nightly" 9 | # command to run tests 10 | script: python test/pymmh3_test.py 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | pymmh3 was written by Fredrik Kihlander and enhanced by Swapnil Gusani, and is placed in the public 2 | domain. The authors hereby disclaim copyright to this source code. 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PYMMH3 - a pure python MurmurHash3 implementation. 2 | 3 | [![Build Status](https://travis-ci.org/wc-duck/pymmh3.svg?branch=master)](https://travis-ci.org/wc-duck/pymmh3) 4 | 5 | ## About: 6 | This is a pure python implementation of the murmur3 hash algorithm 7 | written for the times when you do not want to muck about building and installing c-modules etc. 8 | 9 | As this is pure python performance is FAR from optimal in CPython and if that is required a real c-module such as the 10 | one found here at is absolutely suggested! 11 | 12 | However this module performs extremely well in case of pypy(), an alternative JIT version of python. 13 | 14 | ## Performance: 15 | Bad... we need not say more ;) 16 | 17 | But with pypy it is blazing fast compared to mmh3 :D 18 | 19 | ## Testing: 20 | Tested by hashing all lines in Jane Eyre by Charlotte Bronte in both c and with pymmh3. 21 | 22 | ## Usage: 23 | ```python 24 | try: 25 | # try with a fast c-implementation ... 26 | import mmh3 as mmh3 27 | except ImportError: 28 | # ... otherwise fallback to this code! 29 | import pymmh3 as mmh3 30 | 31 | print mmh3.hash( 'my string of doom!', seed = 1234 ) 32 | print mmh3.hash64( 'my string of doom!', seed = 1234 ) 33 | print mmh3.hash128( 'my string of doom!', seed = 1234 ) 34 | print mmh3.hash_bytes( 'my string of doom!', seed = 1234 ) 35 | ``` 36 | 37 | ## License: 38 | Murmur3 hash was originally created by Austin Appleby. 39 | 40 | * http://code.google.com/p/smhasher/ 41 | 42 | pymmh3 was written by Fredrik Kihlander and enhanced by Swapnil Gusani, and is placed in the public 43 | domain. The authors hereby disclaim copyright to this source code. 44 | -------------------------------------------------------------------------------- /pymmh3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | pymmh3 was written by Fredrik Kihlander and enhanced by Swapnil Gusani, and is placed in the public 3 | domain. The authors hereby disclaim copyright to this source code. 4 | 5 | pure python implementation of the murmur3 hash algorithm 6 | 7 | https://code.google.com/p/smhasher/wiki/MurmurHash3 8 | 9 | This was written for the times when you do not want to compile c-code and install modules, 10 | and you only want a drop-in murmur3 implementation. 11 | 12 | As this is purely python it is FAR from performant and if performance is anything that is needed 13 | a proper c-module is suggested! 14 | 15 | This module is written to have the same format as mmh3 python package found here for simple conversions: 16 | 17 | https://pypi.python.org/pypi/mmh3/2.3.1 18 | ''' 19 | 20 | import sys as _sys 21 | if (_sys.version_info > (3, 0)): 22 | def xrange( a, b, c ): 23 | return range( a, b, c ) 24 | def xencode(x): 25 | if isinstance(x, bytes) or isinstance(x, bytearray): 26 | return x 27 | else: 28 | return x.encode() 29 | else: 30 | def xencode(x): 31 | return x 32 | del _sys 33 | 34 | def hash( key, seed = 0x0 ): 35 | ''' Implements 32bit murmur3 hash. ''' 36 | 37 | key = bytearray( xencode(key) ) 38 | 39 | def fmix( h ): 40 | h ^= h >> 16 41 | h = ( h * 0x85ebca6b ) & 0xFFFFFFFF 42 | h ^= h >> 13 43 | h = ( h * 0xc2b2ae35 ) & 0xFFFFFFFF 44 | h ^= h >> 16 45 | return h 46 | 47 | length = len( key ) 48 | nblocks = int( length / 4 ) 49 | 50 | h1 = seed 51 | 52 | c1 = 0xcc9e2d51 53 | c2 = 0x1b873593 54 | 55 | # body 56 | for block_start in xrange( 0, nblocks * 4, 4 ): 57 | # ??? big endian? 58 | k1 = key[ block_start + 3 ] << 24 | \ 59 | key[ block_start + 2 ] << 16 | \ 60 | key[ block_start + 1 ] << 8 | \ 61 | key[ block_start + 0 ] 62 | 63 | k1 = ( c1 * k1 ) & 0xFFFFFFFF 64 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32 65 | k1 = ( c2 * k1 ) & 0xFFFFFFFF 66 | 67 | h1 ^= k1 68 | h1 = ( h1 << 13 | h1 >> 19 ) & 0xFFFFFFFF # inlined ROTL32 69 | h1 = ( h1 * 5 + 0xe6546b64 ) & 0xFFFFFFFF 70 | 71 | # tail 72 | tail_index = nblocks * 4 73 | k1 = 0 74 | tail_size = length & 3 75 | 76 | if tail_size >= 3: 77 | k1 ^= key[ tail_index + 2 ] << 16 78 | if tail_size >= 2: 79 | k1 ^= key[ tail_index + 1 ] << 8 80 | if tail_size >= 1: 81 | k1 ^= key[ tail_index + 0 ] 82 | 83 | if tail_size > 0: 84 | k1 = ( k1 * c1 ) & 0xFFFFFFFF 85 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32 86 | k1 = ( k1 * c2 ) & 0xFFFFFFFF 87 | h1 ^= k1 88 | 89 | #finalization 90 | unsigned_val = fmix( h1 ^ length ) 91 | if unsigned_val & 0x80000000 == 0: 92 | return unsigned_val 93 | else: 94 | return -( (unsigned_val ^ 0xFFFFFFFF) + 1 ) 95 | 96 | 97 | def hash128( key, seed = 0x0, x64arch = True ): 98 | ''' Implements 128bit murmur3 hash. ''' 99 | def hash128_x64( key, seed ): 100 | ''' Implements 128bit murmur3 hash for x64. ''' 101 | 102 | def fmix( k ): 103 | k ^= k >> 33 104 | k = ( k * 0xff51afd7ed558ccd ) & 0xFFFFFFFFFFFFFFFF 105 | k ^= k >> 33 106 | k = ( k * 0xc4ceb9fe1a85ec53 ) & 0xFFFFFFFFFFFFFFFF 107 | k ^= k >> 33 108 | return k 109 | 110 | length = len( key ) 111 | nblocks = int( length / 16 ) 112 | 113 | h1 = seed 114 | h2 = seed 115 | 116 | c1 = 0x87c37b91114253d5 117 | c2 = 0x4cf5ad432745937f 118 | 119 | #body 120 | for block_start in xrange( 0, nblocks * 8, 8 ): 121 | # ??? big endian? 122 | k1 = key[ 2 * block_start + 7 ] << 56 | \ 123 | key[ 2 * block_start + 6 ] << 48 | \ 124 | key[ 2 * block_start + 5 ] << 40 | \ 125 | key[ 2 * block_start + 4 ] << 32 | \ 126 | key[ 2 * block_start + 3 ] << 24 | \ 127 | key[ 2 * block_start + 2 ] << 16 | \ 128 | key[ 2 * block_start + 1 ] << 8 | \ 129 | key[ 2 * block_start + 0 ] 130 | 131 | k2 = key[ 2 * block_start + 15 ] << 56 | \ 132 | key[ 2 * block_start + 14 ] << 48 | \ 133 | key[ 2 * block_start + 13 ] << 40 | \ 134 | key[ 2 * block_start + 12 ] << 32 | \ 135 | key[ 2 * block_start + 11 ] << 24 | \ 136 | key[ 2 * block_start + 10 ] << 16 | \ 137 | key[ 2 * block_start + 9 ] << 8 | \ 138 | key[ 2 * block_start + 8 ] 139 | 140 | k1 = ( c1 * k1 ) & 0xFFFFFFFFFFFFFFFF 141 | k1 = ( k1 << 31 | k1 >> 33 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64 142 | k1 = ( c2 * k1 ) & 0xFFFFFFFFFFFFFFFF 143 | h1 ^= k1 144 | 145 | h1 = ( h1 << 27 | h1 >> 37 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64 146 | h1 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF 147 | h1 = ( h1 * 5 + 0x52dce729 ) & 0xFFFFFFFFFFFFFFFF 148 | 149 | k2 = ( c2 * k2 ) & 0xFFFFFFFFFFFFFFFF 150 | k2 = ( k2 << 33 | k2 >> 31 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64 151 | k2 = ( c1 * k2 ) & 0xFFFFFFFFFFFFFFFF 152 | h2 ^= k2 153 | 154 | h2 = ( h2 << 31 | h2 >> 33 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64 155 | h2 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF 156 | h2 = ( h2 * 5 + 0x38495ab5 ) & 0xFFFFFFFFFFFFFFFF 157 | 158 | #tail 159 | tail_index = nblocks * 16 160 | k1 = 0 161 | k2 = 0 162 | tail_size = length & 15 163 | 164 | if tail_size >= 15: 165 | k2 ^= key[ tail_index + 14 ] << 48 166 | if tail_size >= 14: 167 | k2 ^= key[ tail_index + 13 ] << 40 168 | if tail_size >= 13: 169 | k2 ^= key[ tail_index + 12 ] << 32 170 | if tail_size >= 12: 171 | k2 ^= key[ tail_index + 11 ] << 24 172 | if tail_size >= 11: 173 | k2 ^= key[ tail_index + 10 ] << 16 174 | if tail_size >= 10: 175 | k2 ^= key[ tail_index + 9 ] << 8 176 | if tail_size >= 9: 177 | k2 ^= key[ tail_index + 8 ] 178 | 179 | if tail_size > 8: 180 | k2 = ( k2 * c2 ) & 0xFFFFFFFFFFFFFFFF 181 | k2 = ( k2 << 33 | k2 >> 31 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64 182 | k2 = ( k2 * c1 ) & 0xFFFFFFFFFFFFFFFF 183 | h2 ^= k2 184 | 185 | if tail_size >= 8: 186 | k1 ^= key[ tail_index + 7 ] << 56 187 | if tail_size >= 7: 188 | k1 ^= key[ tail_index + 6 ] << 48 189 | if tail_size >= 6: 190 | k1 ^= key[ tail_index + 5 ] << 40 191 | if tail_size >= 5: 192 | k1 ^= key[ tail_index + 4 ] << 32 193 | if tail_size >= 4: 194 | k1 ^= key[ tail_index + 3 ] << 24 195 | if tail_size >= 3: 196 | k1 ^= key[ tail_index + 2 ] << 16 197 | if tail_size >= 2: 198 | k1 ^= key[ tail_index + 1 ] << 8 199 | if tail_size >= 1: 200 | k1 ^= key[ tail_index + 0 ] 201 | 202 | if tail_size > 0: 203 | k1 = ( k1 * c1 ) & 0xFFFFFFFFFFFFFFFF 204 | k1 = ( k1 << 31 | k1 >> 33 ) & 0xFFFFFFFFFFFFFFFF # inlined ROTL64 205 | k1 = ( k1 * c2 ) & 0xFFFFFFFFFFFFFFFF 206 | h1 ^= k1 207 | 208 | #finalization 209 | h1 ^= length 210 | h2 ^= length 211 | 212 | h1 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF 213 | h2 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF 214 | 215 | h1 = fmix( h1 ) 216 | h2 = fmix( h2 ) 217 | 218 | h1 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF 219 | h2 = ( h1 + h2 ) & 0xFFFFFFFFFFFFFFFF 220 | 221 | return ( h2 << 64 | h1 ) 222 | 223 | def hash128_x86( key, seed ): 224 | ''' Implements 128bit murmur3 hash for x86. ''' 225 | 226 | def fmix( h ): 227 | h ^= h >> 16 228 | h = ( h * 0x85ebca6b ) & 0xFFFFFFFF 229 | h ^= h >> 13 230 | h = ( h * 0xc2b2ae35 ) & 0xFFFFFFFF 231 | h ^= h >> 16 232 | return h 233 | 234 | length = len( key ) 235 | nblocks = int( length / 16 ) 236 | 237 | h1 = seed 238 | h2 = seed 239 | h3 = seed 240 | h4 = seed 241 | 242 | c1 = 0x239b961b 243 | c2 = 0xab0e9789 244 | c3 = 0x38b34ae5 245 | c4 = 0xa1e38b93 246 | 247 | #body 248 | for block_start in xrange( 0, nblocks * 16, 16 ): 249 | k1 = key[ block_start + 3 ] << 24 | \ 250 | key[ block_start + 2 ] << 16 | \ 251 | key[ block_start + 1 ] << 8 | \ 252 | key[ block_start + 0 ] 253 | 254 | k2 = key[ block_start + 7 ] << 24 | \ 255 | key[ block_start + 6 ] << 16 | \ 256 | key[ block_start + 5 ] << 8 | \ 257 | key[ block_start + 4 ] 258 | 259 | k3 = key[ block_start + 11 ] << 24 | \ 260 | key[ block_start + 10 ] << 16 | \ 261 | key[ block_start + 9 ] << 8 | \ 262 | key[ block_start + 8 ] 263 | 264 | k4 = key[ block_start + 15 ] << 24 | \ 265 | key[ block_start + 14 ] << 16 | \ 266 | key[ block_start + 13 ] << 8 | \ 267 | key[ block_start + 12 ] 268 | 269 | k1 = ( c1 * k1 ) & 0xFFFFFFFF 270 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32 271 | k1 = ( c2 * k1 ) & 0xFFFFFFFF 272 | h1 ^= k1 273 | 274 | h1 = ( h1 << 19 | h1 >> 13 ) & 0xFFFFFFFF # inlined ROTL32 275 | h1 = ( h1 + h2 ) & 0xFFFFFFFF 276 | h1 = ( h1 * 5 + 0x561ccd1b ) & 0xFFFFFFFF 277 | 278 | k2 = ( c2 * k2 ) & 0xFFFFFFFF 279 | k2 = ( k2 << 16 | k2 >> 16 ) & 0xFFFFFFFF # inlined ROTL32 280 | k2 = ( c3 * k2 ) & 0xFFFFFFFF 281 | h2 ^= k2 282 | 283 | h2 = ( h2 << 17 | h2 >> 15 ) & 0xFFFFFFFF # inlined ROTL32 284 | h2 = ( h2 + h3 ) & 0xFFFFFFFF 285 | h2 = ( h2 * 5 + 0x0bcaa747 ) & 0xFFFFFFFF 286 | 287 | k3 = ( c3 * k3 ) & 0xFFFFFFFF 288 | k3 = ( k3 << 17 | k3 >> 15 ) & 0xFFFFFFFF # inlined ROTL32 289 | k3 = ( c4 * k3 ) & 0xFFFFFFFF 290 | h3 ^= k3 291 | 292 | h3 = ( h3 << 15 | h3 >> 17 ) & 0xFFFFFFFF # inlined ROTL32 293 | h3 = ( h3 + h4 ) & 0xFFFFFFFF 294 | h3 = ( h3 * 5 + 0x96cd1c35 ) & 0xFFFFFFFF 295 | 296 | k4 = ( c4 * k4 ) & 0xFFFFFFFF 297 | k4 = ( k4 << 18 | k4 >> 14 ) & 0xFFFFFFFF # inlined ROTL32 298 | k4 = ( c1 * k4 ) & 0xFFFFFFFF 299 | h4 ^= k4 300 | 301 | h4 = ( h4 << 13 | h4 >> 19 ) & 0xFFFFFFFF # inlined ROTL32 302 | h4 = ( h1 + h4 ) & 0xFFFFFFFF 303 | h4 = ( h4 * 5 + 0x32ac3b17 ) & 0xFFFFFFFF 304 | 305 | #tail 306 | tail_index = nblocks * 16 307 | k1 = 0 308 | k2 = 0 309 | k3 = 0 310 | k4 = 0 311 | tail_size = length & 15 312 | 313 | if tail_size >= 15: 314 | k4 ^= key[ tail_index + 14 ] << 16 315 | if tail_size >= 14: 316 | k4 ^= key[ tail_index + 13 ] << 8 317 | if tail_size >= 13: 318 | k4 ^= key[ tail_index + 12 ] 319 | 320 | if tail_size > 12: 321 | k4 = ( k4 * c4 ) & 0xFFFFFFFF 322 | k4 = ( k4 << 18 | k4 >> 14 ) & 0xFFFFFFFF # inlined ROTL32 323 | k4 = ( k4 * c1 ) & 0xFFFFFFFF 324 | h4 ^= k4 325 | 326 | if tail_size >= 12: 327 | k3 ^= key[ tail_index + 11 ] << 24 328 | if tail_size >= 11: 329 | k3 ^= key[ tail_index + 10 ] << 16 330 | if tail_size >= 10: 331 | k3 ^= key[ tail_index + 9 ] << 8 332 | if tail_size >= 9: 333 | k3 ^= key[ tail_index + 8 ] 334 | 335 | if tail_size > 8: 336 | k3 = ( k3 * c3 ) & 0xFFFFFFFF 337 | k3 = ( k3 << 17 | k3 >> 15 ) & 0xFFFFFFFF # inlined ROTL32 338 | k3 = ( k3 * c4 ) & 0xFFFFFFFF 339 | h3 ^= k3 340 | 341 | if tail_size >= 8: 342 | k2 ^= key[ tail_index + 7 ] << 24 343 | if tail_size >= 7: 344 | k2 ^= key[ tail_index + 6 ] << 16 345 | if tail_size >= 6: 346 | k2 ^= key[ tail_index + 5 ] << 8 347 | if tail_size >= 5: 348 | k2 ^= key[ tail_index + 4 ] 349 | 350 | if tail_size > 4: 351 | k2 = ( k2 * c2 ) & 0xFFFFFFFF 352 | k2 = ( k2 << 16 | k2 >> 16 ) & 0xFFFFFFFF # inlined ROTL32 353 | k2 = ( k2 * c3 ) & 0xFFFFFFFF 354 | h2 ^= k2 355 | 356 | if tail_size >= 4: 357 | k1 ^= key[ tail_index + 3 ] << 24 358 | if tail_size >= 3: 359 | k1 ^= key[ tail_index + 2 ] << 16 360 | if tail_size >= 2: 361 | k1 ^= key[ tail_index + 1 ] << 8 362 | if tail_size >= 1: 363 | k1 ^= key[ tail_index + 0 ] 364 | 365 | if tail_size > 0: 366 | k1 = ( k1 * c1 ) & 0xFFFFFFFF 367 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32 368 | k1 = ( k1 * c2 ) & 0xFFFFFFFF 369 | h1 ^= k1 370 | 371 | #finalization 372 | h1 ^= length 373 | h2 ^= length 374 | h3 ^= length 375 | h4 ^= length 376 | 377 | h1 = ( h1 + h2 ) & 0xFFFFFFFF 378 | h1 = ( h1 + h3 ) & 0xFFFFFFFF 379 | h1 = ( h1 + h4 ) & 0xFFFFFFFF 380 | h2 = ( h1 + h2 ) & 0xFFFFFFFF 381 | h3 = ( h1 + h3 ) & 0xFFFFFFFF 382 | h4 = ( h1 + h4 ) & 0xFFFFFFFF 383 | 384 | h1 = fmix( h1 ) 385 | h2 = fmix( h2 ) 386 | h3 = fmix( h3 ) 387 | h4 = fmix( h4 ) 388 | 389 | h1 = ( h1 + h2 ) & 0xFFFFFFFF 390 | h1 = ( h1 + h3 ) & 0xFFFFFFFF 391 | h1 = ( h1 + h4 ) & 0xFFFFFFFF 392 | h2 = ( h1 + h2 ) & 0xFFFFFFFF 393 | h3 = ( h1 + h3 ) & 0xFFFFFFFF 394 | h4 = ( h1 + h4 ) & 0xFFFFFFFF 395 | 396 | return ( h4 << 96 | h3 << 64 | h2 << 32 | h1 ) 397 | 398 | key = bytearray( xencode(key) ) 399 | 400 | if x64arch: 401 | return hash128_x64( key, seed ) 402 | else: 403 | return hash128_x86( key, seed ) 404 | 405 | 406 | def hash64( key, seed = 0x0, x64arch = True ): 407 | ''' Implements 64bit murmur3 hash. Returns a tuple. ''' 408 | 409 | hash_128 = hash128( key, seed, x64arch ) 410 | 411 | unsigned_val1 = hash_128 & 0xFFFFFFFFFFFFFFFF 412 | if unsigned_val1 & 0x8000000000000000 == 0: 413 | signed_val1 = unsigned_val1 414 | else: 415 | signed_val1 = -( (unsigned_val1 ^ 0xFFFFFFFFFFFFFFFF) + 1 ) 416 | 417 | unsigned_val2 = ( hash_128 >> 64 ) & 0xFFFFFFFFFFFFFFFF 418 | if unsigned_val2 & 0x8000000000000000 == 0: 419 | signed_val2 = unsigned_val2 420 | else: 421 | signed_val2 = -( (unsigned_val2 ^ 0xFFFFFFFFFFFFFFFF) + 1 ) 422 | 423 | return ( int( signed_val1 ), int( signed_val2 ) ) 424 | 425 | 426 | def hash_bytes( key, seed = 0x0, x64arch = True ): 427 | ''' Implements 128bit murmur3 hash. Returns a byte string. ''' 428 | 429 | hash_128 = hash128( key, seed, x64arch ) 430 | 431 | bytestring = '' 432 | 433 | for i in xrange(0, 16, 1): 434 | lsbyte = hash_128 & 0xFF 435 | bytestring = bytestring + str( chr( lsbyte ) ) 436 | hash_128 = hash_128 >> 8 437 | 438 | return bytestring 439 | 440 | 441 | if __name__ == "__main__": 442 | import argparse 443 | import sys 444 | 445 | parser = argparse.ArgumentParser( 'pymurmur3', 'pymurmur [options] "string to hash"' ) 446 | parser.add_argument( '--seed', type = int, default = 0 ) 447 | parser.add_argument( 'strings', default = [], nargs='+') 448 | 449 | opts = parser.parse_args() 450 | 451 | for str_to_hash in opts.strings: 452 | sys.stdout.write( '"%s" = 0x%08X\n' % ( str_to_hash, hash( str_to_hash ) ) ) 453 | -------------------------------------------------------------------------------- /test/MurmurHash3.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // MurmurHash3 was written by Austin Appleby, and is placed in the public 3 | // domain. The author hereby disclaims copyright to this source code. 4 | 5 | #ifndef _MURMURHASH3_H_ 6 | #define _MURMURHASH3_H_ 7 | 8 | //----------------------------------------------------------------------------- 9 | // Platform-specific functions and macros 10 | 11 | // Microsoft Visual Studio 12 | 13 | #if defined(_MSC_VER) 14 | 15 | #if !defined(_STDINT) 16 | typedef unsigned char uint8_t; 17 | typedef unsigned long uint32_t; 18 | typedef unsigned __int64 uint64_t; 19 | #endif 20 | 21 | // Other compilers 22 | 23 | #else // defined(_MSC_VER) 24 | 25 | #include 26 | 27 | #endif // !defined(_MSC_VER) 28 | 29 | //----------------------------------------------------------------------------- 30 | 31 | void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out ); 32 | 33 | void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out ); 34 | 35 | void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out ); 36 | 37 | //----------------------------------------------------------------------------- 38 | 39 | #endif // _MURMURHASH3_H_ 40 | -------------------------------------------------------------------------------- /test/MurmurHash3.inc: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // MurmurHash3 was written by Austin Appleby, and is placed in the public 3 | // domain. The author hereby disclaims copyright to this source code. 4 | 5 | // Note - The x86 and x64 versions do _not_ produce the same results, as the 6 | // algorithms are optimized for their respective platforms. You can still 7 | // compile and run any of them on any platform, but your performance with the 8 | // non-native version will be less than optimal. 9 | 10 | #include "MurmurHash3.h" 11 | 12 | //----------------------------------------------------------------------------- 13 | // Platform-specific functions and macros 14 | 15 | // Microsoft Visual Studio 16 | 17 | #if defined(_MSC_VER) 18 | 19 | #define FORCE_INLINE __forceinline 20 | 21 | #include 22 | 23 | #define ROTL32(x,y) _rotl(x,y) 24 | #define ROTL64(x,y) _rotl64(x,y) 25 | 26 | #define BIG_CONSTANT(x) (x) 27 | 28 | // Other compilers 29 | 30 | #else // defined(_MSC_VER) 31 | 32 | #if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && GNUC_MINOR >= 4)) 33 | /* gcc version >= 4.4 4.1 = RHEL 5, 4.4 = RHEL 6. Don't inline for RHEL 5 gcc which is 4.1*/ 34 | #define FORCE_INLINE inline __attribute__((always_inline)) 35 | #else 36 | #define FORCE_INLINE 37 | #endif 38 | 39 | inline uint32_t rotl32 ( uint32_t x, int8_t r ) 40 | { 41 | return (x << r) | (x >> (32 - r)); 42 | } 43 | 44 | inline uint64_t rotl64 ( uint64_t x, int8_t r ) 45 | { 46 | return (x << r) | (x >> (64 - r)); 47 | } 48 | 49 | #define ROTL32(x,y) rotl32(x,y) 50 | #define ROTL64(x,y) rotl64(x,y) 51 | 52 | #define BIG_CONSTANT(x) (x##LLU) 53 | 54 | #endif // !defined(_MSC_VER) 55 | 56 | //----------------------------------------------------------------------------- 57 | // Block read - if your platform needs to do endian-swapping or can only 58 | // handle aligned reads, do the conversion here 59 | 60 | FORCE_INLINE uint32_t getblock ( const uint32_t * p, int i ) 61 | { 62 | return p[i]; 63 | } 64 | 65 | FORCE_INLINE uint64_t getblock ( const uint64_t * p, int i ) 66 | { 67 | return p[i]; 68 | } 69 | 70 | //----------------------------------------------------------------------------- 71 | // Finalization mix - force all bits of a hash block to avalanche 72 | 73 | FORCE_INLINE uint32_t fmix ( uint32_t h ) 74 | { 75 | h ^= h >> 16; 76 | h *= 0x85ebca6b; 77 | h ^= h >> 13; 78 | h *= 0xc2b2ae35; 79 | h ^= h >> 16; 80 | 81 | return h; 82 | } 83 | 84 | //---------- 85 | 86 | FORCE_INLINE uint64_t fmix ( uint64_t k ) 87 | { 88 | k ^= k >> 33; 89 | k *= BIG_CONSTANT(0xff51afd7ed558ccd); 90 | k ^= k >> 33; 91 | k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); 92 | k ^= k >> 33; 93 | 94 | return k; 95 | } 96 | 97 | //----------------------------------------------------------------------------- 98 | 99 | void MurmurHash3_x86_32 ( const void * key, int len, 100 | uint32_t seed, void * out ) 101 | { 102 | const uint8_t * data = (const uint8_t*)key; 103 | const int nblocks = len / 4; 104 | 105 | uint32_t h1 = seed; 106 | 107 | const uint32_t c1 = 0xcc9e2d51; 108 | const uint32_t c2 = 0x1b873593; 109 | 110 | //---------- 111 | // body 112 | 113 | const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); 114 | 115 | for(int i = -nblocks; i; i++) 116 | { 117 | uint32_t k1 = getblock(blocks,i); 118 | 119 | k1 *= c1; 120 | k1 = ROTL32(k1,15); 121 | k1 *= c2; 122 | 123 | h1 ^= k1; 124 | h1 = ROTL32(h1,13); 125 | h1 = h1*5+0xe6546b64; 126 | } 127 | 128 | //---------- 129 | // tail 130 | 131 | const uint8_t * tail = (const uint8_t*)(data + nblocks*4); 132 | 133 | uint32_t k1 = 0; 134 | 135 | switch(len & 3) 136 | { 137 | case 3: k1 ^= tail[2] << 16; 138 | case 2: k1 ^= tail[1] << 8; 139 | case 1: k1 ^= tail[0]; 140 | k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; 141 | }; 142 | 143 | //---------- 144 | // finalization 145 | 146 | h1 ^= len; 147 | 148 | h1 = fmix(h1); 149 | 150 | *(uint32_t*)out = h1; 151 | } 152 | 153 | //----------------------------------------------------------------------------- 154 | 155 | void MurmurHash3_x86_128 ( const void * key, const int len, 156 | uint32_t seed, void * out ) 157 | { 158 | const uint8_t * data = (const uint8_t*)key; 159 | const int nblocks = len / 16; 160 | 161 | uint32_t h1 = seed; 162 | uint32_t h2 = seed; 163 | uint32_t h3 = seed; 164 | uint32_t h4 = seed; 165 | 166 | const uint32_t c1 = 0x239b961b; 167 | const uint32_t c2 = 0xab0e9789; 168 | const uint32_t c3 = 0x38b34ae5; 169 | const uint32_t c4 = 0xa1e38b93; 170 | 171 | //---------- 172 | // body 173 | 174 | const uint32_t * blocks = (const uint32_t *)(data + nblocks*16); 175 | 176 | for(int i = -nblocks; i; i++) 177 | { 178 | uint32_t k1 = getblock(blocks,i*4+0); 179 | uint32_t k2 = getblock(blocks,i*4+1); 180 | uint32_t k3 = getblock(blocks,i*4+2); 181 | uint32_t k4 = getblock(blocks,i*4+3); 182 | 183 | k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; 184 | 185 | h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b; 186 | 187 | k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; 188 | 189 | h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747; 190 | 191 | k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; 192 | 193 | h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35; 194 | 195 | k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; 196 | 197 | h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17; 198 | } 199 | 200 | //---------- 201 | // tail 202 | 203 | const uint8_t * tail = (const uint8_t*)(data + nblocks*16); 204 | 205 | uint32_t k1 = 0; 206 | uint32_t k2 = 0; 207 | uint32_t k3 = 0; 208 | uint32_t k4 = 0; 209 | 210 | switch(len & 15) 211 | { 212 | case 15: k4 ^= tail[14] << 16; 213 | case 14: k4 ^= tail[13] << 8; 214 | case 13: k4 ^= tail[12] << 0; 215 | k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; 216 | 217 | case 12: k3 ^= tail[11] << 24; 218 | case 11: k3 ^= tail[10] << 16; 219 | case 10: k3 ^= tail[ 9] << 8; 220 | case 9: k3 ^= tail[ 8] << 0; 221 | k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; 222 | 223 | case 8: k2 ^= tail[ 7] << 24; 224 | case 7: k2 ^= tail[ 6] << 16; 225 | case 6: k2 ^= tail[ 5] << 8; 226 | case 5: k2 ^= tail[ 4] << 0; 227 | k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; 228 | 229 | case 4: k1 ^= tail[ 3] << 24; 230 | case 3: k1 ^= tail[ 2] << 16; 231 | case 2: k1 ^= tail[ 1] << 8; 232 | case 1: k1 ^= tail[ 0] << 0; 233 | k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; 234 | }; 235 | 236 | //---------- 237 | // finalization 238 | 239 | h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; 240 | 241 | h1 += h2; h1 += h3; h1 += h4; 242 | h2 += h1; h3 += h1; h4 += h1; 243 | 244 | h1 = fmix(h1); 245 | h2 = fmix(h2); 246 | h3 = fmix(h3); 247 | h4 = fmix(h4); 248 | 249 | h1 += h2; h1 += h3; h1 += h4; 250 | h2 += h1; h3 += h1; h4 += h1; 251 | 252 | ((uint32_t*)out)[0] = h1; 253 | ((uint32_t*)out)[1] = h2; 254 | ((uint32_t*)out)[2] = h3; 255 | ((uint32_t*)out)[3] = h4; 256 | } 257 | 258 | //----------------------------------------------------------------------------- 259 | 260 | void MurmurHash3_x64_128 ( const void * key, const int len, 261 | const uint32_t seed, void * out ) 262 | { 263 | const uint8_t * data = (const uint8_t*)key; 264 | const int nblocks = len / 16; 265 | 266 | uint64_t h1 = seed; 267 | uint64_t h2 = seed; 268 | 269 | const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); 270 | const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); 271 | 272 | //---------- 273 | // body 274 | 275 | const uint64_t * blocks = (const uint64_t *)(data); 276 | 277 | for(int i = 0; i < nblocks; i++) 278 | { 279 | uint64_t k1 = getblock(blocks,i*2+0); 280 | uint64_t k2 = getblock(blocks,i*2+1); 281 | 282 | k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; 283 | 284 | h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; 285 | 286 | k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; 287 | 288 | h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; 289 | } 290 | 291 | //---------- 292 | // tail 293 | 294 | const uint8_t * tail = (const uint8_t*)(data + nblocks*16); 295 | 296 | uint64_t k1 = 0; 297 | uint64_t k2 = 0; 298 | 299 | switch(len & 15) 300 | { 301 | case 15: k2 ^= uint64_t(tail[14]) << 48; 302 | case 14: k2 ^= uint64_t(tail[13]) << 40; 303 | case 13: k2 ^= uint64_t(tail[12]) << 32; 304 | case 12: k2 ^= uint64_t(tail[11]) << 24; 305 | case 11: k2 ^= uint64_t(tail[10]) << 16; 306 | case 10: k2 ^= uint64_t(tail[ 9]) << 8; 307 | case 9: k2 ^= uint64_t(tail[ 8]) << 0; 308 | k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; 309 | 310 | case 8: k1 ^= uint64_t(tail[ 7]) << 56; 311 | case 7: k1 ^= uint64_t(tail[ 6]) << 48; 312 | case 6: k1 ^= uint64_t(tail[ 5]) << 40; 313 | case 5: k1 ^= uint64_t(tail[ 4]) << 32; 314 | case 4: k1 ^= uint64_t(tail[ 3]) << 24; 315 | case 3: k1 ^= uint64_t(tail[ 2]) << 16; 316 | case 2: k1 ^= uint64_t(tail[ 1]) << 8; 317 | case 1: k1 ^= uint64_t(tail[ 0]) << 0; 318 | k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; 319 | }; 320 | 321 | //---------- 322 | // finalization 323 | 324 | h1 ^= len; h2 ^= len; 325 | 326 | h1 += h2; 327 | h2 += h1; 328 | 329 | h1 = fmix(h1); 330 | h2 = fmix(h2); 331 | 332 | h1 += h2; 333 | h2 += h1; 334 | 335 | ((uint64_t*)out)[0] = h1; 336 | ((uint64_t*)out)[1] = h2; 337 | } 338 | 339 | //----------------------------------------------------------------------------- 340 | 341 | -------------------------------------------------------------------------------- /test/pymmh3_test.py: -------------------------------------------------------------------------------- 1 | # pymmh3 was written by Fredrik Kihlander and enhanced by Swapnil Gusani, and is placed in the public 2 | # domain. The authors hereby disclaim copyright to this source code. 3 | 4 | import os 5 | import sys 6 | import unittest 7 | 8 | file_dir = os.path.dirname( __file__ ) 9 | sys.path.append( os.path.join( file_dir, '..' ) ) 10 | import pymmh3 11 | 12 | class Testpymmh3( unittest.TestCase ): 13 | def _load_solutions(self, solution_file, base = 16): 14 | solution = {} 15 | with open( os.path.join( file_dir, solution_file ), 'rb' ) as f: 16 | while True: 17 | l = f.readline() 18 | if not l: 19 | break 20 | solution[ l ] = int( f.readline(), base ) 21 | 22 | return solution 23 | 24 | 25 | def test_32bit_basic_string( self ): 26 | solution = self._load_solutions('solution_hash32_seed0.txt', 10) 27 | 28 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 29 | for l in test_file.readlines(): 30 | s = solution[l] 31 | r = pymmh3.hash( l ) 32 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 33 | 34 | def test_32bit_basic_bytearray( self ): 35 | solution = self._load_solutions('solution_hash32_seed0.txt', 10) 36 | 37 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 38 | for l in test_file.readlines(): 39 | s = solution[l] 40 | r = pymmh3.hash( bytearray( l ) ) 41 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 42 | 43 | def test_32bit_custom_seed_string( self ): 44 | solution = self._load_solutions('solution_hash32_seed1234ABCD.txt', 10) 45 | 46 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 47 | for l in test_file.readlines(): 48 | s = solution[l] 49 | r = pymmh3.hash( l, seed = 0x1234ABCD ) 50 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 51 | 52 | def test_32bit_custom_seed_bytearray( self ): 53 | solution = self._load_solutions('solution_hash32_seed1234ABCD.txt', 10) 54 | 55 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 56 | for l in test_file.readlines(): 57 | s = solution[l] 58 | r = pymmh3.hash( bytearray( l ), seed = 0x1234ABCD ) 59 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 60 | 61 | def test_128bit_x86_basic_string( self ): 62 | solution = self._load_solutions('solution_hash128_x86_seed0.txt') 63 | 64 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 65 | for l in test_file.readlines(): 66 | s = solution[l] 67 | r = pymmh3.hash128( l , x64arch = False ) 68 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 69 | 70 | def test_128bit_x86_basic_bytearray( self ): 71 | solution = self._load_solutions('solution_hash128_x86_seed0.txt') 72 | 73 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 74 | for l in test_file.readlines(): 75 | s = solution[l] 76 | r = pymmh3.hash128( bytearray( l ), x64arch = False ) 77 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 78 | 79 | def test_128bit_x86_custom_seed_string( self ): 80 | solution = self._load_solutions('solution_hash128_x86_seed1234ABCD.txt') 81 | 82 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 83 | for l in test_file.readlines(): 84 | s = solution[l] 85 | r = pymmh3.hash128( l, seed = 0x1234ABCD, x64arch = False ) 86 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 87 | 88 | def test_128bit_x86_custom_seed_bytearray( self ): 89 | solution = self._load_solutions('solution_hash128_x86_seed1234ABCD.txt') 90 | 91 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 92 | for l in test_file.readlines(): 93 | s = solution[l] 94 | r = pymmh3.hash128( bytearray( l ), seed = 0x1234ABCD, x64arch = False ) 95 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 96 | 97 | def test_128bit_x64_basic_string( self ): 98 | solution = self._load_solutions('solution_hash128_x64_seed0.txt') 99 | 100 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 101 | for l in test_file.readlines(): 102 | s = solution[l] 103 | r = pymmh3.hash128( l, x64arch = True ) 104 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 105 | 106 | def test_128bit_x64_basic_bytearray( self ): 107 | solution = self._load_solutions('solution_hash128_x64_seed0.txt') 108 | 109 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 110 | for l in test_file.readlines(): 111 | s = solution[l] 112 | r = pymmh3.hash128( bytearray( l ), x64arch = True ) 113 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 114 | 115 | def test_128bit_x64_custom_seed_string( self ): 116 | solution = self._load_solutions('solution_hash128_x64_seed1234ABCD.txt') 117 | 118 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 119 | for l in test_file.readlines(): 120 | s = solution[l] 121 | r = pymmh3.hash128( l, seed = 0x1234ABCD, x64arch = True ) 122 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 123 | 124 | def test_128bit_x64_custom_seed_bytearray( self ): 125 | solution = self._load_solutions('solution_hash128_x64_seed1234ABCD.txt') 126 | 127 | with open( os.path.join( file_dir, 'pg1260.txt' ), 'rb' ) as test_file: 128 | for l in test_file.readlines(): 129 | s = solution[l] 130 | r = pymmh3.hash128( bytearray( l ), seed = 0x1234ABCD, x64arch = True ) 131 | self.assertEqual( s, r, 'different hash for line: "%s"\n0x%08X != 0x%08X' % ( l, s, r ) ) 132 | 133 | if __name__ == "__main__": 134 | unittest.main() 135 | -------------------------------------------------------------------------------- /test/unitest_solution_gen.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * pymmh3 was written by Fredrik Kihlander and enhanced by Swapnil Gusani, and is placed in the public 3 | * domain. The authors hereby disclaim copyright to this source code. 4 | * 5 | * This is a hacky program to generate hashes to test against in the unittests. 6 | * 7 | * Ie, this code was used to generate the solution-files! 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "MurmurHash3.h" 15 | namespace mmh3 { 16 | #include "MurmurHash3.inc" 17 | } 18 | 19 | int main( int argc, const char** argv ) 20 | { 21 | FILE* f = fopen( "test/pg1260.txt", "rb" ); 22 | FILE* out1 = fopen( "test/solution_hash32_seed0.txt", "wb" ); 23 | FILE* out2 = fopen( "test/solution_hash32_seed1234ABCD.txt", "wb" ); 24 | FILE* out3 = fopen( "test/solution_hash128_x86_seed0.txt", "wb" ); 25 | FILE* out4 = fopen( "test/solution_hash128_x86_seed1234ABCD.txt", "wb" ); 26 | FILE* out5 = fopen( "test/solution_hash128_x64_seed0.txt", "wb" ); 27 | FILE* out6 = fopen( "test/solution_hash128_x64_seed1234ABCD.txt", "wb" ); 28 | char buffer[2048]; 29 | 30 | char* l; 31 | while( ( l = fgets( buffer, 2048, f ) ) != 0x0 ) 32 | { 33 | int32_t res1; 34 | int32_t res2; 35 | uint32_t res3[4]; 36 | uint32_t res4[4]; 37 | uint32_t res5[4]; 38 | uint32_t res6[4]; 39 | mmh3::MurmurHash3_x86_32( l, strlen(l), 0, &res1 ); 40 | fprintf( out1, "%s%d\n", l, res1 ); 41 | mmh3::MurmurHash3_x86_32( l, strlen(l), 0x1234ABCD, &res2 ); 42 | fprintf( out2, "%s%d\n", l, res2 ); 43 | mmh3::MurmurHash3_x86_128( l, strlen(l), 0, res3 ); 44 | fprintf( out3, "%s0x%08X%08X%08X%08X\n", l, res3[3], res3[2], res3[1], res3[0] ); 45 | mmh3::MurmurHash3_x86_128( l, strlen(l), 0x1234ABCD, res4 ); 46 | fprintf( out4, "%s0x%08X%08X%08X%08X\n", l, res4[3], res4[2], res4[1], res4[0] ); 47 | mmh3::MurmurHash3_x64_128( l, strlen(l), 0, res5 ); 48 | fprintf( out5, "%s0x%08X%08X%08X%08X\n", l, res5[3], res5[2], res5[1], res5[0] ); 49 | mmh3::MurmurHash3_x64_128( l, strlen(l), 0x1234ABCD, res6 ); 50 | fprintf( out6, "%s0x%08X%08X%08X%08X\n", l, res6[3], res6[2], res6[1], res6[0] ); 51 | } 52 | 53 | fclose( f ); 54 | fclose( out1 ); 55 | fclose( out2 ); 56 | fclose( out3 ); 57 | fclose( out4 ); 58 | fclose( out5 ); 59 | fclose( out6 ); 60 | return 0; 61 | } 62 | --------------------------------------------------------------------------------