diff --git a/libyasm/intnum.c b/libyasm/intnum.c index 5e22dc47..b4d82821 100644 --- a/libyasm/intnum.c +++ b/libyasm/intnum.c @@ -258,6 +258,44 @@ yasm_intnum_create_int(long i) return intn; } +yasm_intnum * +yasm_intnum_create_leb128(const unsigned char *ptr, int sign, + unsigned long *size, unsigned long line) +{ + yasm_intnum *intn = yasm_xmalloc(sizeof(yasm_intnum)); + const unsigned char *ptr_orig = ptr; + unsigned long i = 0; + + intn->origsize = 0; + + BitVector_Empty(conv_bv); + for (;;) { + BitVector_Chunk_Store(conv_bv, 7, i, *ptr); + i += 7; + if ((*ptr & 0x80) != 0x80) + break; + ptr++; + } + + *size = (ptr-ptr_orig)+1; + + if(i > BITVECT_NATIVE_SIZE) + yasm__warning(YASM_WARN_GENERAL, line, + N_("Numeric constant too large for internal format")); + else if (sign && (*ptr & 0x40) == 0x40) + BitVector_Interval_Fill(conv_bv, i, BITVECT_NATIVE_SIZE-1); + + if (Set_Max(conv_bv) < 32) { + intn->type = INTNUM_UL; + intn->val.ul = BitVector_Chunk_Read(conv_bv, 32, 0); + } else { + intn->type = INTNUM_BV; + intn->val.bv = BitVector_Clone(conv_bv); + } + + return intn; +} + yasm_intnum * yasm_intnum_copy(const yasm_intnum *intn) { diff --git a/libyasm/intnum.h b/libyasm/intnum.h index 9cb4f66c..779534a8 100644 --- a/libyasm/intnum.h +++ b/libyasm/intnum.h @@ -90,6 +90,18 @@ void yasm_intnum_cleanup(void); */ /*@only@*/ yasm_intnum *yasm_intnum_create_int(long i); +/** Create a new intnum from LEB128-encoded form. + * \param ptr pointer to start of LEB128 encoded form + * \param sign signed (1) or unsiged (0) LEB128 format + * \param size number of bytes read from ptr (output) + * \param line virtual line (where the number came from) + * \return Newly allocated intnum. Number of bytes read returned into + * bytes_read parameter. + */ +/*@only@*/ yasm_intnum *yasm_intnum_create_leb128 + (const unsigned char *ptr, int sign, /*@out@*/ unsigned long *size, + unsigned long line); + /** Duplicate an intnum. * \param intn intnum * \return Newly allocated intnum with the same value as intn. diff --git a/libyasm/tests/leb128_test.c b/libyasm/tests/leb128_test.c index f8ab3465..100e4837 100644 --- a/libyasm/tests/leb128_test.c +++ b/libyasm/tests/leb128_test.c @@ -80,7 +80,7 @@ static char failed[1000]; static char failmsg[100]; static int -run_test(Test_Entry *test) +run_output_test(Test_Entry *test) { char *valstr = yasm__xstrdup(test->input); yasm_intnum *intn = yasm_intnum_create_hex(valstr, 0); @@ -129,6 +129,44 @@ run_test(Test_Entry *test) return 0; } +static int +run_input_test(Test_Entry *test) +{ + char *valstr = yasm__xstrdup(test->input); + yasm_intnum *intn = yasm_intnum_create_hex(valstr, 0); + yasm_intnum *testn; + unsigned long size, i; + unsigned char out[100]; + + yasm_xfree(valstr); + + if (test->negate) + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, 0); + + testn = yasm_intnum_create_leb128(test->result, test->sign, &size, 0); + if (size != test->outsize) { + yasm_intnum_destroy(testn); + yasm_intnum_destroy(intn); + sprintf(failmsg, "%ssigned %s%s create() bad size: expected %lu, got %lu!", + test->sign?"":"un", test->negate?"-":"", test->input, + test->outsize, size); + return 1; + } + + yasm_intnum_calc(intn, YASM_EXPR_EQ, testn, 0); + if (!yasm_intnum_is_pos1(intn)) { + yasm_intnum_destroy(testn); + yasm_intnum_destroy(intn); + sprintf(failmsg, "%ssigned %s%s create() bad output!", + test->sign?"":"un", test->negate?"-":"", test->input); + return 1; + } + + yasm_intnum_destroy(testn); + yasm_intnum_destroy(intn); + return 0; +} + int main(void) { @@ -143,7 +181,16 @@ main(void) failed[0] = '\0'; printf("Test leb128_test: "); for (i=0; i0 ? 'F':'.'); + fflush(stdout); + if (fail) + sprintf(failed, "%s ** F: %s\n", failed, failmsg); + nf += fail; + + fail = run_input_test(&tests[i]); printf("%c", fail>0 ? 'F':'.'); fflush(stdout); if (fail) @@ -154,6 +201,7 @@ main(void) yasm_intnum_cleanup(); printf(" +%d-%d/%d %d%%\n%s", - numtests-nf, nf, numtests, 100*(numtests-nf)/numtests, failed); + numtests*2-nf, nf, numtests*2, 100*(numtests*2-nf)/(numtests*2), + failed); return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }