crc & crc-turbo:
@@ -12,12 +12,12 @@ | ||
12 | 12 | * author: dearblue (mailto:dearblue@users.osdn.me) |
13 | 13 | * report issue to: <https://osdn.jp/projects/rutsubo/ticket/> |
14 | 14 | * how to install: ``gem install crc-turbo`` |
15 | - * version: 0.2 | |
15 | + * version: 0.3 | |
16 | 16 | * release quality: thechnical preview |
17 | 17 | * licensing: BSD-2-Clause<br>any parts are under Creative Commons License Zero (CC0 / Public Domain). |
18 | - * dependency gems: crc-0.2 (<https://rubygems/gems/crc>) | |
19 | - * dependency external c libraries: none | |
20 | - * bundled external c libraries: none | |
18 | + * dependency gems: crc-0.3 (<https://rubygems/gems/crc>) | |
19 | + * dependency external C libraries: none | |
20 | + * bundled external C libraries: none | |
21 | 21 | |
22 | 22 | |
23 | 23 | ## How to usage |
@@ -26,8 +26,6 @@ | ||
26 | 26 | |
27 | 27 | ``` shell:shell |
28 | 28 | # gem install crc-turbo |
29 | -..... | |
30 | -# | |
31 | 29 | ``` |
32 | 30 | |
33 | 31 | And, to do ``require "crc"``. |
@@ -16,15 +16,16 @@ | ||
16 | 16 | TABLE_NOTREADY = 0x1000, |
17 | 17 | }; |
18 | 18 | |
19 | -#define SWITCH_BY_TYPE(FLAGS, STMT_U8, STMT_U16, STMT_U32, STMT_U64, STMT_U128) \ | |
20 | - switch ((FLAGS) & TYPE_MASK) { \ | |
21 | - case TYPE_UINT8_T: { STMT_U8; break; } \ | |
22 | - case TYPE_UINT16_T: { STMT_U16; break; } \ | |
23 | - case TYPE_UINT32_T: { STMT_U32; break; } \ | |
24 | - case TYPE_UINT64_T: { STMT_U64; break; } \ | |
25 | - /* case TYPE_UINT128_T: { STMT_U128; break; } */ \ | |
26 | - default: { rb_bug(" [INVALID TYPE FLAGS: 0x%02X] ", (FLAGS) & TYPE_MASK); } \ | |
27 | - } \ | |
19 | +//#define SNNIPET(BITSIZE, AS, TYPE, TOUINT, CONVUINT) | |
20 | +#define SWITCH_BY_TYPE(TYPE, SNNIPET) \ | |
21 | + switch ((TYPE)) { \ | |
22 | + case TYPE_UINT8_T: { SNNIPET( 8, as8, uint8_t, to_uint8, conv_uint8); break; } \ | |
23 | + case TYPE_UINT16_T: { SNNIPET( 16, as16, uint16_t, to_uint16, conv_uint16); break; } \ | |
24 | + case TYPE_UINT32_T: { SNNIPET( 32, as32, uint32_t, to_uint32, conv_uint32); break; } \ | |
25 | + case TYPE_UINT64_T: { SNNIPET( 64, as64, uint64_t, to_uint64, conv_uint64); break; } \ | |
26 | + /* case TYPE_UINT128_T: { SNNIPET(128, as128, uint128_t, to_uint128, conv_uint128); break; } */ \ | |
27 | + default: { rb_bug(" [INVALID TYPE FLAGS: 0x%02X] ", (TYPE)); } \ | |
28 | + } \ | |
28 | 29 | |
29 | 30 | static inline uint8_t |
30 | 31 | to_uint8(VALUE num) |
@@ -321,52 +322,50 @@ | ||
321 | 322 | }; |
322 | 323 | } anyuint_t; |
323 | 324 | |
324 | -struct generator | |
325 | +struct crc_module | |
325 | 326 | { |
326 | - int bitsize; | |
327 | - int flags; /* int type, refin, refout */ | |
327 | + uint32_t bitsize:10; | |
328 | + uint32_t type:10; | |
329 | + uint32_t reflect_input:1; | |
330 | + uint32_t reflect_output:1; | |
331 | + | |
328 | 332 | anyuint_t bitmask, polynomial, initial, xorout; |
329 | 333 | const void *table; /* entity is String buffer as instance variable */ |
330 | 334 | }; |
331 | 335 | |
332 | -static VALUE mCRC; /* module CRC */ | |
336 | +static VALUE cCRC; /* class CRC */ | |
333 | 337 | static VALUE mUtils; /* module CRC::Utils */ |
334 | -static VALUE cGenerator; /* class CRC::Generator */ | |
335 | -static ID generator_iv_name; | |
336 | -static ID generator_iv_table_buffer; | |
338 | +static ID ext_iv_name; | |
339 | +static ID ext_iv_module; | |
340 | +static ID ext_iv_table_buffer; | |
337 | 341 | |
338 | -static const rb_data_type_t generator_type = { | |
339 | - .wrap_struct_name = "crc-turbo.CRC::Generator", | |
342 | +static const rb_data_type_t ext_type = { | |
343 | + .wrap_struct_name = "crc-turbo.CRC.module", | |
340 | 344 | .function.dmark = NULL, |
341 | 345 | .function.dsize = NULL, |
342 | 346 | .function.dfree = (void *)-1, |
343 | 347 | }; |
344 | 348 | |
345 | -static void | |
346 | -check_generator_notinit(VALUE obj) | |
349 | +static struct crc_module * | |
350 | +get_modulep(VALUE obj) | |
347 | 351 | { |
348 | - struct generator *p; | |
349 | - TypedData_Get_Struct(obj, struct generator, &generator_type, p); | |
350 | - if (p) { rb_raise(rb_eArgError, "already initialized object - #<%s:0x%p>", rb_obj_classname(obj), (void *)obj); } | |
352 | + struct crc_module *p; | |
353 | + obj = rb_ivar_get(obj, ext_iv_module); | |
354 | + if (NIL_P(obj)) { return NULL; } | |
355 | + TypedData_Get_Struct(obj, struct crc_module, &ext_type, p); | |
356 | + return p; | |
351 | 357 | } |
352 | 358 | |
353 | -static struct generator * | |
354 | -get_generator(VALUE obj) | |
359 | +static struct crc_module * | |
360 | +get_module(VALUE obj) | |
355 | 361 | { |
356 | - struct generator *p; | |
357 | - TypedData_Get_Struct(obj, struct generator, &generator_type, p); | |
358 | - if (!p) { rb_raise(rb_eArgError, "wrong initialized object - #<%s:0x%p>", rb_obj_classname(obj), (void *)obj); } | |
362 | + struct crc_module *p = get_modulep(obj); | |
363 | + if (!p) { rb_raise(rb_eTypeError, "wrong initialized object - #<%s:0x%p>", rb_obj_classname(obj), (void *)obj); } | |
359 | 364 | return p; |
360 | 365 | } |
361 | 366 | |
362 | -static VALUE | |
363 | -generator_alloc(VALUE mod) | |
364 | -{ | |
365 | - return TypedData_Wrap_Struct(mod, &generator_type, NULL); | |
366 | -} | |
367 | - | |
368 | 367 | static void |
369 | -generator_init_args(int argc, VALUE argv[], int *flags, int *bitsize, VALUE *poly, VALUE *init, VALUE *xorout, VALUE *name) | |
368 | +ext_init_args(int argc, VALUE argv[], int *flags, int *bitsize, VALUE *poly, VALUE *init, VALUE *xorout, VALUE *name) | |
370 | 369 | { |
371 | 370 | rb_check_arity(argc, 2, 7); |
372 | 371 | *bitsize = NUM2INT(argv[0]); |
@@ -390,191 +389,180 @@ | ||
390 | 389 | *name = (argc > 6 && !NIL_P(argv[6])) ? rb_String(argv[6]) : Qnil; |
391 | 390 | } |
392 | 391 | |
393 | -/* | |
394 | - * call-seq: | |
395 | - * initialize(bitsize, polynomial, initial_state = 0, reflect_input = true, reflect_output = true, xor_output = ~0, name = nil) | |
396 | - */ | |
397 | 392 | static VALUE |
398 | -generator_init(int argc, VALUE argv[], VALUE obj) | |
393 | +ext_s_new(int argc, VALUE argv[], VALUE crc) | |
399 | 394 | { |
400 | - int flags, bitsize; | |
401 | - VALUE poly, init, xorout, name; | |
402 | - check_generator_notinit(obj); | |
403 | - generator_init_args(argc, argv, &flags, &bitsize, &poly, &init, &xorout, &name); | |
395 | + if (get_modulep(crc)) { | |
396 | + return rb_call_super(argc, argv); | |
397 | + } else { | |
398 | + int flags, bitsize; | |
399 | + VALUE poly, init, xorout, name; | |
400 | + ext_init_args(argc, argv, &flags, &bitsize, &poly, &init, &xorout, &name); | |
404 | 401 | |
405 | - struct generator *p; | |
406 | - size_t allocsize = sizeof(struct generator); | |
407 | - RTYPEDDATA_DATA(obj) = p = (struct generator *)ALLOC_N(char, allocsize); | |
408 | - p->bitsize = bitsize; | |
409 | - p->flags = flags; | |
410 | - p->table = NULL; | |
402 | + struct crc_module *p; | |
403 | + VALUE crcmod = TypedData_Make_Struct(crc, struct crc_module, &ext_type, p); | |
411 | 404 | |
412 | - /* | |
413 | - * bitmask の代入でわざわざ1ビット分を後から行う理由は、 | |
414 | - * 例えば uint8_t に対して << 8 をすると何もしないため、 | |
415 | - * これへの対処を目的とする。 | |
416 | - */ | |
417 | -#define INIT_GENERATOR(TYPE, AS, TO_UINT, CONV_UINT, P, BITSIZE, POLY, INIT, XOROUT) \ | |
418 | - P->bitmask.AS = ~(~(TYPE)0 << 1 << (BITSIZE - 1)); \ | |
419 | - P->polynomial.AS = P->bitmask.AS & TO_UINT(POLY); \ | |
420 | - P->initial.AS = P->bitmask.AS & TO_UINT(INIT); \ | |
421 | - P->xorout.AS = P->bitmask.AS & TO_UINT(XOROUT); \ | |
405 | + p->bitsize = bitsize; | |
406 | + p->type = flags & TYPE_MASK; | |
407 | + p->reflect_input = ((flags & REFLECT_INPUT) != 0) ? 1 : 0; | |
408 | + p->reflect_output = ((flags & REFLECT_OUTPUT) != 0) ? 1 : 0; | |
409 | + p->table = NULL; | |
422 | 410 | |
423 | - SWITCH_BY_TYPE(flags, | |
424 | - INIT_GENERATOR(uint8_t, as8, to_uint8, conv_uint8, p, bitsize, poly, init, xorout), | |
425 | - INIT_GENERATOR(uint16_t, as16, to_uint16, conv_uint16, p, bitsize, poly, init, xorout), | |
426 | - INIT_GENERATOR(uint32_t, as32, to_uint32, conv_uint32, p, bitsize, poly, init, xorout), | |
427 | - INIT_GENERATOR(uint64_t, as64, to_uint64, conv_uint64, p, bitsize, poly, init, xorout), | |
428 | - INIT_GENERATOR(uint128_t, as128, to_uint128, conv_uint128, p, bitsize, poly, init, xorout)); | |
411 | + /* | |
412 | + * bitmask の代入でわざわざ1ビット分を後から行う理由は、 | |
413 | + * 例えば uint8_t に対して << 8 をすると何もしないため、 | |
414 | + * これへの対処を目的とする。 | |
415 | + */ | |
416 | +#define SNNIPET_INIT_MOD(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
417 | + p->bitmask.AS = ~(~(TYPE)0 << 1 << (bitsize - 1)); \ | |
418 | + p->polynomial.AS = p->bitmask.AS & TOUINT(poly); \ | |
419 | + p->initial.AS = p->bitmask.AS & TOUINT(init); \ | |
420 | + p->xorout.AS = p->bitmask.AS & TOUINT(xorout); \ | |
429 | 421 | |
430 | -#undef INIT_GENERATOR | |
422 | + SWITCH_BY_TYPE(p->type, SNNIPET_INIT_MOD); | |
431 | 423 | |
432 | - rb_ivar_set(obj, generator_iv_name, name); | |
424 | + VALUE newcrc = rb_define_class_id(0, crc); | |
425 | + rb_ivar_set(newcrc, ext_iv_module, crcmod); | |
426 | + rb_ivar_set(newcrc, ext_iv_name, name); | |
433 | 427 | |
434 | - return obj; | |
428 | + rb_extend_object(newcrc, rb_const_get(cCRC, rb_intern("ModuleClass"))); | |
429 | + rb_define_alias(rb_singleton_class(newcrc), "[]", "new"); | |
430 | + | |
431 | + return newcrc; | |
432 | + } | |
435 | 433 | } |
436 | 434 | |
437 | 435 | static VALUE |
438 | -generator_bitsize(VALUE t) | |
436 | +ext_bitsize(VALUE t) | |
439 | 437 | { |
440 | - return INT2FIX(get_generator(t)->bitsize); | |
438 | + return INT2FIX(get_module(t)->bitsize); | |
441 | 439 | } |
442 | 440 | |
443 | 441 | static VALUE |
444 | -generator_bitmask(VALUE t) | |
442 | +ext_bitmask(VALUE t) | |
445 | 443 | { |
446 | - struct generator *p = get_generator(t); | |
447 | - SWITCH_BY_TYPE(p->flags, | |
448 | - return conv_uint8(p->bitmask.as8), | |
449 | - return conv_uint16(p->bitmask.as16), | |
450 | - return conv_uint32(p->bitmask.as32), | |
451 | - return conv_uint64(p->bitmask.as64), | |
452 | - return conv_uint128(p->bitmask.as128)); | |
444 | + struct crc_module *p = get_module(t); | |
445 | + | |
446 | +#define SNNIPET_BITMASK(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
447 | + return CONVUINT(p->bitmask.AS); \ | |
448 | + | |
449 | + SWITCH_BY_TYPE(p->type, SNNIPET_BITMASK); | |
453 | 450 | } |
454 | 451 | |
455 | 452 | static VALUE |
456 | -generator_polynomial(VALUE t) | |
453 | +ext_polynomial(VALUE t) | |
457 | 454 | { |
458 | - struct generator *p = get_generator(t); | |
459 | - SWITCH_BY_TYPE(p->flags, | |
460 | - return conv_uint8(p->polynomial.as8), | |
461 | - return conv_uint16(p->polynomial.as16), | |
462 | - return conv_uint32(p->polynomial.as32), | |
463 | - return conv_uint64(p->polynomial.as64), | |
464 | - return conv_uint128(p->polynomial.as128)); | |
455 | + struct crc_module *p = get_module(t); | |
456 | + | |
457 | +#define SNNIPET_POLYNOMIAL(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
458 | + return CONVUINT(p->polynomial.AS); \ | |
459 | + | |
460 | + SWITCH_BY_TYPE(p->type, SNNIPET_POLYNOMIAL); | |
465 | 461 | } |
466 | 462 | |
467 | 463 | static VALUE |
468 | -generator_initial_state(VALUE t) | |
464 | +ext_initial_crc(VALUE t) | |
469 | 465 | { |
470 | - struct generator *p = get_generator(t); | |
471 | - SWITCH_BY_TYPE(p->flags, | |
472 | - return conv_uint8(p->initial.as8), | |
473 | - return conv_uint16(p->initial.as16), | |
474 | - return conv_uint32(p->initial.as32), | |
475 | - return conv_uint64(p->initial.as64), | |
476 | - return conv_uint128(p->initial.as128)); | |
466 | + struct crc_module *p = get_module(t); | |
467 | + | |
468 | +#define SNNIPET_INITIAL_CRC(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
469 | + return CONVUINT(p->initial.AS); \ | |
470 | + | |
471 | + SWITCH_BY_TYPE(p->type, SNNIPET_INITIAL_CRC); | |
477 | 472 | } |
478 | 473 | |
479 | 474 | static VALUE |
480 | -generator_table(VALUE t) | |
475 | +ext_table(VALUE t) | |
481 | 476 | { |
482 | - struct generator *p = get_generator(t); | |
477 | + struct crc_module *p = get_module(t); | |
483 | 478 | rb_raise(rb_eNotImpError, ""); |
484 | 479 | } |
485 | 480 | |
486 | 481 | static VALUE |
487 | -generator_reflect_input(VALUE t) | |
482 | +ext_reflect_input(VALUE t) | |
488 | 483 | { |
489 | - struct generator *p = get_generator(t); | |
490 | - return (p->flags & REFLECT_INPUT) ? Qtrue : Qfalse; | |
484 | + struct crc_module *p = get_module(t); | |
485 | + return (p->reflect_input != 0) ? Qtrue : Qfalse; | |
491 | 486 | } |
492 | 487 | |
493 | 488 | static VALUE |
494 | -generator_reflect_output(VALUE t) | |
489 | +ext_reflect_output(VALUE t) | |
495 | 490 | { |
496 | - struct generator *p = get_generator(t); | |
497 | - return (p->flags & REFLECT_OUTPUT) ? Qtrue : Qfalse; | |
491 | + struct crc_module *p = get_module(t); | |
492 | + return (p->reflect_output != 0) ? Qtrue : Qfalse; | |
498 | 493 | } |
499 | 494 | |
500 | 495 | static VALUE |
501 | -generator_xor_output(VALUE t) | |
496 | +ext_xor_output(VALUE t) | |
502 | 497 | { |
503 | - struct generator *p = get_generator(t); | |
504 | - SWITCH_BY_TYPE(p->flags, | |
505 | - return conv_uint8(p->xorout.as8), | |
506 | - return conv_uint16(p->xorout.as16), | |
507 | - return conv_uint32(p->xorout.as32), | |
508 | - return conv_uint64(p->xorout.as64), | |
509 | - return conv_uint128(p->xorout.as128)); | |
498 | + struct crc_module *p = get_module(t); | |
499 | + | |
500 | +#define SNNIPET_XOR_OUTPUT(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
501 | + return CONVUINT(p->xorout.AS); \ | |
502 | + | |
503 | + SWITCH_BY_TYPE(p->type, SNNIPET_XOR_OUTPUT); | |
510 | 504 | } |
511 | 505 | |
512 | 506 | static VALUE |
513 | -generator_name(VALUE t) | |
507 | +ext_name(VALUE t) | |
514 | 508 | { |
515 | - // get_generator で初期化の確認 | |
516 | - get_generator(t); | |
509 | + // get_module で初期化の確認 | |
510 | + get_module(t); | |
517 | 511 | |
518 | - return rb_ivar_get(t, generator_iv_name); | |
512 | + return rb_ivar_get(t, ext_iv_name); | |
519 | 513 | } |
520 | 514 | |
521 | 515 | static VALUE |
522 | -generator_set_name(VALUE t, VALUE name) | |
516 | +ext_set_name(VALUE t, VALUE name) | |
523 | 517 | { |
524 | - // get_generator で初期化の確認 | |
525 | - get_generator(t); | |
518 | + // get_module で初期化の確認 | |
519 | + get_module(t); | |
526 | 520 | |
527 | - rb_ivar_set(t, generator_iv_name, rb_String(name)); | |
521 | + rb_ivar_set(t, ext_iv_name, rb_String(name)); | |
528 | 522 | return name; |
529 | 523 | } |
530 | 524 | |
531 | 525 | static VALUE |
532 | -generator_update(VALUE t, VALUE seq, VALUE state) | |
526 | +ext_update(VALUE t, VALUE seq, VALUE state) | |
533 | 527 | { |
534 | - struct generator *p = get_generator(t); | |
528 | + struct crc_module *p = get_module(t); | |
535 | 529 | rb_check_type(seq, RUBY_T_STRING); |
536 | 530 | const char *q = RSTRING_PTR(seq); |
537 | 531 | const char *qq = q + RSTRING_LEN(seq); |
538 | 532 | |
539 | 533 | if (!p->table) { |
540 | - size_t tablebytes = (p->flags & TYPE_MASK) * 16 * 256; | |
534 | + size_t tablebytes = (p->type) * 16 * 256; | |
541 | 535 | VALUE tablebuf = rb_str_buf_new(tablebytes); |
542 | 536 | rb_str_set_len(tablebuf, tablebytes); |
543 | 537 | void *table = RSTRING_PTR(tablebuf); |
544 | - if (p->flags & REFLECT_INPUT) { | |
545 | - SWITCH_BY_TYPE(p->flags, | |
546 | - crc_build_reflect_tables_u8(p->bitsize, table, p->polynomial.as8, 16), | |
547 | - crc_build_reflect_tables_u16(p->bitsize, table, p->polynomial.as16, 16), | |
548 | - crc_build_reflect_tables_u32(p->bitsize, table, p->polynomial.as32, 16), | |
549 | - crc_build_reflect_tables_u64(p->bitsize, table, p->polynomial.as64, 16), | |
550 | - crc_build_reflect_tables_u128(p->bitsize, table, p->polynomial.as128, 16)); | |
538 | + if (p->reflect_input) { | |
539 | +#define SNNIPET_BUILD_REFTABLE(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
540 | + crc_build_reflect_tables_u##BITSIZE(p->bitsize, table, p->polynomial.AS, 16); \ | |
541 | + | |
542 | + SWITCH_BY_TYPE(p->type, SNNIPET_BUILD_REFTABLE); | |
551 | 543 | } else { |
552 | - SWITCH_BY_TYPE(p->flags, | |
553 | - crc_build_tables_u8(p->bitsize, table, p->polynomial.as8, 16), | |
554 | - crc_build_tables_u16(p->bitsize, table, p->polynomial.as16, 16), | |
555 | - crc_build_tables_u32(p->bitsize, table, p->polynomial.as32, 16), | |
556 | - crc_build_tables_u64(p->bitsize, table, p->polynomial.as64, 16), | |
557 | - crc_build_tables_u128(p->bitsize, table, p->polynomial.as128, 16)); | |
544 | +#define SNNIPET_BUILD_TABLE(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
545 | + crc_build_tables_u##BITSIZE(p->bitsize, table, p->polynomial.AS, 16); \ | |
546 | + | |
547 | + SWITCH_BY_TYPE(p->type, SNNIPET_BUILD_TABLE); | |
558 | 548 | } |
559 | - rb_ivar_set(t, generator_iv_table_buffer, tablebuf); | |
549 | + rb_ivar_set(t, ext_iv_table_buffer, tablebuf); | |
560 | 550 | rb_obj_freeze(tablebuf); |
561 | 551 | p->table = table; |
562 | 552 | } |
563 | 553 | |
564 | - if (p->flags & REFLECT_INPUT) { | |
565 | - SWITCH_BY_TYPE(p->flags, | |
566 | - return conv_uint8(crc_reflect_update_u8(p->bitsize, p->table, q, qq, to_uint8(state))), | |
567 | - return conv_uint16(crc_reflect_update_u16(p->bitsize, p->table, q, qq, to_uint16(state))), | |
568 | - return conv_uint32(crc_reflect_update_u32(p->bitsize, p->table, q, qq, to_uint32(state))), | |
569 | - return conv_uint64(crc_reflect_update_u64(p->bitsize, p->table, q, qq, to_uint64(state))), | |
570 | - return conv_uint128(crc_reflect_update_u128(p->bitsize, p->table, q, qq, to_uint128(state)))); | |
554 | + if (p->reflect_input) { | |
555 | +#define SNNIPET_REFUPDATE(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
556 | + return CONVUINT(crc_reflect_update_u##BITSIZE( \ | |
557 | + p->bitsize, p->table, q, qq, TOUINT(state))); \ | |
558 | + | |
559 | + SWITCH_BY_TYPE(p->type, SNNIPET_REFUPDATE); | |
571 | 560 | } else { |
572 | - SWITCH_BY_TYPE(p->flags, | |
573 | - return conv_uint8(crc_update_u8(p->bitsize, p->table, q, qq, to_uint8(state))), | |
574 | - return conv_uint16(crc_update_u16(p->bitsize, p->table, q, qq, to_uint16(state))), | |
575 | - return conv_uint32(crc_update_u32(p->bitsize, p->table, q, qq, to_uint32(state))), | |
576 | - return conv_uint64(crc_update_u64(p->bitsize, p->table, q, qq, to_uint64(state))), | |
577 | - return conv_uint128(crc_update_u128(p->bitsize, p->table, q, qq, to_uint128(state)))); | |
561 | +#define SNNIPET_UPDATE(BITSIZE, AS, TYPE, TOUINT, CONVUINT) \ | |
562 | + return CONVUINT(crc_update_u##BITSIZE( \ | |
563 | + p->bitsize, p->table, q, qq, TOUINT(state))); \ | |
564 | + | |
565 | + SWITCH_BY_TYPE(p->type, SNNIPET_UPDATE); | |
578 | 566 | } |
579 | 567 | } |
580 | 568 |
@@ -639,30 +627,28 @@ | ||
639 | 627 | void |
640 | 628 | Init__turbo(void) |
641 | 629 | { |
642 | - generator_iv_name = rb_intern("crc-turbo.CRC::Generator.name"); | |
643 | - generator_iv_table_buffer = rb_intern("crc-turbo.CRC::Generator.table-buffer"); | |
630 | + ext_iv_name = rb_intern("crc-turbo.CRC.name"); | |
631 | + ext_iv_module = rb_intern("crc-turbo.CRC.module"); | |
632 | + ext_iv_table_buffer = rb_intern("crc-turbo.CRC.table-buffer"); | |
644 | 633 | |
645 | - mCRC = rb_define_module("CRC"); | |
634 | + cCRC = rb_define_class("CRC", rb_cObject); | |
635 | + rb_define_singleton_method(cCRC, "new", ext_s_new, -1); | |
636 | + rb_define_singleton_method(cCRC, "bitsize", ext_bitsize, 0); | |
637 | + rb_define_singleton_method(cCRC, "bitmask", ext_bitmask, 0); | |
638 | + rb_define_singleton_method(cCRC, "polynomial", ext_polynomial, 0); | |
639 | + rb_define_singleton_method(cCRC, "initial_crc", ext_initial_crc, 0); | |
640 | + rb_define_singleton_method(cCRC, "table", ext_table, 0); | |
641 | + rb_define_singleton_method(cCRC, "reflect_input?", ext_reflect_input, 0); | |
642 | + rb_define_singleton_method(cCRC, "reflect_output?", ext_reflect_output, 0); | |
643 | + rb_define_singleton_method(cCRC, "xor_output", ext_xor_output, 0); | |
644 | + rb_define_singleton_method(cCRC, "name", ext_name, 0); | |
645 | + rb_define_singleton_method(cCRC, "name=", ext_set_name, 1); | |
646 | + rb_define_singleton_method(cCRC, "update", ext_update, 2); | |
646 | 647 | |
647 | - mUtils = rb_define_module_under(mCRC, "Utils"); | |
648 | + mUtils = rb_define_module_under(cCRC, "Utils"); | |
648 | 649 | rb_define_method(mUtils, "bitreflect8", utils_s_bitref8, 1); |
649 | 650 | rb_define_method(mUtils, "bitreflect16", utils_s_bitref16, 1); |
650 | 651 | rb_define_method(mUtils, "bitreflect32", utils_s_bitref32, 1); |
651 | 652 | rb_define_method(mUtils, "bitreflect64", utils_s_bitref64, 1); |
652 | 653 | rb_define_method(mUtils, "bitreflect128", utils_s_bitref128, 1); |
653 | - | |
654 | - cGenerator = rb_define_class_under(mCRC, "Generator", rb_cObject); | |
655 | - rb_define_alloc_func(cGenerator, generator_alloc); | |
656 | - rb_define_method(cGenerator, "initialize", generator_init, -1); | |
657 | - rb_define_method(cGenerator, "bitsize", generator_bitsize, 0); | |
658 | - rb_define_method(cGenerator, "bitmask", generator_bitmask, 0); | |
659 | - rb_define_method(cGenerator, "polynomial", generator_polynomial, 0); | |
660 | - rb_define_method(cGenerator, "initial_state", generator_initial_state, 0); | |
661 | - rb_define_method(cGenerator, "table", generator_table, 0); | |
662 | - rb_define_method(cGenerator, "reflect_input", generator_reflect_input, 0); | |
663 | - rb_define_method(cGenerator, "reflect_output", generator_reflect_output, 0); | |
664 | - rb_define_method(cGenerator, "xor_output", generator_xor_output, 0); | |
665 | - rb_define_method(cGenerator, "name", generator_name, 0); | |
666 | - rb_define_method(cGenerator, "name=", generator_set_name, 1); | |
667 | - rb_define_method(cGenerator, "update", generator_update, 2); | |
668 | 654 | } |
@@ -4,7 +4,7 @@ | ||
4 | 4 | * |
5 | 5 | * This is a general CRC generator. |
6 | 6 | * |
7 | - * It's used slice-by-16 algorithm with byte-order free and byte-alignment free. | |
7 | + * It's used slice-by-16 algorithm with byte-order free. | |
8 | 8 | * This is based on the Intel's slice-by-eight algorithm. |
9 | 9 | * |
10 | 10 | * Worst point is need more memory! |
@@ -1,6 +1,6 @@ | ||
1 | 1 | GEMSTUB = Gem::Specification.new do |s| |
2 | 2 | s.name = "crc-turbo" |
3 | - s.version = "0.2" | |
3 | + s.version = "0.3" | |
4 | 4 | s.summary = "general CRC generator" |
5 | 5 | s.description = <<EOS |
6 | 6 | This is a C extention for "crc" gem library. |
@@ -12,8 +12,8 @@ | ||
12 | 12 | s.email = "dearblue@users.osdn.me" |
13 | 13 | |
14 | 14 | s.required_ruby_version = ">= 2.0" |
15 | - s.add_development_dependency "rake", "~> 11.0" | |
16 | - s.add_runtime_dependency "crc", "~> 0.2" | |
15 | + s.add_development_dependency "rake" | |
16 | + s.add_runtime_dependency "crc", "~> 0.3" | |
17 | 17 | end |
18 | 18 | |
19 | 19 | EXTMAP["crc"] = "crc/_turbo" |
@@ -2,6 +2,10 @@ | ||
2 | 2 | |
3 | 3 | # crc-turbo for ruby の更新履歴 |
4 | 4 | |
5 | +## crc-0.3 | |
6 | + | |
7 | + * crc-0.3 に追従して、CRC::BasicCRC と CRC::Generator を CRC に統合 | |
8 | + | |
5 | 9 | ## crc-0.2 (平成28年5月15日 (日)) |
6 | 10 | |
7 | 11 | * \[FIX\] CRC::Generator#polynomial メソッドが間違った値を返していた問題を修正 |
@@ -0,0 +1,5 @@ | ||
1 | +#!ruby | |
2 | + | |
3 | +class CRC | |
4 | + VERSION = "0.3" | |
5 | +end |
@@ -12,12 +12,13 @@ | ||
12 | 12 | # * https://github.com/cluelogic/cluelib/blob/master/src/cl_crc.svh |
13 | 13 | # * https://users.ece.cmu.edu/~koopman/crc/hw_data.html |
14 | 14 | # * https://users.ece.cmu.edu/~koopman/roses/dsn04/koopman04_crc_poly_embedded.pdf |
15 | +# * (CRC-64-ISO-3309) http://swissknife.cvs.sourceforge.net/viewvc/swissknife/SWISS/lib/SWISS/CRC64.pm | |
15 | 16 | #++ |
16 | 17 | |
17 | -module CRC | |
18 | +class CRC | |
18 | 19 | LIST = [ |
19 | 20 | # |
20 | - # bit size, polynomial, initial state, | |
21 | + # bit size, polynomial, initial crc, | |
21 | 22 | # refrect input, xor output, |
22 | 23 | # reflect output, crc("123456789"), names... |
23 | 24 | # |
@@ -33,10 +34,10 @@ | ||
33 | 34 | [ 6, 0x19, true, true, 0, 0, 0x26, "CRC-6-DARC"], |
34 | 35 | [ 6, 0x03, true, true, 0, 0, 0x06, "CRC-6-ITU"], |
35 | 36 | [ 7, 0x09, false, false, 0, 0, 0x75, "CRC-7", "CRC-7-JESD84-A441"], |
36 | - [ 7, 0x65, false, false, 0, 0, nil, "CRC-7-MVB"], | |
37 | + #[ 7, 0x65, false, false, 0, 0, nil, "CRC-7-MVB"], | |
37 | 38 | [ 7, 0x4F, true, true, ~0, 0, 0x53, "CRC-7-ROHC", "CRC-7-RFC 3095"], |
38 | 39 | [ 7, 0x45, false, false, 0, 0, 0x61, "CRC-7-UMTS"], |
39 | - [ 8, 0xD5, false, false, 0, 0, nil, "CRC-8"], | |
40 | + #[ 8, 0xD5, false, false, 0, 0, nil, "CRC-8"], | |
40 | 41 | [ 8, 0x07, false, false, 0, 0, 0xF4, "CRC-8-CCITT", "CRC-8-SMBus"], |
41 | 42 | [ 8, 0x31, true, true, 0, 0, 0xA1, "CRC-8-MAXIM", "CRC-8-Dallas/Maxim", "DOW-CRC"], |
42 | 43 | [ 8, 0x39, true, true, 0, 0, 0x15, "CRC-8-DARC"], |
@@ -60,9 +61,9 @@ | ||
60 | 61 | [14, 0x0805, true, true, 0, 0, 0x082D, "CRC-14-DARC"], |
61 | 62 | [15, 0x4599, false, false, 0, 0, 0x059E, "CRC-15", "CRC-15-CAN"], |
62 | 63 | [15, 0x6815, false, false, 1, 1, 0x2566, "CRC-15-MPT1327"], |
63 | - [16, 0x2F15, false, false, 0, 0, nil, "Chakravarty"], | |
64 | - [16, 0x8005, true, true, 0, 0, 0xBB3D, "ARC", "CRC-16", "CRC-IBM", "CRC-16-ARC", "CRC-16-LHA"], | |
65 | - [16, 0xA02B, false, false, 0, 0, nil, "CRC-16-ARINC"], | |
64 | + #[16, 0x2F15, false, false, 0, 0, nil, "Chakravarty"], | |
65 | + [16, 0x8005, true, true, 0, 0, 0xBB3D, "CRC-16", "ARC", "CRC-IBM", "CRC-16-ARC", "CRC-16-LHA"], | |
66 | + #[16, 0xA02B, false, false, 0, 0, nil, "CRC-16-ARINC"], | |
66 | 67 | [16, 0x1021, false, false, 0x1D0F, 0, 0xE5CC, "CRC-16-AUG-CCITT", "CRC-16-SPI-FUJITSU"], |
67 | 68 | [16, 0xC867, false, false, ~0, 0, 0x4C06, "CRC-16-CDMA2000"], |
68 | 69 | [16, 0x0589, false, false, 1, 1, 0x007E, "CRC-16-DECT-R", "R-CRC-16"], |
@@ -81,14 +82,14 @@ | ||
81 | 82 | [16, 0xA097, false, false, 0, 0, 0x0FB3, "CRC-16-TELEDISK"], |
82 | 83 | [16, 0x1021, true, true, 0x89EC, 0, 0x26B1, "CRC-16-TMS37157"], |
83 | 84 | [16, 0x8005, true, true, 0, ~0, 0xB4C8, "CRC-16-USB"], |
84 | - [16, 0x1021, true, true, 0xC6C6, 0, 0xBF05, "CRC-A", "CRC-16-ISO/IEC FCD 14443-3"], | |
85 | - [16, 0x1021, true, true, 0, 0, 0x2189, "KERMIT", "CRC-16-CCITT", "CRC-16-CCITT-TRUE", "CRC-CCITT"], | |
86 | - [16, 0x8005, true, true, ~0, 0, 0x4B37, "MODBUS"], | |
87 | - [16, 0x1021, true, true, 0, ~0, 0x906E, "X-25", "CRC-16-IBM-SDLC", "CRC-16-ISO-HDLC", "CRC-B"], | |
88 | - [16, 0x1021, false, false, 0, 0, 0x31C3, "XMODEM", "ZMODEM", "CRC-16-ACORN", "CRC-16-LTE"], | |
89 | - [17, 0x0001685B, false, false, 0, 0, nil, "CRC-17-CAN"], | |
90 | - [21, 0x00102899, false, false, 0, 0, nil, "CRC-21-CAN"], | |
91 | - [24, 0x005D6DCB, false, false, 0, 0, nil, "CRC-24"], | |
85 | + [16, 0x1021, true, true, 0xC6C6, 0, 0xBF05, "CRC-16-A", "CRC-A", "CRC-16-ISO/IEC FCD 14443-3"], | |
86 | + [16, 0x1021, true, true, 0, 0, 0x2189, "CRC-16-KERMIT", "KERMIT", "CRC-16-CCITT", "CRC-16-CCITT-TRUE", "CRC-CCITT"], | |
87 | + [16, 0x8005, true, true, ~0, 0, 0x4B37, "CRC-16-MODBUS", "MODBUS"], | |
88 | + [16, 0x1021, true, true, 0, ~0, 0x906E, "CRC-16-X-25", "X-25", "CRC-16-IBM-SDLC", "CRC-16-ISO-HDLC", "CRC-16-CRC-B", "CRC-B"], | |
89 | + [16, 0x1021, false, false, 0, 0, 0x31C3, "CRC-16-XMODEM", "XMODEM", "CRC-16-ZMODEM", "ZMODEM", "CRC-16-ACORN", "CRC-16-LTE"], | |
90 | + #[17, 0x0001685B, false, false, 0, 0, nil, "CRC-17-CAN"], | |
91 | + #[21, 0x00102899, false, false, 0, 0, nil, "CRC-21-CAN"], | |
92 | + #[24, 0x005D6DCB, false, false, 0, 0, nil, "CRC-24"], | |
92 | 93 | [24, 0x00864CFB, false, false, 0, 0, 0x00CDE703, "CRC-24-Radix-64"], |
93 | 94 | [24, 0x00864CFB, false, false, 0x00B704CE, 0, 0x0021CF02, "CRC-24-OPENPGP"], |
94 | 95 | [24, 0x0000065B, true, true, 0x00555555, 0, 0x00C25A56, "CRC-24-BLE"], |
@@ -97,25 +98,25 @@ | ||
97 | 98 | [24, 0x00328B63, false, false, 0, ~0, 0x00B4F3E6, "CRC-24-INTERLAKEN"], |
98 | 99 | [24, 0x00864CFB, false, false, 0, 0, 0x00CDE703, "CRC-24-LTE-A"], |
99 | 100 | [24, 0x00800063, false, false, 0, 0, 0x0023EF52, "CRC-24-LTE-B"], |
100 | - [30, 0x2030B9C7, false, false, 0, 0, nil, "CRC-30"], | |
101 | + #[30, 0x2030B9C7, false, false, 0, 0, nil, "CRC-30"], | |
101 | 102 | [30, 0x2030B9C7, false, false, 0, ~0, 0x04C34ABF, "CRC-30-CDMA"], |
102 | 103 | [31, 0x04C11DB7, false, false, 0, ~0, 0x0CE9E46C, "CRC-31-PHILIPS"], |
103 | - [32, 0x04C11DB7, true, true, 0, ~0, 0xCBF43926, "CRC-32", "CRC-32-ADCCP", "PKZIP", "CRC-32-PKZIP"], | |
104 | + [32, 0x04C11DB7, true, true, 0, ~0, 0xCBF43926, "CRC-32", "CRC-32-ADCCP", "CRC-32-PKZIP", "PKZIP"], | |
104 | 105 | [32, 0x04C11DB7, false, false, 0, ~0, 0xFC891918, "CRC-32-BZIP2", "CRC-32-AAL5", "CRC-32-DECT-B", "B-CRC-32"], |
105 | 106 | [32, 0x1EDC6F41, true, true, 0, ~0, 0xE3069283, "CRC-32C", "CRC-32-ISCSI", "CRC-32-CASTAGNOLI", "CRC-32-INTERLAKEN"], |
106 | 107 | [32, 0xa833982b, true, true, 0, ~0, 0x87315576, "CRC-32D"], |
107 | 108 | [32, 0x04C11DB7, false, false, ~0, 0, 0x0376E6E7, "CRC-32-MPEG-2"], |
108 | 109 | [32, 0x04C11DB7, false, false, ~0, ~0, 0x765E7680, "CRC-32-POSIX", "CKSUM"], |
109 | - [32, 0x741B8CD7, true, true, 0, ~0, nil, "CRC-32K"], | |
110 | - [32, 0x32583499, true, true, 0, ~0, nil, "CRC-32K2"], | |
110 | + #[32, 0x741B8CD7, true, true, 0, ~0, nil, "CRC-32K"], | |
111 | + #[32, 0x32583499, true, true, 0, ~0, nil, "CRC-32K2"], | |
111 | 112 | [32, 0x814141AB, false, false, 0, 0, 0x3010BF7F, "CRC-32Q"], |
112 | - [32, 0x04C11DB7, true, true, ~0, 0, 0x340BC6D9, "JAMCRC", "CRC-32-JAMCRC"], | |
113 | - [32, 0x000000AF, false, false, 0, 0, 0xBD0BE338, "XFER", "CRC-32-XFER"], | |
113 | + [32, 0x04C11DB7, true, true, ~0, 0, 0x340BC6D9, "CRC-32-JAMCRC", "JAMCRC"], | |
114 | + [32, 0x000000AF, false, false, 0, 0, 0xBD0BE338, "CRC-32-XFER", "XFER"], | |
114 | 115 | [40, 0x0004820009, false, false, ~0, ~0, 0xD4164FC646, "CRC-40-GSM"], |
115 | - [64, 0x42F0E1EBA9EA3693, true, true, 0, ~0, 0x995DC9BBDF1939FA, "CRC-64", "CRC-64-XZ"], | |
116 | + [64, 0x42F0E1EBA9EA3693, true, true, 0, ~0, 0x995DC9BBDF1939FA, "CRC-64-XZ", "CRC-64"], | |
116 | 117 | [64, 0x42F0E1EBA9EA3693, false, false, 0, 0, 0x6C40DF5F0B497347, "CRC-64-ECMA", "CRC-64-ECMA-182"], |
117 | 118 | [64, 0x42F0E1EBA9EA3693, false, false, 0, ~0, 0x62EC59E3F1A4F00A, "CRC-64-WE"], |
118 | - [64, 0x000000000000001B, false, false, 0, 0, nil, "CRC-64-ISO"], | |
119 | + [64, 0x000000000000001B, true, true, 0, 0, 0x46A5A9388A5BEFFE, "CRC-64-ISO", "CRC-64-ISO-3309"], | |
119 | 120 | # [82, 0x308C0111011401440411, true, true, 0, 0, 0x9EA83F625023801FD612, "CRC-82/DARC"], |
120 | 121 | ] |
121 | 122 | end |
@@ -1,6 +1,8 @@ | ||
1 | +#!ruby | |
2 | + | |
1 | 3 | require_relative "../crc" |
2 | 4 | |
3 | -module CRC | |
5 | +class CRC | |
4 | 6 | def self.find(crc, seq, bitsize, polynomial, initstate = [0, ~0, 1], xor = [0, ~0, 1]) |
5 | 7 | bitsize0 = bitsize.to_i |
6 | 8 | if bitsize0 < 1 || bitsize0 > 128 |
@@ -10,8 +12,6 @@ | ||
10 | 12 | crc &= bitmask |
11 | 13 | results = [] |
12 | 14 | poly = Array(polynomial) |
13 | - #poly += poly.map { |po| Utils.bitreflect(po, bitsize0) } | |
14 | - #poly.uniq! | |
15 | 15 | poly.each do |poly| |
16 | 16 | poly &= bitmask |
17 | 17 | [false, true].each do |refin| |
@@ -20,7 +20,7 @@ | ||
20 | 20 | xormask &= bitmask |
21 | 21 | Array(initstate).each do |init| |
22 | 22 | init &= bitmask |
23 | - mod = CRC.create_module(bitsize0, poly, init, refin, refout, xormask) | |
23 | + mod = CRC.new(bitsize0, poly, init, refin, refout, xormask) | |
24 | 24 | results << mod if mod.crc(seq) == crc |
25 | 25 | end |
26 | 26 | end |
@@ -0,0 +1,195 @@ | ||
1 | +#!ruby | |
2 | + | |
3 | +require_relative "../crc" | |
4 | + | |
5 | +class CRC | |
6 | + module ModuleClass | |
7 | + # | |
8 | + # call-seq: | |
9 | + # acrc(crc, rest_seq = nil, target_crc = 0) -> byte string as arc-code | |
10 | + # | |
11 | + # 目的となる crc になるように、指定された crc に続くバイト列を逆算します。 | |
12 | + # | |
13 | + # 出力されるバイト列は、crc のビット数を表現できるバイト数となります。 | |
14 | + # | |
15 | + # 現在のところ、reflect-input/output 限定となっています。 | |
16 | + # | |
17 | + # * crc32("123456789????") の結果が 0 となるような、???? の部分を逆算する | |
18 | + # | |
19 | + # seq = "123456789" | |
20 | + # seq << CRC::CRC32.acrc(seq) | |
21 | + # p CRC::CRC32[seq] # => #<CRC::CRC32:00000000> | |
22 | + # | |
23 | + # * crc32("123456789????ABCDEFG") の結果が 0 となるような、???? の部分を逆算する | |
24 | + # | |
25 | + # seq1 = "123456789" | |
26 | + # seq2 = "ABCDEFG" | |
27 | + # seq = seq1 + CRC::CRC32.acrc(seq1, seq2) + seq2 | |
28 | + # p CRC::CRC32[seq] # => #<CRC::CRC32:00000000> | |
29 | + # | |
30 | + # * crc32("123456789????ABCDEFG") の結果が 0x12345678 となるような、???? の部分を逆算する | |
31 | + # | |
32 | + # seq1 = "123456789" | |
33 | + # seq2 = "ABCDEFG" | |
34 | + # target_crc = 0x12345678 | |
35 | + # seq = seq1 + CRC::CRC32.acrc(seq1, seq2, target_crc) + seq2 | |
36 | + # p CRC::CRC32[seq] # => #<CRC::CRC32:12345678> | |
37 | + # | |
38 | + def acrc(crc, rest_seq = nil, target_crc = 0) | |
39 | + raise NotImplementedError, "crc polynomial is not odd" unless polynomial.odd? | |
40 | + raise NotImplementedError, "crc module is not reflect input and output" unless reflect_input? && reflect_output? | |
41 | + | |
42 | + bitsize = self.bitsize | |
43 | + poly = CRC.bitreflect(polynomial, bitsize) | |
44 | + target_crc = target_crc.to_i | |
45 | + target_crc ^= xor_output | |
46 | + | |
47 | + if rest_seq | |
48 | + rest_seq.bytesize.downto(1) do |i| | |
49 | + target_crc = Aux.acrc_loop_reflect(target_crc, rest_seq.getbyte(i - 1), poly, bitsize, 0xff, 8) | |
50 | + end | |
51 | + end | |
52 | + | |
53 | + bytes = (bitsize + 7) / 8 | |
54 | + bits = bytes * 8 | |
55 | + | |
56 | + case crc | |
57 | + when Numeric | |
58 | + state = bitmask & crc ^ xor_output | |
59 | + when CRC | |
60 | + raise "different crc module (given %p(%p), expect %p)" % [crc, crc.class, self] unless variant?(crc) | |
61 | + state = crc.state | |
62 | + else | |
63 | + state = new(crc).state | |
64 | + end | |
65 | + | |
66 | + if bits > bitsize | |
67 | + # ビット数が 8 の境界にない場合、その隙間分を埋める。 | |
68 | + # 現在の実装では、最終結果のバイト列における最終バイト値の | |
69 | + # 上位ビットが 0 であるようにしている。 | |
70 | + pad = bits - bitsize | |
71 | + target_crc = Aux.acrc_loop_reflect(target_crc, 0, poly, bitsize, 0xff, pad) | |
72 | + end | |
73 | + | |
74 | + target_crc = Aux.acrc_loop_reflect(target_crc, state, poly, bitsize, bitmask, bitsize) | |
75 | + | |
76 | + bytes.times.reduce("") { |a, *| a << (target_crc & 0xff).chr(Encoding::BINARY); target_crc >>= 8; a } | |
77 | + end | |
78 | + end | |
79 | + | |
80 | + module Aux | |
81 | + def self.acrc_loop_reflect(target_crc, state, poly, crcbits, bitmask, bits) | |
82 | + head = bits - 1 | |
83 | + bitmask1 = bitmask >> 1 | |
84 | + crchead = crcbits - 1 | |
85 | + | |
86 | + #puts "target_crc=0b%016b, state=0b%016b, reversed-polynomial=0b%016b" % [target_crc, state, poly] | |
87 | + bits.times do |i| | |
88 | + if target_crc[crchead] == 0 | |
89 | + target_crc <<= 1 | |
90 | + else | |
91 | + target_crc ^= poly | |
92 | + target_crc <<= 1 | |
93 | + target_crc |= 0x01 | |
94 | + end | |
95 | + | |
96 | + target_crc ^= state[head] | |
97 | + #puts " 0_%016b ^ %d" % [target_crc, state[head]] | |
98 | + state = (state & bitmask1) << 1 | |
99 | + end | |
100 | + #puts "target_crc=0b%016b" % target_crc | |
101 | + | |
102 | + target_crc | |
103 | + end | |
104 | + end | |
105 | +end | |
106 | + | |
107 | +if $0 == __FILE__ | |
108 | + seq = "abcdefghijklmnopqrstuvwxyz" | |
109 | + seq2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
110 | + code = CRC::X_25.acrc(seq, seq2) | |
111 | + puts "base-crc=[%p, %p], arc'd-crc=%p, arc-code=%s" % [CRC::X_25[seq], CRC::X_25[seq2], CRC::X_25[seq + code + seq2], code.unpack("H*")[0]] | |
112 | + code = CRC::CRC32.acrc(seq, seq2) | |
113 | + puts "base-crc=[%p, %p], arc'd-crc=%p, arc-code=%s" % [CRC::CRC32[seq], CRC::CRC32[seq2], CRC::CRC32[seq + code + seq2], code.unpack("H*")[0]] | |
114 | + code = CRC::CRC32C.acrc(seq, seq2) | |
115 | + puts "base-crc=[%p, %p], arc'd-crc=%p, arc-code=%s" % [CRC::CRC32C[seq], CRC::CRC32C[seq2], CRC::CRC32C[seq + code + seq2], code.unpack("H*")[0]] | |
116 | + | |
117 | + MyCRC = crcmod = CRC.new(32, rand(1<<32) | 1, rand(1<<32) | 1, true, true, rand(1<<32) | 1) | |
118 | + 20.times do |i| | |
119 | + s = (10+rand(20)).times.reduce("") { |a, *| a << rand(256).chr(Encoding::BINARY) } | |
120 | + t = (10+rand(20)).times.reduce("") { |a, *| a << rand(256).chr(Encoding::BINARY) } | |
121 | + crc = crcmod.new(s) | |
122 | + puts "crc=[%p, %p], arc'd-crc=%p, target=%08X, seq=%s" % | |
123 | + [crc, crcmod[t], crcmod.new(s + crcmod.acrc(crc.crc, t, i * 9929) + t), i * 9929, s.unpack("H*")[0]] | |
124 | + end | |
125 | +end | |
126 | + | |
127 | +__END__ | |
128 | + | |
129 | +目的となる CRC 値を逆算して、特定のバイト列を得る機能です。 | |
130 | + | |
131 | +ただの思いつきで、crc すると結果が 0 になるバイト列を計算できないかなと遊んでみた結果、 | |
132 | +それなりの形となってしまいました。 | |
133 | + | |
134 | +以下は acrc メソッドとして実装した、その仕組みとなります。 | |
135 | + | |
136 | + | |
137 | +X-25{CRC-16-0x1021 ref-in/out xor=0xffff} を用いた場合 | |
138 | + | |
139 | +("abcdefghijklmnopqrstuvwxyz" + ??) を CRC して結果を 0 にしたい (?? は2バイト)。 | |
140 | + | |
141 | +この時の ?? を求める。 | |
142 | + | |
143 | +先に "abcdefghijklmnopqrstuvwxyz" までの CRC を求めておく => 0x0d43 | |
144 | + | |
145 | +(ここまでの内部状態は 0xf2bc) ?? <STOP> (この段階で内部状態が 0xffff であること) | |
146 | + | |
147 | +内部状態の最上位ビットから順に送って、目的となる内部状態が 0xffff から 0xf2bc になるような値を逆算する | |
148 | + | |
149 | + | |
150 | +code = 0 # 最終的に求めたい CRC | |
151 | +state = 0b1111001010111100 # 現在の CRC 生成器の内部状態 | |
152 | +reversed_polynomial = 0b1000010000001000 | |
153 | + | |
154 | + 1. 最終的に求めたい CRC と xor_output する | |
155 | + 1111111111111111 | |
156 | + | |
157 | + 2. この時、code の最上位ビットが1なので、poly (reversed) で xor する | |
158 | + 最上位ビットが0ならば何もしない | |
159 | + 0111101111110111 | |
160 | + | |
161 | + 3. 左にずらす | |
162 | + 1111011111101110 | |
163 | + | |
164 | + 4. (2) において poly-reversed で xor したため、最下位ビットを1にする | |
165 | + (2) を行わなかった場合は何もしない | |
166 | + 1111011111101111 | |
167 | + | |
168 | + 5. 目的となる内部状態の最上位ビットと作業内部状態の最下位ビットを xor した時に 1 となるように調整する | |
169 | + (2) を行わなかった場合は 0 を維持するように処置する | |
170 | + 1111011111101110 | |
171 | + | |
172 | + 6. 1 ビット目の処理が完了。(2) に戻って必要なだけ繰り返す | |
173 | + | |
174 | + 1111011111101110 <= 1 ## 最上位から2ビット目を入力 | |
175 | + 1110011111001100 <= 1 ## 最上位から3ビット目を入力 | |
176 | + 1100011110001000 <= 1 ## 以下同様に…… | |
177 | + 1000011100000000 <= 0 | |
178 | + 0000011000010001 <= 0 | |
179 | + 0000110000100010 <= 1 | |
180 | + 0001100001000101 <= 0 | |
181 | + 0011000010001010 <= 1 | |
182 | + 0110000100010101 <= 0 | |
183 | + 1100001000101010 <= 1 | |
184 | + 1000110001000100 <= 1 | |
185 | + 0001000010011000 <= 1 | |
186 | + 0010000100110001 <= 1 | |
187 | + 0100001001100011 <= 0 | |
188 | + 1000010011000110 <= 0 | |
189 | + 0000000110011101 ## 繰り返して得られた結果 | |
190 | + この結果を元にして、バイト順を入れ替える | |
191 | + (CRC として求める場合に、下位から入力されるため) | |
192 | + | |
193 | + 10011101:00000001 >>>> [0x9d, 0x01] が返る | |
194 | + | |
195 | +[EOF] |
@@ -9,7 +9,7 @@ | ||
9 | 9 | # \* \* \* \* \* \* \* \* |
10 | 10 | # |
11 | 11 | # Ruby implemented CRC generator. |
12 | -# It's used slice-by-16 algorithm with byte-order free and byte-alignment free. | |
12 | +# It's used slice-by-16 algorithm with byte-order free. | |
13 | 13 | # This is based on the Intel's slice-by-eight algorithm. |
14 | 14 | # |
15 | 15 | # It's faster than about 50% (CRC-32) and about 30% (CRC-64) of |
@@ -26,69 +26,46 @@ | ||
26 | 26 | # |
27 | 27 | # If defined "RUBY_CRC_NOFAST=3" enviroment variable, switch to reference algorithm. |
28 | 28 | # |
29 | -module CRC | |
30 | - module Utils | |
31 | - def bitreflect8(n) | |
32 | - n = n.to_i | |
33 | - n = ((n & 0x55) << 1) | ((n >> 1) & 0x55) | |
34 | - n = ((n & 0x33) << 2) | ((n >> 2) & 0x33) | |
35 | - return ((n & 0x0f) << 4) | (n >> 4) # 0x0f | |
36 | - end | |
37 | - | |
38 | - def bitreflect16(n) | |
39 | - n = n.to_i | |
40 | - n = ((n & 0x5555) << 1) | ((n >> 1) & 0x5555) | |
41 | - n = ((n & 0x3333) << 2) | ((n >> 2) & 0x3333) | |
42 | - n = ((n & 0x0f0f) << 4) | ((n >> 4) & 0x0f0f) | |
43 | - return ((n & 0x00ff) << 8) | (n >> 8) # 0x00ff | |
44 | - end | |
45 | - | |
46 | - def bitreflect32(n) | |
47 | - n = n.to_i | |
48 | - n = ((n & 0x55555555) << 1) | ((n >> 1) & 0x55555555) | |
49 | - n = ((n & 0x33333333) << 2) | ((n >> 2) & 0x33333333) | |
50 | - n = ((n & 0x0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f) | |
51 | - n = ((n & 0x00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff) | |
52 | - return ((n & 0x0000ffff) << 16) | (n >> 16) # 0x0000ffff | |
53 | - end | |
54 | - | |
55 | - def bitreflect64(n) | |
56 | - n = n.to_i | |
57 | - n = ((n & 0x5555555555555555) << 1) | ((n >> 1) & 0x5555555555555555) | |
58 | - n = ((n & 0x3333333333333333) << 2) | ((n >> 2) & 0x3333333333333333) | |
59 | - n = ((n & 0x0f0f0f0f0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f0f0f0f0f) | |
60 | - n = ((n & 0x00ff00ff00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff00ff00ff) | |
61 | - n = ((n & 0x0000ffff0000ffff) << 16) | ((n >> 16) & 0x0000ffff0000ffff) | |
62 | - return ((n & 0x00000000ffffffff) << 32) | (n >> 32) # 0x00000000ffffffff | |
63 | - end | |
64 | - | |
65 | - def bitreflect128(n) | |
66 | - n = n.to_i | |
67 | - n = ((n & 0x55555555555555555555555555555555) << 1) | ((n >> 1) & 0x55555555555555555555555555555555) | |
68 | - n = ((n & 0x33333333333333333333333333333333) << 2) | ((n >> 2) & 0x33333333333333333333333333333333) | |
69 | - n = ((n & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f) | |
70 | - n = ((n & 0x00ff00ff00ff00ff00ff00ff00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff00ff00ff00ff00ff00ff00ff) | |
71 | - n = ((n & 0x0000ffff0000ffff0000ffff0000ffff) << 16) | ((n >> 16) & 0x0000ffff0000ffff0000ffff0000ffff) | |
72 | - n = ((n & 0x00000000ffffffff00000000ffffffff) << 32) | ((n >> 32) & 0x00000000ffffffff00000000ffffffff) | |
73 | - return ((n & 0x0000000000000000ffffffffffffffff) << 64) | (n >> 64) # 0x0000000000000000ffffffffffffffff | |
74 | - end | |
75 | - end | |
76 | - | |
77 | - class Generator < Struct.new(:bitsize, :bitmask, :polynomial, :initial_state, :table, :reflect_input, :reflect_output, :xor_output, :name) | |
78 | - BasicStruct = superclass | |
79 | - | |
80 | - def initialize(bitsize, polynomial, initial_state = 0, reflect_input = true, reflect_output = true, xor_output = ~0, name = nil) | |
29 | +class CRC | |
30 | + class << self | |
31 | + # | |
32 | + # call-seq: | |
33 | + # new(bitsize, polynomial, initial_crc = 0, reflect_input = true, reflect_output = true, xor_output = ~0, name = nil) -> new crc module class (CRC based class) | |
34 | + # new(initial_crc = nil, size = 0) -> new crc generator (CRC instance) | |
35 | + # new(seq, initial_crc = nil, size = 0) -> new crc generator (CRC instance) | |
36 | + # | |
37 | + def new(bitsize, polynomial, initial_crc = 0, reflect_input = true, reflect_output = true, xor_output = ~0, name = nil) | |
81 | 38 | bitsize = bitsize.to_i |
82 | 39 | if bitsize < 1 || bitsize > 64 |
83 | 40 | raise ArgumentError, "wrong bitsize (except 1..64, but given #{bitsize})" |
84 | 41 | end |
42 | + | |
85 | 43 | bitmask = ~(~0 << bitsize) |
86 | 44 | polynomial = bitmask & polynomial |
87 | - initial_state = bitmask & initial_state | |
45 | + initial_crc = bitmask & initial_crc | |
88 | 46 | xor_output = bitmask & xor_output |
89 | 47 | name = (name.nil? || ((name = String(name)).empty?)) ? nil : name |
90 | - super(bitsize, bitmask, polynomial, initial_state, nil, | |
91 | - !!reflect_input, !!reflect_output, xor_output, name) | |
48 | + | |
49 | + ::Class.new(self) do | |
50 | + @bitsize = bitsize | |
51 | + @bitmask = bitmask | |
52 | + @polynomial = polynomial | |
53 | + @initial_crc = initial_crc | |
54 | + @table = nil | |
55 | + @reflect_input = !!reflect_input | |
56 | + @reflect_output = !!reflect_output | |
57 | + @xor_output = xor_output | |
58 | + @name = name | |
59 | + | |
60 | + # CRC クラスを普通に派生させた場合でも、CRC.new の基底メソッドが呼ばれるための細工 | |
61 | + define_singleton_method(:new, &Class.instance_method(:new).bind(self)) | |
62 | + | |
63 | + singleton_class.class_eval do | |
64 | + alias_method :[], :new | |
65 | + end | |
66 | + | |
67 | + extend CRC::ModuleClass | |
68 | + end | |
92 | 69 | end |
93 | 70 | |
94 | 71 | def update_with_reference(seq, state) |
@@ -204,14 +181,14 @@ | ||
204 | 181 | |
205 | 182 | def table |
206 | 183 | if reflect_input |
207 | - set_table t = CRC.build_reflect_table(bitsize, polynomial, slice: 16) | |
184 | + @table = CRC.build_reflect_table(bitsize, polynomial, slice: 16) | |
208 | 185 | else |
209 | - set_table t = CRC.build_table(bitsize, polynomial, slice: 16) | |
186 | + @table = CRC.build_table(bitsize, polynomial, slice: 16) | |
210 | 187 | end |
211 | 188 | |
212 | - define_singleton_method :table, self.class.superclass.instance_method(:table) | |
189 | + singleton_class.class_eval "attr_reader :table" | |
213 | 190 | |
214 | - t | |
191 | + @table | |
215 | 192 | end |
216 | 193 | |
217 | 194 | case ENV["RUBY_CRC_NOFAST"].to_i |
@@ -222,13 +199,60 @@ | ||
222 | 199 | else |
223 | 200 | alias update update_with_reference |
224 | 201 | end |
202 | + end | |
225 | 203 | |
226 | - class BasicStruct | |
227 | - alias set_table table= | |
228 | - private :set_table | |
204 | + module ModuleClass | |
205 | + attr_reader :bitsize, :bitmask, :polynomial, :initial_crc, | |
206 | + :reflect_input, :reflect_output, :xor_output, :name | |
229 | 207 | |
230 | - undef :bitsize=, :bitmask=, :polynomial=, :initial_state=, :table=, | |
231 | - :reflect_input=, :reflect_output=, :xor_output=, :name=, :[]= | |
208 | + alias reflect_input? reflect_input | |
209 | + alias reflect_output? reflect_output | |
210 | + end | |
211 | + | |
212 | + module Utils | |
213 | + def bitreflect8(n) | |
214 | + n = n.to_i | |
215 | + n = ((n & 0x55) << 1) | ((n >> 1) & 0x55) | |
216 | + n = ((n & 0x33) << 2) | ((n >> 2) & 0x33) | |
217 | + return ((n & 0x0f) << 4) | (n >> 4) # 0x0f | |
232 | 218 | end |
219 | + | |
220 | + def bitreflect16(n) | |
221 | + n = n.to_i | |
222 | + n = ((n & 0x5555) << 1) | ((n >> 1) & 0x5555) | |
223 | + n = ((n & 0x3333) << 2) | ((n >> 2) & 0x3333) | |
224 | + n = ((n & 0x0f0f) << 4) | ((n >> 4) & 0x0f0f) | |
225 | + return ((n & 0x00ff) << 8) | (n >> 8) # 0x00ff | |
226 | + end | |
227 | + | |
228 | + def bitreflect32(n) | |
229 | + n = n.to_i | |
230 | + n = ((n & 0x55555555) << 1) | ((n >> 1) & 0x55555555) | |
231 | + n = ((n & 0x33333333) << 2) | ((n >> 2) & 0x33333333) | |
232 | + n = ((n & 0x0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f) | |
233 | + n = ((n & 0x00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff) | |
234 | + return ((n & 0x0000ffff) << 16) | (n >> 16) # 0x0000ffff | |
235 | + end | |
236 | + | |
237 | + def bitreflect64(n) | |
238 | + n = n.to_i | |
239 | + n = ((n & 0x5555555555555555) << 1) | ((n >> 1) & 0x5555555555555555) | |
240 | + n = ((n & 0x3333333333333333) << 2) | ((n >> 2) & 0x3333333333333333) | |
241 | + n = ((n & 0x0f0f0f0f0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f0f0f0f0f) | |
242 | + n = ((n & 0x00ff00ff00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff00ff00ff) | |
243 | + n = ((n & 0x0000ffff0000ffff) << 16) | ((n >> 16) & 0x0000ffff0000ffff) | |
244 | + return ((n & 0x00000000ffffffff) << 32) | (n >> 32) # 0x00000000ffffffff | |
245 | + end | |
246 | + | |
247 | + def bitreflect128(n) | |
248 | + n = n.to_i | |
249 | + n = ((n & 0x55555555555555555555555555555555) << 1) | ((n >> 1) & 0x55555555555555555555555555555555) | |
250 | + n = ((n & 0x33333333333333333333333333333333) << 2) | ((n >> 2) & 0x33333333333333333333333333333333) | |
251 | + n = ((n & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f) << 4) | ((n >> 4) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f) | |
252 | + n = ((n & 0x00ff00ff00ff00ff00ff00ff00ff00ff) << 8) | ((n >> 8) & 0x00ff00ff00ff00ff00ff00ff00ff00ff) | |
253 | + n = ((n & 0x0000ffff0000ffff0000ffff0000ffff) << 16) | ((n >> 16) & 0x0000ffff0000ffff0000ffff0000ffff) | |
254 | + n = ((n & 0x00000000ffffffff00000000ffffffff) << 32) | ((n >> 32) & 0x00000000ffffffff00000000ffffffff) | |
255 | + return ((n & 0x0000000000000000ffffffffffffffff) << 64) | (n >> 64) # 0x0000000000000000ffffffffffffffff | |
256 | + end | |
233 | 257 | end |
234 | 258 | end |
@@ -33,7 +33,7 @@ | ||
33 | 33 | # License:: zlib-style |
34 | 34 | #-- |
35 | 35 | |
36 | -module CRC | |
36 | +class CRC | |
37 | 37 | module Aux |
38 | 38 | def self.gf2_matrix_times(matrix, vector) |
39 | 39 | sum = 0 |
@@ -53,13 +53,13 @@ | ||
53 | 53 | |
54 | 54 | nil |
55 | 55 | end |
56 | - end | |
57 | 56 | |
58 | - class Generator | |
59 | - def combine(crc1, crc2, len2) | |
57 | + def self.combine(crc1, crc2, len2, | |
58 | + bitsize, polynomial, initial_crc, | |
59 | + reflect_input, reflect_output, xor_output) | |
60 | 60 | return crc1 unless len2 > 1 |
61 | 61 | |
62 | - crc1 ^= initial_state | |
62 | + crc1 ^= initial_crc | |
63 | 63 | |
64 | 64 | odd = [] |
65 | 65 | even = [] |
@@ -10,6 +10,8 @@ | ||
10 | 10 | end |
11 | 11 | end |
12 | 12 | |
13 | +require_relative "crc/version" | |
14 | + | |
13 | 15 | # |
14 | 16 | # This is a general CRC generator. |
15 | 17 | # |
@@ -30,15 +32,18 @@ | ||
30 | 32 | # crc32 << s |
31 | 33 | # end |
32 | 34 | # p crc32 # => #<CRC::CRC32:6A632AA5> |
33 | -# p crc32.state # => 1784883877 | |
35 | +# p crc32.crc # => 1784883877 | |
34 | 36 | # p crc32.digest # => "jc*\xA5" |
35 | 37 | # p crc32.hexdigest # => "6A632AA5" |
36 | 38 | # |
37 | -module CRC | |
39 | +class CRC | |
38 | 40 | CRC = self |
39 | 41 | |
40 | 42 | extend Utils |
41 | 43 | |
44 | + # | |
45 | + # Utilities. | |
46 | + # | |
42 | 47 | module Utils |
43 | 48 | extend self |
44 | 49 |
@@ -141,20 +146,23 @@ | ||
141 | 146 | |
142 | 147 | extend Utils |
143 | 148 | |
149 | + # | |
150 | + # Internal using module. | |
151 | + # | |
144 | 152 | module Aux |
145 | - def self.DIGEST(state, bitsize) | |
153 | + def self.DIGEST(num, bitsize) | |
146 | 154 | bits = (bitsize + 7) / 8 * 8 |
147 | - seq = "".b | |
148 | - (bits - 8).step(0, -8) { |i| seq << yield((state >> i) & 0xff) } | |
155 | + seq = "" | |
156 | + (bits - 8).step(0, -8) { |i| seq << yield((num >> i) & 0xff) } | |
149 | 157 | seq |
150 | 158 | end |
151 | 159 | |
152 | - def self.digest(state, bitsize) | |
153 | - DIGEST(state, bitsize) { |n| [n].pack("C") } | |
160 | + def self.digest(num, bitsize) | |
161 | + DIGEST(num, bitsize) { |n| n.chr(Encoding::BINARY) } | |
154 | 162 | end |
155 | 163 | |
156 | - def self.hexdigest(state, bitsize) | |
157 | - DIGEST(state, bitsize) { |n| "%02X" % n } | |
164 | + def self.hexdigest(num, bitsize) | |
165 | + DIGEST(num, bitsize) { |n| "%02X" % n } | |
158 | 166 | end |
159 | 167 | |
160 | 168 | # |
@@ -174,35 +182,76 @@ | ||
174 | 182 | end |
175 | 183 | end |
176 | 184 | |
177 | - class Generator | |
178 | - def crc(seq, state = nil) | |
179 | - finish(update(seq, setup(state))) | |
185 | + module ModuleClass | |
186 | + def setup(crc = nil) | |
187 | + crc ||= initial_crc | |
188 | + crc = CRC.bitreflect(crc, bitsize) if reflect_input? ^ reflect_output? | |
189 | + crc ^ xor_output | |
180 | 190 | end |
181 | 191 | |
182 | - def setup(state = nil) | |
183 | - state ||= initial_state | |
184 | - state = CRC.bitreflect(state, bitsize) if reflect_input ^ reflect_output | |
185 | - state ^ xor_output | |
186 | - end | |
192 | + alias init setup | |
187 | 193 | |
188 | 194 | def finish(state) |
189 | - state = CRC.bitreflect(state, bitsize) if reflect_input ^ reflect_output | |
195 | + state = CRC.bitreflect(state, bitsize) if reflect_input? ^ reflect_output? | |
190 | 196 | state ^ xor_output |
191 | 197 | end |
192 | 198 | |
193 | - alias reflect_input? reflect_input | |
194 | - alias reflect_output? reflect_output | |
199 | + def crc(seq, crc = nil) | |
200 | + finish(update(seq, setup(crc))) | |
201 | + end | |
195 | 202 | |
196 | - def digest(seq, state = nil) | |
197 | - Aux.digest(crc(seq, state), bitsize) | |
203 | + def digest(seq, crc = nil) | |
204 | + Aux.digest(crc(seq, crc), bitsize) | |
198 | 205 | end |
199 | 206 | |
200 | - def hexdigest(seq, state = nil) | |
201 | - Aux.hexdigest(crc(seq, state), bitsize) | |
207 | + def hexdigest(seq, crc = nil) | |
208 | + Aux.hexdigest(crc(seq, crc), bitsize) | |
202 | 209 | end |
203 | 210 | |
204 | - def to_s | |
211 | + def variant?(obj) | |
205 | 212 | case |
213 | + when obj.kind_of?(CRC) | |
214 | + mod = obj.class | |
215 | + when obj.kind_of?(Class) && obj < CRC | |
216 | + mod = obj | |
217 | + else | |
218 | + return false | |
219 | + end | |
220 | + | |
221 | + if bitsize == mod.bitsize && | |
222 | + polynomial == mod.polynomial && | |
223 | + reflect_input? == mod.reflect_input? && | |
224 | + reflect_output? == mod.reflect_output? && | |
225 | + xor_output == mod.xor_output | |
226 | + true | |
227 | + else | |
228 | + false | |
229 | + end | |
230 | + end | |
231 | + | |
232 | + # | |
233 | + # call-seq: | |
234 | + # combine(crc1, crc2) -> new combined crc | |
235 | + # combine(crc1_int, crc2_int, crc2_len) -> new combined crc | |
236 | + # | |
237 | + def combine(*args) | |
238 | + case args.size | |
239 | + when 2 | |
240 | + unless args[0].kind_of?(CRC) && args[1].kind_of?(CRC) | |
241 | + raise ArgumentError, "When given two arguments, both arguments are should be CRC instance" | |
242 | + end | |
243 | + | |
244 | + crc1 + crc2 | |
245 | + when 3 | |
246 | + Aux.combine(Integer(args[0].to_i), Integer(args[1].to_i), Integer(args[2].to_i), | |
247 | + bitsize, polynomial, initial_crc, reflect_input?, reflect_output?, xor_output) | |
248 | + else | |
249 | + raise ArgumentError, "wrong number of arguments (given #{args.size}, expect 2..3)" | |
250 | + end | |
251 | + end | |
252 | + | |
253 | + def to_str | |
254 | + case | |
206 | 255 | when bitsize > 64 then width = 20 |
207 | 256 | when bitsize > 32 then width = 16 |
208 | 257 | when bitsize > 16 then width = 8 |
@@ -210,17 +259,17 @@ | ||
210 | 259 | else width = 2 |
211 | 260 | end |
212 | 261 | |
213 | - if reflect_input | |
214 | - ref = ", reflect-in#{reflect_output ? "/out" : ""}" | |
262 | + if reflect_input? | |
263 | + ref = " reflect-in#{reflect_output? ? "/out" : ""}" | |
215 | 264 | else |
216 | - ref = reflect_output ? ", reflect-out" : "" | |
265 | + ref = reflect_output? ? " reflect-out" : "" | |
217 | 266 | end |
218 | 267 | |
219 | - case initial_state | |
268 | + case initial_crc | |
220 | 269 | when 0 then init = "0" |
221 | 270 | when bitmask then init = "~0" |
222 | 271 | when 1 then init = "1" |
223 | - else init = "0x%0#{width}X" % initial_state | |
272 | + else init = "0x%0#{width}X" % initial_crc | |
224 | 273 | end |
225 | 274 | |
226 | 275 | case xor_output |
@@ -230,15 +279,11 @@ | ||
230 | 279 | else xor = "0x%0#{width}X" % xor_output |
231 | 280 | end |
232 | 281 | |
233 | - if nm = name | |
234 | - "#{nm}(CRC-%d-0x%0#{width}X%s init=%s, xor=%s)" % [bitsize, polynomial, ref, init, xor] | |
235 | - else | |
236 | - "(CRC-%d-0x%0#{width}X%s init=%s, xor=%s)" % [bitsize, polynomial, ref, init, xor] | |
237 | - end | |
282 | + "CRC-%d-0x%0#{width}X%s init=%s xor=%s" % [bitsize, polynomial, ref, init, xor] | |
238 | 283 | end |
239 | 284 | |
240 | 285 | def inspect |
241 | - "\#<#{self.class} #{to_s}>" | |
286 | + "#{super}{#{to_str}}" | |
242 | 287 | end |
243 | 288 | |
244 | 289 | def pretty_inspect(q) |
@@ -246,189 +291,136 @@ | ||
246 | 291 | end |
247 | 292 | end |
248 | 293 | |
249 | - class BasicCRC < Struct.new(:internal_state, :initial_state, :size) | |
250 | - BasicStruct = superclass | |
294 | + attr_accessor :state, :size | |
251 | 295 | |
252 | - class BasicStruct | |
253 | - alias state! internal_state | |
254 | - alias set_state! internal_state= | |
296 | + # | |
297 | + # call-seq: | |
298 | + # initialize(initial_crc = nil, size = 0) | |
299 | + # initialize(seq, initial_crc = nil, size = 0) | |
300 | + # | |
301 | + def initialize(*args) | |
302 | + initialize_args(args) do |seq, initial_crc, size| | |
303 | + m = self.class | |
304 | + @state = m.setup((initial_crc || m.initial_crc).to_i) | |
305 | + @size = size.to_i | |
306 | + update(seq) if seq | |
255 | 307 | end |
308 | + end | |
256 | 309 | |
257 | - # | |
258 | - # call-seq: | |
259 | - # initialize(initial_state = nil, size = 0) | |
260 | - # initialize(seq, initial_state = nil, size = 0) | |
261 | - # | |
262 | - def initialize(*args) | |
263 | - initialize_args(args) do |seq, initial_state, size| | |
264 | - g = self.class::GENERATOR | |
265 | - initial_state ||= g.initial_state | |
266 | - super g.setup(initial_state.to_i), initial_state.to_i, size.to_i | |
267 | - update(seq) if seq | |
268 | - end | |
269 | - end | |
310 | + def reset(initial_crc = nil, size = 0) | |
311 | + m = self.class | |
312 | + @state = m.setup((initial_crc || m.initial_crc).to_i) | |
313 | + @size = size.to_i | |
314 | + self | |
315 | + end | |
270 | 316 | |
271 | - def reset(initial_state = self.initial_state, size = 0) | |
272 | - g = self.class::GENERATOR | |
273 | - initial_state ||= g.initial_state | |
274 | - set_state! g.setup(initial_state) | |
275 | - self.initial_state = initial_state | |
276 | - self.size = size.to_i | |
277 | - self | |
278 | - end | |
317 | + def update(seq) | |
318 | + @state = self.class.update(seq, state) | |
319 | + @size += seq.bytesize | |
320 | + self | |
321 | + end | |
279 | 322 | |
280 | - def update(seq) | |
281 | - set_state! self.class::GENERATOR.update(seq, state!) | |
282 | - self.size += seq.bytesize | |
283 | - self | |
284 | - end | |
323 | + alias << update | |
285 | 324 | |
286 | - alias << update | |
325 | + def crc | |
326 | + self.class.finish(state) | |
327 | + end | |
287 | 328 | |
288 | - def state | |
289 | - self.class::GENERATOR.finish(state!) | |
329 | + def +(crc2) | |
330 | + raise ArgumentError, "not a CRC instance (#{crc2.inspect})" unless crc2.kind_of?(CRC) | |
331 | + m1 = self.class | |
332 | + m2 = crc2.class | |
333 | + unless m1.bitsize == m2.bitsize && | |
334 | + m1.polynomial == m2.polynomial && | |
335 | + m1.reflect_input? == m2.reflect_input? && | |
336 | + m1.reflect_output? == m2.reflect_output? && | |
337 | + # m1.initial_crc == m2.initial_crc && | |
338 | + m1.xor_output == m2.xor_output | |
339 | + raise ArgumentError, "different CRC module (#{m1.inspect} and #{m2.inspect})" | |
290 | 340 | end |
341 | + m1.new(m1.combine(crc, crc2.crc, crc2.size), size + crc2.size) | |
342 | + end | |
291 | 343 | |
292 | - def +(crc2) | |
293 | - raise ArgumentError, "not a CRC instance (#{crc2.inspect})" unless crc2.kind_of?(BasicCRC) | |
294 | - c1 = self.class | |
295 | - g1 = c1::GENERATOR | |
296 | - g2 = crc2.class::GENERATOR | |
297 | - unless g1.bitsize == g2.bitsize && | |
298 | - g1.polynomial == g2.polynomial && | |
299 | - g1.reflect_input == g2.reflect_input && | |
300 | - g1.reflect_output == g2.reflect_output && | |
301 | - # g1.initial_state == g2.initial_state && | |
302 | - g1.xor_output == g2.xor_output | |
303 | - raise ArgumentError, "different CRC module (#{g1.inspect} and #{g2.inspect})" | |
304 | - end | |
305 | - c1.new(g1.combine(state, crc2.state, crc2.size), size + crc2.size) | |
306 | - end | |
307 | - | |
308 | - def ==(a) | |
309 | - case a | |
310 | - when BasicCRC | |
311 | - c1 = self.class | |
312 | - g1 = c1::GENERATOR | |
313 | - g2 = a.class::GENERATOR | |
314 | - if g1.bitsize == g2.bitsize && | |
315 | - g1.polynomial == g2.polynomial && | |
316 | - g1.reflect_input == g2.reflect_input && | |
317 | - g1.reflect_output == g2.reflect_output && | |
318 | - # g1.initial_state == g2.initial_state && | |
319 | - g1.xor_output == g2.xor_output && | |
320 | - state! == a.state! | |
321 | - true | |
322 | - else | |
323 | - false | |
324 | - end | |
325 | - when Integer | |
326 | - state == a | |
344 | + def ==(a) | |
345 | + case a | |
346 | + when CRC | |
347 | + m1 = self.class | |
348 | + m2 = a.class | |
349 | + if m1.bitsize == m2.bitsize && | |
350 | + m1.polynomial == m2.polynomial && | |
351 | + m1.reflect_input? == m2.reflect_input? && | |
352 | + m1.reflect_output? == m2.reflect_output? && | |
353 | + # m1.initial_crc == m2.initial_crc && | |
354 | + m1.xor_output == m2.xor_output && | |
355 | + state == a.state | |
356 | + true | |
327 | 357 | else |
328 | - super | |
358 | + false | |
329 | 359 | end |
360 | + when Integer | |
361 | + crc == a | |
362 | + else | |
363 | + super | |
330 | 364 | end |
365 | + end | |
331 | 366 | |
332 | - alias to_i state | |
333 | - alias to_int state | |
367 | + alias to_i crc | |
368 | + alias to_int crc | |
334 | 369 | |
335 | - def to_a | |
336 | - [state] | |
337 | - end | |
370 | + def to_a | |
371 | + [crc] | |
372 | + end | |
338 | 373 | |
339 | - def digest | |
340 | - Aux.DIGEST(state, self.class::GENERATOR.bitsize) { |n| [n].pack("C") } | |
341 | - end | |
374 | + def digest | |
375 | + Aux.digest(crc, self.class.bitsize) | |
376 | + end | |
342 | 377 | |
343 | - # return digest as internal state | |
344 | - def digest! | |
345 | - Aux.DIGEST(state!, self.class::GENERATOR.bitsize) { |n| [n].pack("C") } | |
346 | - end | |
378 | + # return digest as internal state | |
379 | + def digest! | |
380 | + Aux.digest(state, self.class.bitsize) | |
381 | + end | |
347 | 382 | |
348 | - def hexdigest | |
349 | - Aux.DIGEST(state, self.class::GENERATOR.bitsize) { |n| "%02X" % n } | |
350 | - end | |
383 | + def hexdigest | |
384 | + Aux.hexdigest(crc, self.class.bitsize) | |
385 | + end | |
351 | 386 | |
352 | - # return hex-digest as internal state | |
353 | - def hexdigest! | |
354 | - Aux.DIGEST(state!, self.class::GENERATOR.bitsize) { |n| "%02X" % n } | |
355 | - end | |
387 | + # return hex-digest as internal state | |
388 | + def hexdigest! | |
389 | + Aux.hexdigest(state, self.class.bitsize) | |
390 | + end | |
356 | 391 | |
357 | - alias to_str hexdigest | |
358 | - alias to_s hexdigest | |
392 | + alias to_str hexdigest | |
393 | + alias to_s hexdigest | |
359 | 394 | |
360 | - def inspect | |
361 | - "\#<#{self.class}:#{hexdigest}>" | |
362 | - end | |
395 | + def inspect | |
396 | + "\#<#{self.class}:#{hexdigest}>" | |
397 | + end | |
363 | 398 | |
364 | - def pretty_inspect(q) | |
365 | - q.text inspect | |
366 | - end | |
399 | + def pretty_inspect(q) | |
400 | + q.text inspect | |
401 | + end | |
367 | 402 | |
368 | - class << self | |
369 | - alias [] new | |
370 | - | |
371 | - # | |
372 | - # call-seq: | |
373 | - # combine(crc1, crc2) -> new combined crc | |
374 | - # combine(crc1_int, crc2_int, crc2_len) -> new combined crc | |
375 | - # | |
376 | - def combine(crc1, crc2, len2 = nil) | |
377 | - return crc1 + crc2 if crc1.kind_of?(BasicCRC) && crc2.kind_of?(BasicCRC) | |
378 | - self::GENERATOR.combine(crc1.to_i, crc2.to_i, len2) | |
403 | + private | |
404 | + def initialize_args(args) | |
405 | + case args.size | |
406 | + when 0 | |
407 | + yield nil, nil, 0 | |
408 | + when 1 | |
409 | + if args[0].kind_of?(String) | |
410 | + yield args[0], nil, 0 | |
411 | + else | |
412 | + yield nil, args[0], 0 | |
379 | 413 | end |
380 | - | |
381 | - def crc(seq, state = nil) | |
382 | - self::GENERATOR.crc(seq, state) | |
383 | - end | |
384 | - | |
385 | - def digest(seq, state = nil) | |
386 | - Aux.digest(self::GENERATOR.crc(seq, state), self::GENERATOR.bitsize) | |
387 | - end | |
388 | - | |
389 | - def hexdigest(seq, state = nil) | |
390 | - Aux.hexdigest(self::GENERATOR.crc(seq, state), self::GENERATOR.bitsize) | |
391 | - end | |
392 | - | |
393 | - def inspect | |
394 | - if const_defined?(:GENERATOR) | |
395 | - if nm = name | |
396 | - "#{nm}(#{self::GENERATOR.to_s})" | |
397 | - else | |
398 | - super.sub(/(?=\>$)/) { " #{self::GENERATOR.to_s}" } | |
399 | - end | |
400 | - else | |
401 | - super | |
402 | - end | |
403 | - end | |
404 | - | |
405 | - def pretty_inspect(q) | |
406 | - q.text inspect | |
407 | - end | |
408 | - end | |
409 | - | |
410 | - private | |
411 | - def initialize_args(args) | |
412 | - case args.size | |
413 | - when 0 | |
414 | - yield nil, nil, 0 | |
415 | - when 1 | |
416 | - if args[0].kind_of?(String) | |
417 | - yield args[0], nil, 0 | |
418 | - else | |
419 | - yield nil, args[0], 0 | |
420 | - end | |
421 | - when 2 | |
422 | - if args[0].kind_of?(String) | |
423 | - yield args[0], args[1], 0 | |
424 | - else | |
425 | - yield nil, args[0], args[1].to_i | |
426 | - end | |
427 | - when 3 | |
428 | - yield args[0], args[1], args[2].to_i | |
414 | + when 2 | |
415 | + if args[0].kind_of?(String) | |
416 | + yield args[0], args[1], 0 | |
429 | 417 | else |
430 | - raise ArgumentError, "wrong argument size (given #{args.size}, expect 0..3)" | |
418 | + yield nil, args[0], args[1].to_i | |
431 | 419 | end |
420 | + when 3 | |
421 | + yield args[0], args[1], args[2].to_i | |
422 | + else | |
423 | + raise ArgumentError, "wrong argument size (given #{args.size}, expect 0..3)" | |
432 | 424 | end |
433 | 425 | end |
434 | 426 |
@@ -443,24 +435,17 @@ | ||
443 | 435 | |
444 | 436 | alias [] lookup |
445 | 437 | |
446 | - def crc(modulename, seq, state = nil) | |
447 | - lookup(modulename).crc(seq, state) | |
438 | + def crc(modulename, seq, crc = nil) | |
439 | + lookup(modulename).crc(seq, crc) | |
448 | 440 | end |
449 | 441 | |
450 | - def digest(modulename, seq, state = nil) | |
451 | - lookup(modulename).digest(seq, state) | |
442 | + def digest(modulename, seq, crc = nil) | |
443 | + lookup(modulename).digest(seq, crc) | |
452 | 444 | end |
453 | 445 | |
454 | - def hexdigest(modulename, seq, state = nil) | |
455 | - lookup(modulename).hexdigest(seq, state) | |
446 | + def hexdigest(modulename, seq, crc = nil) | |
447 | + lookup(modulename).hexdigest(seq, crc) | |
456 | 448 | end |
457 | - | |
458 | - def create_module(bitsize, polynomial, initial_state = 0, refin = true, refout = true, xor = ~0, name = nil) | |
459 | - g = Generator.new(bitsize, polynomial, initial_state, refin, refout, xor, name) | |
460 | - crc = Class.new(BasicCRC) | |
461 | - crc.const_set :GENERATOR, g | |
462 | - crc | |
463 | - end | |
464 | 449 | end |
465 | 450 | |
466 | 451 | require_relative "crc/_modules" |
@@ -469,10 +454,11 @@ | ||
469 | 454 | # |
470 | 455 | # Create CRC module classes. |
471 | 456 | # |
472 | - LIST.each do |bitsize, polynomial, refin, refout, initial_state, xor, check, *names| | |
457 | + LIST.each do |bitsize, polynomial, refin, refout, initial_crc, xor, check, *names| | |
458 | + names.flatten! | |
473 | 459 | names.map! { |nm| nm.freeze } |
474 | 460 | |
475 | - crc = create_module(bitsize, polynomial, initial_state, refin, refout, xor, names[0]) | |
461 | + crc = CRC.new(bitsize, polynomial, initial_crc, refin, refout, xor, names[0]) | |
476 | 462 | crc.const_set :NAME, names |
477 | 463 | |
478 | 464 | names.each do |nm| |
@@ -481,31 +467,36 @@ | ||
481 | 467 | raise NameError, "collision crc-module name: #{nm} (#{crc::GENERATOR} and #{MODULE_TABLE[nm1]::GENERATOR})" |
482 | 468 | end |
483 | 469 | MODULE_TABLE[nm1] = crc |
470 | + | |
471 | + name = nm.sub(/(?<=\bCRC)-(?=\d+)/, "").gsub(/[\W]+/, "_") | |
472 | + const_set(name, crc) | |
473 | + | |
474 | + define_singleton_method(name.upcase, ->(*args) { crc.new(*args) }) | |
475 | + define_singleton_method(name.downcase, ->(*args) { | |
476 | + if args.size == 0 | |
477 | + crc | |
478 | + else | |
479 | + crc.crc(*args) | |
480 | + end | |
481 | + }) | |
484 | 482 | end |
485 | - name = names[0].sub(/(?<=\bCRC)-(?=\d+)/, "").gsub(/[\W]+/, "_") | |
486 | - const_set(name, crc) | |
487 | 483 | |
488 | 484 | check = Integer(check.to_i) if check |
489 | 485 | crc.const_set :CHECK, check |
490 | - | |
491 | - g = crc::GENERATOR | |
492 | - define_singleton_method(name.upcase, ->(*args) { crc.new(*args) }) | |
493 | - define_singleton_method(name.downcase, ->(*args) { g.crc(*args) }) | |
494 | 486 | end |
495 | 487 | |
496 | 488 | if $0 == __FILE__ |
497 | 489 | $stderr.puts "#{__FILE__}:#{__LINE__}: SELF CHECK for CRC modules (#{File.basename($".grep(/_(?:byruby|turbo)/)[0]||"")})\n" |
498 | 490 | MODULE_TABLE.values.uniq.each do |crc| |
499 | - g = crc::GENERATOR | |
500 | 491 | check = crc::CHECK |
501 | - checked = g.crc("123456789") | |
492 | + checked = crc.crc("123456789") | |
502 | 493 | case check |
503 | 494 | when nil |
504 | - $stderr.puts "| %20s(\"123456789\") = %16X (check only)\n" % [g.name, checked] | |
495 | + $stderr.puts "| %20s(\"123456789\") = %16X (check only)\n" % [crc.name, checked] | |
505 | 496 | when checked |
506 | 497 | ; |
507 | 498 | else |
508 | - $stderr.puts "| %20s(\"123456789\") = %16X (expect to %X)\n" % [g.name, checked, check] | |
499 | + $stderr.puts "| %20s(\"123456789\") = %16X (expect to %X)\n" % [crc.name, checked, check] | |
509 | 500 | end |
510 | 501 | end |
511 | 502 | $stderr.puts "#{__FILE__}:#{__LINE__}: DONE SELF CHECK\n" |
@@ -1,12 +1,13 @@ | ||
1 | +require_relative "lib/crc/version" | |
2 | + | |
1 | 3 | GEMSTUB = Gem::Specification.new do |s| |
2 | 4 | s.name = "crc" |
3 | - s.version = "0.2" | |
5 | + s.version = CRC::VERSION | |
4 | 6 | s.summary = "general CRC generator" |
5 | 7 | s.description = <<EOS |
6 | 8 | This is a general CRC (Cyclic Redundancy Check) generator for ruby. |
7 | -It is written by pure ruby with based on slice-by-eight algorithm (slice-by-16 algorithm as byte-order free and byte-alignment free). | |
8 | -Included built-in CRC modules are CRC-32, CRC-64-XZ, CRC-64-ECMA, CRC-64-ISO, CRC-16-CCITT, CRC-16-IBM, CRC-8, CRC-5-USB, CRC-5-EPC and many more. | |
9 | -Additional your customized CRC modules are defined to posible. | |
9 | +It is written by pure ruby. | |
10 | +Customization is posible for 1 to 64 bit width, any polynomial primitives, and with/without bit reflection input/output. | |
10 | 11 | If you need more speed, please use crc-turbo. |
11 | 12 | EOS |
12 | 13 | s.homepage = "https://osdn.jp/projects/rutsubo/" |
@@ -15,7 +16,7 @@ | ||
15 | 16 | s.email = "dearblue@users.osdn.me" |
16 | 17 | |
17 | 18 | s.required_ruby_version = ">= 2.0" |
18 | - s.add_development_dependency "rake", "~> 11.0" | |
19 | + s.add_development_dependency "rake" | |
19 | 20 | end |
20 | 21 | |
21 | 22 | EXTRA << "benchmark.rb" |
@@ -2,6 +2,28 @@ | ||
2 | 2 | |
3 | 3 | # crc for ruby の更新履歴 |
4 | 4 | |
5 | +## crc-0.3 (平成28年7月31日 日曜日) | |
6 | + | |
7 | +互換性を損なう変更があります。 | |
8 | + | |
9 | + * CRC::BasicCRC クラスと CRC::Generator クラスを、CRC クラスに統合 | |
10 | + * ruby オブジェクト CRC をモジュールからクラスに変更しました。 | |
11 | + * CRC::BasicCRC クラスと CRC::Generator クラスを削除しました。 | |
12 | + * crc-0.2 まで CRC::BasicCRC の派生クラスだった各 crc モジュールは | |
13 | + CRC クラスから派生するようになりました。 | |
14 | + * CRC.create\_module を削除し、CRC.new に統合 | |
15 | + * crc-0.2 まであった CRC.create\_module メソッドを削除しました。 | |
16 | + * CRC.new メソッドが変わりの役割を担うようになりました。 | |
17 | + * crc モジュールの別名も CRC クラスの定数 (クラスの別名) として追加するように変更 | |
18 | + * CRC としての整数値を得るメソッドを引数なしで呼び出した場合、CRC モジュールを返すように変更 | |
19 | + * 例えば ``CRC.crc32`` を引数なしで呼び出すと、CRC::CRC32 クラスオブジェクトが返るようになりました。 | |
20 | + * CRC-64-ISO の修正 | |
21 | + * CRC モジュール名の整理 | |
22 | + * 初期値以外が同じかどうかを確認する CRC.variant? メソッドを追加 | |
23 | + * ``CRC#initial_crc`` を廃止 | |
24 | + * 定義が不確かな CRC モジュールを無効化 | |
25 | + * (実験的) 任意の CRC 値から逆算してバイト列を生成する機能 CRC.acrc (crc/acrc.rb) を追加 | |
26 | + | |
5 | 27 | ## crc-0.2 (平成28年5月15日 (日)) |
6 | 28 | |
7 | 29 | * CRC モジュールの追加と修正 |
@@ -7,7 +7,7 @@ | ||
7 | 7 | |
8 | 8 | Included built-in CRC modules are CRC-32, CRC-64-ECMA, CRC-64-ISO, CRC-16-CCITT, CRC-16-IBM, CRC-8, CRC-5-USB, CRC-5-EPC and many more. |
9 | 9 | |
10 | -Additional your customized CRC modules are defined to posible. | |
10 | +Customization is posible for 1 to 64 bit width, any polynomial primitives, and with/without bit reflection input/output. | |
11 | 11 | |
12 | 12 | This library is slower than ×85+ of zlib/crc32, and slower than ×120+ of extlzma/crc32 on FreeBSD 10.3R amd64. |
13 | 13 |
@@ -20,51 +20,98 @@ | ||
20 | 20 | * author: dearblue (mailto:dearblue@users.osdn.me) |
21 | 21 | * report issue to: <https://osdn.jp/projects/rutsubo/ticket/> |
22 | 22 | * how to install: ``gem install crc`` |
23 | - * version: 0.2 | |
24 | - * release quality: thechnical preview | |
23 | + * version: 0.3 | |
24 | + * release quality: technical preview | |
25 | 25 | * licensing: BSD-2-Clause<br>any parts are under Creative Commons License Zero (CC0 / Public Domain), and zlib-style License. |
26 | 26 | * dependency gems: none |
27 | - * dependency external c libraries: none | |
28 | - * bundled external c libraries: none | |
27 | + * dependency external C libraries: none | |
28 | + * bundled external C libraries: none | |
29 | 29 | |
30 | 30 | |
31 | -## Features | |
31 | +## API Guide | |
32 | 32 | |
33 | -This examples are used CRC-32 module. Please see CRC::BasicCRC for more details. | |
33 | +This examples are used CRC-32 module. Please see CRC for more details. | |
34 | 34 | |
35 | - * CRC.crc32(seq, init = 0) -> crc-32 integer (likely as ``Zlib.crc32``) | |
36 | - * CRC::CRC32.crc(seq, init = 0) -> crc-32 integer (likely as ``Zlib.crc32``) | |
37 | - * CRC::CRC32.digest(seq, init = 0) -> crc-32 digest (likely as ``Digest::XXXX.digest``) | |
38 | - * CRC::CRC32.hexdigest(seq, init = 0) -> crc-32 hex-digest (likely as ``Digest::XXXX.hexdigest``) | |
39 | - * CRC::CRC32.new(init = 0) -> crc-32 context (likely as ``Digest::XXXX.new``) | |
40 | - * CRC::CRC32#update(seq) -> self (likely as ``Digest::XXXX#update``) | |
41 | - * CRC::CRC32#state -> crc-32 integer | |
42 | - * CRC::CRC32#digest -> crc-32 digest (likely as ``Digest::XXXX#digest``) | |
43 | - * CRC::CRC32#hexdigest -> crc-32 hex-digest (likely as ``Digest::XXXX#hexdigest``) | |
44 | - * CRC.crc("crc-32", seq, init = 0) -> crc-32 integer | |
45 | - * CRC.digest("crc-32", seq, init = 0) -> crc-32 digest | |
46 | - * CRC.hexdigest("crc-32", seq, init = 0) -> crc-32 hex-digest | |
47 | - * CRC::CRC32.combine(CRC.crc32("123"), CRC.crc32("456789"), 6) -> 3421780262 (likely as ``Zlib.crc32_comibne``) | |
48 | - * CRC.CRC32("123") + CRC.CRC32("456") + CRC.CRC32("789") -> #<CRC::CRC32:CBF43926> | |
35 | + * Calcurate by direct | |
49 | 36 | |
50 | ----- | |
37 | + * ``CRC.crc32(seq, init = CRC::CRC32.initial_crc) => crc-32 integer`` (likely as ``Zlib.crc32``) | |
38 | + * ``CRC.crc32.crc(seq, init = CRC::CRC32.initial_crc) => crc-32 integer`` (likely as ``Zlib.crc32``) | |
39 | + * ``CRC.crc32.digest(seq, init = CRC::CRC32.initial_crc) => crc-32 digest`` (likely as ``Digest::XXXX.digest``) | |
40 | + * ``CRC.crc32.hexdigest(seq, init = 0) -> crc-32 hex-digest`` (likely as ``Digest::XXXX.hexdigest``) | |
41 | + * ``CRC.crc32[seq, init = 0, current_length = 0] -> crc-32 generator`` | |
42 | + * ``CRC.crc32.new(seq, init = 0, current_length = 0) -> crc-32 generator`` | |
51 | 43 | |
52 | - * CRC.create\_module(bitsize, poly, init\_state, refin, refout, xorout) -> new crc module class | |
44 | + * Calcurate by streaming | |
53 | 45 | |
46 | + * ``CRC.crc32[init = 0, current_length = 0] => crc-32 generator`` | |
47 | + * ``CRC.crc32.new(init = 0, current_length = 0) => crc-32 generator`` | |
48 | + * ``CRC.crc32#update(seq) => self`` (likely as ``Digest::XXXX.update``) | |
49 | + * ``CRC.crc32#finish => crc-32 integer`` (likely as ``Digest::XXXX.finish``) | |
50 | + * ``CRC.crc32#crc => crc-32 integer`` (same as ``CRC.crc32#finish``) | |
51 | + * ``CRC.crc32#digest => crc-32 digest`` (likely as ``Digest::XXXX.digest``) | |
52 | + * ``CRC.crc32#hexdigest => crc-32 hex-digest`` (likely as ``Digest::XXXX.hexdigest``) | |
53 | + | |
54 | + Example: | |
55 | + | |
54 | 56 | ``` ruby:ruby |
55 | - MyCRC32 = CRC.create_module(32, 0x04C11DB7) | |
56 | - p MyCRC32.class # => Class | |
57 | - p MyCRC32.hexdigest("123456789") # => "CBF43926" | |
57 | + x = CRC.crc32.new # => #<CRC::CRC32:00000000> | |
58 | + x.update "123" # => #<CRC::CRC32:884863D2> | |
59 | + x.update "456789" # => #<CRC::CRC32:CBF43926> | |
60 | + x.crc # => 3421780262 | |
61 | + x.digest # => "\xCB\xF49&" | |
62 | + x.hexdigest # => "CBF43926" | |
58 | 63 | ``` |
59 | 64 | |
65 | + * Combine | |
60 | 66 | |
67 | + * ``CRC.combine(crc1, crc2, len2) => combined crc integer`` (likely as ``Zlib.crc32_comibne``) | |
68 | + * ``CRC#+(right_crc) => combined crc generator`` | |
69 | + | |
70 | + Example-1: | |
71 | + | |
72 | + ``` ruby:ruby | |
73 | + CRC.crc32.combine(CRC.crc32("123"), CRC.crc32("456789"), 6) # => 3421780262 | |
74 | + ``` | |
75 | + | |
76 | + Example-2: | |
77 | + | |
78 | + ``` ruby:ruby | |
79 | + CRC.crc32["123"] + CRC.crc32["456"] + CRC.crc32["789"] # => #<CRC::CRC32:CBF43926> | |
80 | + ``` | |
81 | + | |
82 | + * Create customized crc module | |
83 | + | |
84 | + * ``CRC.new(bitsize, poly, initial_crc = 0, refin = true, refout = true, xor_output = ~0) => new crc module class`` | |
85 | + | |
86 | + ``` ruby:ruby | |
87 | + MyCRC32 = CRC.new(32, 0x04C11DB7) | |
88 | + MyCRC32.class # => Class | |
89 | + MyCRC32.hexdigest("123456789") # => "CBF43926" | |
90 | + MyCRC32.new("123456789") # => #<MyCRC32:CBF43926> | |
91 | + ``` | |
92 | + | |
93 | + * Calcurate arc-crc (***EXPERIMENTAL***) | |
94 | + | |
95 | + * ``CRC.acrc(pre, post = nil, want_crc = 0) => arc-crc byte string`` | |
96 | + | |
97 | + ``` ruby:ruby | |
98 | + a = "12" | |
99 | + c = "789" | |
100 | + wantcrc = 0xCBF43926 | |
101 | + b = CRC.crc32.acrc(a, c, wantcrc) # => "3456" | |
102 | + CRC.crc32[a + b + c] # => #<CRC::CRC32:CBF43926> | |
103 | + ``` | |
104 | + | |
105 | + See CRC::ModuleClass.acrc for more detail. | |
106 | + | |
107 | + | |
61 | 108 | ## Built-in CRC modules |
62 | 109 | |
63 | 110 | ``` shell:shell |
64 | -% ruby -rcrc -e 'puts CRC::MODULE_TABLE.values.uniq.map { |m| m::GENERATOR.name }.join(", ")' | |
111 | +% ruby -rcrc -e 'puts CRC::MODULE_TABLE.values.uniq.map { |m| m.name }.join(", ")' | |
65 | 112 | ``` |
66 | 113 | |
67 | -CRC-1, CRC-3-ROHC, CRC-4-INTERLAKEN, CRC-4-ITU, CRC-5-EPC, CRC-5-ITU, CRC-5-USB, CRC-6-CDMA2000-A, CRC-6-CDMA2000-B, CRC-6-DARC, CRC-6-ITU, CRC-7, CRC-7-MVB, CRC-7-ROHC, CRC-7-UMTS, CRC-8, CRC-8-CCITT, CRC-8-MAXIM, CRC-8-DARC, CRC-8-SAE, CRC-8-WCDMA, CRC-8-CDMA2000, CRC-8-DVB-S2, CRC-8-EBU, CRC-8-I-CODE, CRC-8-ITU, CRC-8-LTE, CRC-8-ROHC, CRC-10, CRC-10-CDMA2000, CRC-11, CRC-11-UMTS, CRC-12-CDMA2000, CRC-12-DECT, CRC-12-UMTS, CRC-13-BBC, CRC-14-DARC, CRC-15, CRC-15-MPT1327, Chakravarty, ARC, CRC-16-ARINC, CRC-16-AUG-CCITT, CRC-16-CDMA2000, CRC-16-DECT-R, CRC-16-DECT-X, CRC-16-T10-DIF, CRC-16-DNP, CRC-16-BUYPASS, CRC-16-CCITT-FALSE, CRC-16-DDS-110, CRC-16-EN-13757, CRC-16-GENIBUS, CRC-16-LJ1200, CRC-16-MAXIM, CRC-16-MCRF4XX, CRC-16-RIELLO, CRC-16-TELEDISK, CRC-16-TMS37157, CRC-16-USB, CRC-A, KERMIT, MODBUS, X-25, XMODEM, CRC-17-CAN, CRC-21-CAN, CRC-24, CRC-24-Radix-64, CRC-24-OPENPGP, CRC-24-BLE, CRC-24-FLEXRAY-A, CRC-24-FLEXRAY-B, CRC-24-INTERLAKEN, CRC-24-LTE-A, CRC-24-LTE-B, CRC-30, CRC-30-CDMA, CRC-31-PHILIPS, CRC-32, CRC-32-BZIP2, CRC-32C, CRC-32D, CRC-32-MPEG-2, CRC-32-POSIX, CRC-32K, CRC-32K2, CRC-32Q, JAMCRC, XFER, CRC-40-GSM, CRC-64, CRC-64-ECMA, CRC-64-WE, CRC-64-ISO | |
114 | +CRC-1, CRC-3-ROHC, CRC-4-INTERLAKEN, CRC-4-ITU, CRC-5-EPC, CRC-5-ITU, CRC-5-USB, CRC-6-CDMA2000-A, CRC-6-CDMA2000-B, CRC-6-DARC, CRC-6-ITU, CRC-7, CRC-7-MVB, CRC-7-ROHC, CRC-7-UMTS, CRC-8, CRC-8-CCITT, CRC-8-MAXIM, CRC-8-DARC, CRC-8-SAE, CRC-8-WCDMA, CRC-8-CDMA2000, CRC-8-DVB-S2, CRC-8-EBU, CRC-8-I-CODE, CRC-8-ITU, CRC-8-LTE, CRC-8-ROHC, CRC-10, CRC-10-CDMA2000, CRC-11, CRC-11-UMTS, CRC-12-CDMA2000, CRC-12-DECT, CRC-12-UMTS, CRC-13-BBC, CRC-14-DARC, CRC-15, CRC-15-MPT1327, Chakravarty, CRC-16, CRC-16-ARINC, CRC-16-AUG-CCITT, CRC-16-CDMA2000, CRC-16-DECT-R, CRC-16-DECT-X, CRC-16-T10-DIF, CRC-16-DNP, CRC-16-BUYPASS, CRC-16-CCITT-FALSE, CRC-16-DDS-110, CRC-16-EN-13757, CRC-16-GENIBUS, CRC-16-LJ1200, CRC-16-MAXIM, CRC-16-MCRF4XX, CRC-16-RIELLO, CRC-16-TELEDISK, CRC-16-TMS37157, CRC-16-USB, CRC-16-A, CRC-16-KERMIT, CRC-16-MODBUS, CRC-16-X-25, CRC-16-XMODEM, CRC-17-CAN, CRC-21-CAN, CRC-24, CRC-24-Radix-64, CRC-24-OPENPGP, CRC-24-BLE, CRC-24-FLEXRAY-A, CRC-24-FLEXRAY-B, CRC-24-INTERLAKEN, CRC-24-LTE-A, CRC-24-LTE-B, CRC-30, CRC-30-CDMA, CRC-31-PHILIPS, CRC-32, CRC-32-BZIP2, CRC-32C, CRC-32D, CRC-32-MPEG-2, CRC-32-POSIX, CRC-32K, CRC-32K2, CRC-32Q, CRC-32-JAMCRC, CRC-32-XFER, CRC-40-GSM, CRC-64-XZ, CRC-64-ECMA, CRC-64-WE, CRC-64-ISO | |
68 | 115 | |
69 | 116 | |
70 | 117 | ## Environment variables for behavior |
@@ -75,6 +122,69 @@ | ||
75 | 122 | * ``RUBY_CRC_NOFAST=3``: Switch to reference algorithm from slice-by-16 algorithm. Slower than about 7% (when CRC-32). |
76 | 123 | |
77 | 124 | |
78 | -## About CRC::Generator#combine | |
125 | +## About CRC.combine | |
79 | 126 | |
80 | -CRC::Generator#combine is ported from Mark Adler's crccomb.c in https://stackoverflow.com/questions/29915764/generic-crc-8-16-32-64-combine-implementation#29928573 . | |
127 | +CRC.combine is ported from Mark Adler's crccomb.c in <https://stackoverflow.com/questions/29915764/generic-crc-8-16-32-64-combine-implementation#29928573>. | |
128 | + | |
129 | + | |
130 | +## arc-crc (***EXPERIMENTAL***) | |
131 | + | |
132 | +(Written in japanese from here) | |
133 | + | |
134 | +crc-0.3 にて、任意の CRC となるバイト列を逆算する機能が***実験的に***追加されました。 | |
135 | + | |
136 | +今のところは、reflect-input/output 限定となっています。 | |
137 | + | |
138 | +``require "crc/acrc"`` にて、その機能が利用可能となります。 | |
139 | + | |
140 | +名前の由来は、arc-sin などの C 関数である asin と同様に、arc-crc => acrc となっています。 | |
141 | + | |
142 | +以下は使用例です。 | |
143 | + | |
144 | + * 文字列 "123456789????" を CRC32 した場合に 0 となるような、???? の部分を逆算する | |
145 | + | |
146 | + ``` ruby:ruby | |
147 | + require "crc/acrc" | |
148 | + | |
149 | + seq = "123456789" | |
150 | + seq << CRC.crc32.acrc(seq) | |
151 | + p CRC.crc32[seq] # => #<CRC::CRC32:00000000> | |
152 | + ``` | |
153 | + | |
154 | + * 文字列 "123456789????ABCDEFG" の、???? の部分を逆算する | |
155 | + | |
156 | + ``` ruby:ruby | |
157 | + require "crc/acrc" | |
158 | + | |
159 | + seq1 = "123456789" | |
160 | + seq2 = "ABCDEFG" | |
161 | + seq = seq1 + CRC.crc32.acrc(seq1, seq2) + seq2 | |
162 | + p CRC.crc32[seq] # => #<CRC::CRC32:00000000> | |
163 | + ``` | |
164 | + | |
165 | + * 文字列 "123456789????ABCDEFG" を CRC32 した場合に 0x12345678 となるような、???? の部分を逆算する | |
166 | + | |
167 | + ``` ruby:ruby | |
168 | + require "crc/acrc" | |
169 | + | |
170 | + seq1 = "123456789" | |
171 | + seq2 = "ABCDEFG" | |
172 | + target_crc = 0x12345678 | |
173 | + seq = seq1 + CRC.crc32.acrc(seq1, seq2, target_crc) + seq2 | |
174 | + p CRC.crc32[seq] # => #<CRC::CRC32:12345678> | |
175 | + ``` | |
176 | + | |
177 | + * 独自仕様の CRC モジュールにも対応 | |
178 | + | |
179 | + ``` ruby:ruby | |
180 | + require "crc/acrc" | |
181 | + | |
182 | + seq1 = "123456789" | |
183 | + seq2 = "ABCDEFG" | |
184 | + target_crc = 0x12345678 | |
185 | + MyCRC = CRC.new(29, rand(1 << 29) | 1) | |
186 | + seq = seq1 + MyCRC.acrc(seq1, seq2, target_crc) + seq2 | |
187 | + p MyCRC[seq] # => #<MyCRC:12345678> | |
188 | + ``` | |
189 | + | |
190 | +[EOF] |
@@ -9,8 +9,9 @@ | ||
9 | 9 | require "crc" |
10 | 10 | begin; require "extlzma"; rescue LoadError; no_extlzma = true; end |
11 | 11 | begin; require "digest/crc"; rescue LoadError; no_digest_crc = true; end |
12 | +begin; require "crc32"; rescue LoadError; no_crc32 = true; end | |
12 | 13 | |
13 | -def measure(generator_name) | |
14 | +def measure(size, generator_name) | |
14 | 15 | print " * measuring for #{generator_name}..." |
15 | 16 | $stdout.flush |
16 | 17 | realms = 5.times.map do |
@@ -19,7 +20,7 @@ | ||
19 | 20 | $stdout.flush |
20 | 21 | real |
21 | 22 | end.min |
22 | - puts " (#{(realms * 100).round / 100.0} ms.)\n" | |
23 | + printf " (%.2f ms.) (peak: %0.2f MiB / s)\n", realms, size / (realms / 1000) | |
23 | 24 | [generator_name, realms] |
24 | 25 | end |
25 | 26 |
@@ -38,17 +39,22 @@ | ||
38 | 39 | #s = SecureRandom.random_bytes(size << 20) |
39 | 40 | s = "0" * (size << 20) |
40 | 41 | |
41 | -crc = measure("ruby-crc/crc32") { CRC.crc32(s) }[1] | |
42 | +crc = measure(size, "crc/crc32") { CRC.crc32(s) }[1] | |
42 | 43 | comparisons = [] |
43 | -comparisons << measure("zlib/crc-32") { Zlib.crc32(s) } | |
44 | -comparisons << measure("extlzma/crc-32") { LZMA.crc32(s) } unless no_extlzma | |
45 | -comparisons << measure("digest/crc-32") { Digest::CRC32.digest(s) } unless no_digest_crc | |
46 | -comparisons << measure("ruby-crc/crc-64") { CRC.crc64(s) } | |
47 | -comparisons << measure("extlzma/crc-64") { LZMA.crc64(s) } unless no_extlzma | |
44 | +comparisons << measure(size, "zlib/crc-32") { Zlib.crc32(s) } | |
45 | +comparisons << measure(size, "extlzma/crc-32") { LZMA.crc32(s) } unless no_extlzma | |
46 | +comparisons << measure(size, "digest/crc-32") { Digest::CRC32.digest(s) } unless no_digest_crc | |
47 | +comparisons << measure(size, "crc32/crc-32") { Crc32.calculate(s, s.bytesize, 0) } unless no_crc32 | |
48 | +comparisons << measure(size, "crc/crc-64") { CRC.crc64(s) } | |
49 | +comparisons << measure(size, "extlzma/crc-64") { LZMA.crc64(s) } unless no_extlzma | |
50 | +comparisons << measure(size, "crc/crc-5-usb") { CRC.crc5_usb(s) } | |
51 | +comparisons << measure(size, "crc/crc-16-usb") { CRC.crc16_usb(s) } | |
52 | +comparisons << measure(size, "crc/crc-32-posix") { CRC.crc32_posix(s) } | |
53 | +comparisons << measure(size, "crc/crc-32c") { CRC.crc32c(s) } | |
48 | 54 | |
49 | 55 | puts <<'EOS' |
50 | 56 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
51 | - (slowly at over 1.0) | |
57 | + (ruby-crc/crc32 is slowly at over 1.0) | |
52 | 58 | EOS |
53 | 59 | |
54 | 60 | comparisons.each do |name, meas| |