leb128.c 3.76 KB
/*

	LEB128.C

	Encoding/decoding routines for leb128
	compression.

*/

#include <sys/types.h>
#include <sys/syssgi.h>
#include "leb128.h"

#define MORE_BYTES	0x80
#define DATA_MASK	0x7f
#define DIGIT_WIDTH	7
#define SIGN_BIT	0x40

	/*******************************************************
		Function: uncompress_u4

		LEB128 decoding of a compressed 4 byte 
		unsigned number.

	 *******************************************************/
void * 
uncompress_u4(char *ptr, __uint32_t * const value)
{
char byte = 0;
unsigned shift = 0;

    *value = 0;

    do {
    byte = *ptr++;

    *value |= ((0x7f & byte) << shift);
    shift+=7;

		/*
		 * more bytes to come
		 */
    } while(byte & 0x80);
    
    return(ptr);
}

	/*******************************************************
		Function: uncompress_u8

		LEB128 decoding of a compressed 8 byte 
		unsigned number.

	 *******************************************************/
void * 
uncompress_u8(char *ptr, __uint64_t * const value)
{
char byte = 0;
unsigned shift = 0;

    *value = 0;

    do{

    byte = *ptr++;

    *value |= ((0x7f & byte) << shift);
    shift+=7;

		/*
		 * more bytes to come
		 */
    } while(byte & 0x80);
    
    return(ptr);
}

	/*******************************************************
		Function: uncompress_s4

		LEB128 decoding of a compressed 4 byte 
		signed number.

	 *******************************************************/
void *
uncompress_s4(char *ptr, __int32_t * const value)
{
char byte = 0;
__uint32_t shift = 0;
__uint32_t size = (sizeof(__int32_t))*8;

    *value = 0;

    while(1) {

    byte = *ptr++;

	*value |= ((0x7f & byte) << shift);
	shift+=7;

		/*
		 * The sign bit of byte is 2nd high
		 * order bit 0x40. Break if the 
		 * high order bit is clear indicating
		 * the end.
		 */
	if (!(byte & 0x80))
	    break;
    }

    if ((shift < size) && (byte & 0x40))
	*value |= -(1<<shift);

    return(ptr);
}

	/*******************************************************
		Function: uncompress_s8

		LEB128 decoding of a compressed 8 byte 
		signed number.

	 *******************************************************/
void *
uncompress_s8(char *ptr, __int64_t * const value)
{
char byte = 0;
__uint32_t shift = 0;
__uint32_t size = (sizeof(__int64_t))*8;

    *value = 0;

    while(1) {

    byte = *ptr++;

	*value |= ((0x7f & byte) << shift);
	shift+=7;

		/*
		 * The sign bit of byte is 2nd high
		 * order bit 0x40. Break if the 
		 * high order bit is clear indicating
		 * the end.
		 */
	if (!(byte & 0x80))
	    break;
    }

    if ((shift < size) && (byte & 0x40))
	*value |= -(1<<shift);

    return(ptr);
}



/*********************************************************
	    Function: compress_u8

	    LEB128 encoding of a 8 byte unsigned number.

**********************************************************/
__uint32_t compress_u8(char *buf, __uint64_t value)
{
    char byte;
    __uint32_t count = 0;

    do{
	byte = value & DATA_MASK;
	value >>= DIGIT_WIDTH;
	count++;
	/* check if there are more bytes to come */
	if (value !=0) byte |= MORE_BYTES;
	*buf++ = byte;
    } while (value != 0);
    
    return count;
}

/*******************************************************
	    Function: compress_s8

	    LEB128 encoding of a 8 byte signed number.

 *******************************************************/
__uint32_t compress_s8 (char *buf, __int64_t value)
{
    char byte;
    __uint32_t count = 0;
    __uint32_t more = 1;
    __int64_t sign = - (value < 0);

    do {
	byte = value & DATA_MASK;
	value >>= DIGIT_WIDTH;
	count++;
	/* Remaining chunks would just contain the sign bit, and this chunk
	   has already captured at least one sign bit.
	*/
	if (value == sign && (byte & SIGN_BIT) == (sign & SIGN_BIT))
	    more = 0;
	else
	    byte |= MORE_BYTES;
	*buf++ = byte;
    } while (more);
    
    return count;
}