Commit partial work on dimensional compression

This commit is contained in:
Paul Ramsey 2013-02-18 20:54:37 -08:00
parent 8b99ca3750
commit 87b05d6668
7 changed files with 568 additions and 12 deletions

View File

@ -14,8 +14,10 @@
static PCSCHEMA *schema = NULL;
static PCSCHEMA *simpleschema = NULL;
static PCSCHEMA *lasschema = NULL;
static const char *xmlfile = "data/pdal-schema.xml";
static const char *simplexmlfile = "data/simple-schema.xml";
static const char *lasxmlfile = "data/las-schema.xml";
/* Setup/teardown for this suite */
static int
@ -31,6 +33,11 @@ init_suite(void)
pcfree(xmlstr);
if ( rv == PC_FAILURE ) return 1;
xmlstr = file_to_str(lasxmlfile);
rv = pc_schema_from_xml(xmlstr, &lasschema);
pcfree(xmlstr);
if ( rv == PC_FAILURE ) return 1;
return 0;
}
@ -39,6 +46,7 @@ clean_suite(void)
{
pc_schema_free(schema);
pc_schema_free(simpleschema);
pc_schema_free(lasschema);
return 0;
}
@ -183,6 +191,28 @@ test_patch_hex_out()
uint8_t* pc_bytes_run_length_decode(const uint8_t *bytes_rle, size_t bytes_rle_size, uint32_t interpretation, size_t *bytes_nelems);
#endif
static void
test_schema_xy()
{
/*
"Intensity", "ReturnNumber", "NumberOfReturns", "ScanDirectionFlag", "EdgeOfFlightLine", "Classification", "ScanAngleRank", "UserData", "PointSourceId", "Time", "Red", "Green", "Blue", "PointID", "BlockID", "X", "Y", "Z"
25, 1, 1, 1, 0, 1, 6, 124, 7327, 246093, 39, 57, 56, 20, 0, -125.0417204, 49.2540081, 128.85
*/
static char *hexpt = "01010000000AE9C90307A1100522A5000019000101010001067C9F1C4953C474650A0E412700390038001400000000000000876B6601962F750155320000";
uint8_t *bytes = bytes_from_hexbytes(hexpt, strlen(hexpt));
PCPOINT *pt;
double val;
pt = pc_point_from_wkb(lasschema, bytes, strlen(hexpt)/2);
pc_point_get_double_by_name(pt, "x", &val);
CU_ASSERT_DOUBLE_EQUAL(val, -125.0417204, 0.00001);
pt = pc_point_from_wkb(lasschema, bytes, strlen(hexpt)/2);
pc_point_get_double_by_name(pt, "y", &val);
CU_ASSERT_DOUBLE_EQUAL(val, 49.2540081, 0.00001);
}
static void
test_run_length_encoding()
@ -268,6 +298,8 @@ static void
test_sigbits_encoding()
{
char *bytes;
uint8_t *ebytes;
size_t ebytes_size;
uint32_t count;
uint8_t common8;
uint16_t common16;
@ -300,21 +332,76 @@ test_sigbits_encoding()
CU_ASSERT_EQUAL(count, 6);
CU_ASSERT_EQUAL(common16, 24576);
// bytes = "aaabac";
// common16 = pc_sigbits_16(bytes, strlen(bytes)/2, &count);
// CU_ASSERT_EQUAL(count, 14);
// CU_ASSERT_EQUAL(common16, 24928);
bytes = "aaaabaaacaaadaaaeaaafaaa";
common32 = pc_sigbits_32(bytes, strlen(bytes)/4, &count);
CU_ASSERT_EQUAL(count, 29);
CU_ASSERT_EQUAL(common32, 1633771872);
/*
"abca" encoded:
base a b c a
01100000 01 10 11 01
*/
bytes = "abcaabcaabcbabcc";
ebytes = pc_bytes_sigbits_encode(bytes, PC_INT8, strlen(bytes), &ebytes_size);
CU_ASSERT_EQUAL(ebytes[0], 96);
CU_ASSERT_EQUAL(ebytes[1], 109);
CU_ASSERT_EQUAL(ebytes[2], 109);
CU_ASSERT_EQUAL(ebytes[3], 110);
CU_ASSERT_EQUAL(ebytes[4], 111);
/*
"abca" encoded:
base a b c d a b
01100000 001 010 011 100 001 010
*/
bytes = "abcda";
ebytes = pc_bytes_sigbits_encode(bytes, PC_INT8, strlen(bytes), &ebytes_size);
CU_ASSERT_EQUAL(ebytes[0], 96);
CU_ASSERT_EQUAL(ebytes[1], 41);
CU_ASSERT_EQUAL(ebytes[2], 194);
/*
0110000101100001 aa
0110000101100010 ab
0110000101100011 ac
0110000101100001 aa
0110000101100010 ab
0110000101100011 ac
"aaabacaaabacaaab" encoded:
base aa ab ac aa ab ac aa ab
0110000101100000 01 10 11 01 10 11 01 10
*/
// bytes = "aaabacaaabacaaab";
// ebytes = pc_bytes_sigbits_encode(bytes, PC_INT16, strlen(bytes)/2, &ebytes_size);
// CU_ASSERT_EQUAL(ebytes[0], 97);
// CU_ASSERT_EQUAL(ebytes[1], 96);
// CU_ASSERT_EQUAL(ebytes[2], 109);
// CU_ASSERT_EQUAL(ebytes[3], 182);
}
/* REGISTER ***********************************************************/
CU_TestInfo patch_tests[] = {
PG_TEST(test_endian_flip),
PG_TEST(test_patch_hex_in),
PG_TEST(test_patch_hex_out),
PG_TEST(test_run_length_encoding),
PG_TEST(test_sigbits_encoding),
PC_TEST(test_endian_flip),
PC_TEST(test_patch_hex_in),
PC_TEST(test_patch_hex_out),
PC_TEST(test_run_length_encoding),
PC_TEST(test_schema_xy),
PC_TEST(test_sigbits_encoding),
CU_TEST_INFO_NULL
};

View File

@ -86,7 +86,7 @@ test_point_hex_inout()
/* REGISTER ***********************************************************/
CU_TestInfo point_tests[] = {
PG_TEST(test_point_hex_inout),
PC_TEST(test_point_hex_inout),
CU_TEST_INFO_NULL
};

View File

@ -169,11 +169,11 @@ test_point_access()
/* REGISTER ***********************************************************/
CU_TestInfo schema_tests[] = {
PG_TEST(test_schema_from_xml),
PG_TEST(test_schema_size),
PG_TEST(test_dimension_get),
PG_TEST(test_dimension_byteoffsets),
PG_TEST(test_point_access),
PC_TEST(test_schema_from_xml),
PC_TEST(test_schema_size),
PC_TEST(test_dimension_get),
PC_TEST(test_dimension_byteoffsets),
PC_TEST(test_point_access),
CU_TEST_INFO_NULL
};

View File

@ -9,7 +9,7 @@
#include "pc_api_internal.h"
#define PG_TEST(test_func) { #test_func, test_func }
#define PC_TEST(test_func) { #test_func, test_func }
#define MAX_CUNIT_MSG_LENGTH 512
/* Contains the most recent error message generated by rterror. */

View File

@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
<pc:PointCloudSchema xmlns:pc="http://pointcloud.org/schemas/PC/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<pc:dimension>
<pc:position>1</pc:position>
<pc:size>4</pc:size>
<pc:description>X coordinate as a long integer. You must use the scale and offset information of the header to determine the double value.</pc:description>
<pc:name>X</pc:name>
<pc:interpretation>int32_t</pc:interpretation>
<pc:scale>0.01</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>2ee118d1-119e-4906-99c3-42934203f872</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>2</pc:position>
<pc:size>4</pc:size>
<pc:description>Y coordinate as a long integer. You must use the scale and offset information of the header to determine the double value.</pc:description>
<pc:name>Y</pc:name>
<pc:interpretation>int32_t</pc:interpretation>
<pc:scale>0.01</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>87707eee-2f30-4979-9987-8ef747e30275</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>3</pc:position>
<pc:size>4</pc:size>
<pc:description>Z coordinate as a long integer. You must use the scale and offset information of the header to determine the double value.</pc:description>
<pc:name>Z</pc:name>
<pc:interpretation>int32_t</pc:interpretation>
<pc:scale>0.01</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>e74b5e41-95e6-4cf2-86ad-e3f5a996da5d</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>4</pc:position>
<pc:size>2</pc:size>
<pc:description>The intensity value is the integer representation of the pulse return magnitude. This value is optional and system specific. However, it should always be included if available.</pc:description>
<pc:name>Intensity</pc:name>
<pc:interpretation>uint16_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>61e90c9a-42fc-46c7-acd3-20d67bd5626f</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>5</pc:position>
<pc:size>1</pc:size>
<pc:description>Return Number: The Return Number is the pulse return number for a given output pulse. A given output laser pulse can have many returns, and they must be marked in sequence of return. The first return will have a Return Number of one, the second a Return Number of two, and so on up to five returns.</pc:description>
<pc:name>ReturnNumber</pc:name>
<pc:interpretation>uint8_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>ffe5e5f8-4cec-4560-abf0-448008f7b89e</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>6</pc:position>
<pc:size>1</pc:size>
<pc:description>Number of Returns (for this emitted pulse): The Number of Returns is the total number of returns for a given pulse. For example, a laser data point may be return two (Return Number) within a total number of five returns.</pc:description>
<pc:name>NumberOfReturns</pc:name>
<pc:interpretation>uint8_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>7c28bfd4-a9ed-4fb2-b07f-931c076fbaf0</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>7</pc:position>
<pc:size>1</pc:size>
<pc:description>The Scan Direction Flag denotes the direction at which the scanner mirror was traveling at the time of the output pulse. A bit value of 1 is a positive scan direction, and a bit value of 0 is a negative scan direction (where positive scan direction is a scan moving from the left side of the in-track direction to the right side and negative the opposite).</pc:description>
<pc:name>ScanDirectionFlag</pc:name>
<pc:interpretation>uint8_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>13019a2c-cf88-480d-a995-0162055fe5f9</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>8</pc:position>
<pc:size>1</pc:size>
<pc:description>The Edge of Flight Line data bit has a value of 1 only when the point is at the end of a scan. It is the last point on a given scan line before it changes direction.</pc:description>
<pc:name>EdgeOfFlightLine</pc:name>
<pc:interpretation>uint8_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>108c18f2-5cc0-4669-ae9a-f41eb4006ea5</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>9</pc:position>
<pc:size>1</pc:size>
<pc:description>Classification in LAS 1.0 was essentially user defined and optional. LAS 1.1 defines a standard set of ASPRS classifications. In addition, the field is now mandatory. If a point has never been classified, this byte must be set to zero. There are no user defined classes since both point format 0 and point format 1 supply 8 bits per point for user defined operations. Note that the format for classification is a bit encoded field with the lower five bits used for class and the three high bits used for flags.</pc:description>
<pc:name>Classification</pc:name>
<pc:interpretation>uint8_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>b4c67de9-cef1-432c-8909-7c751b2a4e0b</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>10</pc:position>
<pc:size>1</pc:size>
<pc:description>The Scan Angle Rank is a signed one-byte number with a valid range from -90 to +90. The Scan Angle Rank is the angle (rounded to the nearest integer in the absolute value sense) at which the laser point was output from the laser system including the roll of the aircraft. The scan angle is within 1 degree of accuracy from +90 to 90 degrees. The scan angle is an angle based on 0 degrees being nadir, and 90 degrees to the left side of the aircraft in the direction of flight.</pc:description>
<pc:name>ScanAngleRank</pc:name>
<pc:interpretation>int8_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>aaadaf77-e0c9-4df0-81a7-27060794cd69</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>11</pc:position>
<pc:size>1</pc:size>
<pc:description>This field may be used at the users discretion</pc:description>
<pc:name>UserData</pc:name>
<pc:interpretation>uint8_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>70eb558e-63d4-4804-b1db-fc2fd716927c</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>12</pc:position>
<pc:size>2</pc:size>
<pc:description>This value indicates the file from which this point originated. Valid values for this field are 1 to 65,535 inclusive with zero being used for a special case discussed below. The numerical value corresponds to the File Source ID from which this point originated. Zero is reserved as a convenience to system implementers. A Point Source ID of zero implies that this point originated in this file. This implies that processing software should set the Point Source ID equal to the File Source ID of the file containing this point at some time during processing. </pc:description>
<pc:name>PointSourceId</pc:name>
<pc:interpretation>uint16_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>4e42e96a-6af0-4fdd-81cb-6216ff47bf6b</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>13</pc:position>
<pc:size>8</pc:size>
<pc:description>The GPS Time is the double floating point time tag value at which the point was acquired. It is GPS Week Time if the Global Encoding low bit is clear and Adjusted Standard GPS Time if the Global Encoding low bit is set (see Global Encoding in the Public Header Block description).</pc:description>
<pc:name>Time</pc:name>
<pc:interpretation>double</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>aec43586-2711-4e59-9df0-65aca78a4ffc</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>14</pc:position>
<pc:size>2</pc:size>
<pc:description>The red image channel value associated with this point</pc:description>
<pc:name>Red</pc:name>
<pc:interpretation>uint16_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>a42ce297-6aa2-4a62-bd29-2db19ba862d5</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>15</pc:position>
<pc:size>2</pc:size>
<pc:description>The green image channel value associated with this point</pc:description>
<pc:name>Green</pc:name>
<pc:interpretation>uint16_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>7752759d-5713-48cd-9842-51db350cc979</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>16</pc:position>
<pc:size>2</pc:size>
<pc:description>The blue image channel value associated with this point</pc:description>
<pc:name>Blue</pc:name>
<pc:interpretation>uint16_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>5c1a99c8-1829-4d5b-8735-4f6f393a7970</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>17</pc:position>
<pc:size>4</pc:size>
<pc:description>Point ID within the chipper block for this point</pc:description>
<pc:name>PointID</pc:name>
<pc:interpretation>uint32_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>a5e90806-b12d-431f-8a26-584672853375</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>18</pc:position>
<pc:size>4</pc:size>
<pc:description>Block ID of the chipper block for this point</pc:description>
<pc:name>BlockID</pc:name>
<pc:interpretation>uint32_t</pc:interpretation>
<pc:scale>1</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>289657d3-3193-42da-b9a8-2c6dba73facf</pc:uuid>
<pc:parent_uuid>00000000-0000-0000-0000-000000000000</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>19</pc:position>
<pc:size>4</pc:size>
<pc:description>X coordinate as a long integer. You must use the scale and offset information of the header to determine the double value.</pc:description>
<pc:name>X</pc:name>
<pc:interpretation>int32_t</pc:interpretation>
<pc:scale>0.0000001</pc:scale>
<pc:offset>-127.390661926409</pc:offset>
<pc:active>true</pc:active>
<pc:uuid>2b1b0b1f-886e-4658-ae14-eeed0321846a</pc:uuid>
<pc:parent_uuid>2ee118d1-119e-4906-99c3-42934203f872</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>20</pc:position>
<pc:size>4</pc:size>
<pc:description>Y coordinate as a long integer. You must use the scale and offset information of the header to determine the double value.</pc:description>
<pc:name>Y</pc:name>
<pc:interpretation>int32_t</pc:interpretation>
<pc:scale>0.0000001</pc:scale>
<pc:offset>46.808297115426</pc:offset>
<pc:active>true</pc:active>
<pc:uuid>a510c76c-bed5-4196-85c9-fdce1a3f614f</pc:uuid>
<pc:parent_uuid>87707eee-2f30-4979-9987-8ef747e30275</pc:parent_uuid>
</pc:dimension>
<pc:dimension>
<pc:position>21</pc:position>
<pc:size>4</pc:size>
<pc:description>Z coordinate as a long integer. You must use the scale and offset information of the header to determine the double value.</pc:description>
<pc:name>Z</pc:name>
<pc:interpretation>int32_t</pc:interpretation>
<pc:scale>0.01</pc:scale>
<pc:active>true</pc:active>
<pc:uuid>34b5df9e-0b70-4e2e-97ec-3031b7e76946</pc:uuid>
<pc:parent_uuid>e74b5e41-95e6-4cf2-86ad-e3f5a996da5d</pc:parent_uuid>
</pc:dimension>
</pc:PointCloudSchema>

View File

@ -101,4 +101,6 @@ uint16_t pc_sigbits_16(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbit
uint32_t pc_sigbits_32(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits);
uint64_t pc_sigbits_64(const uint8_t *bytes8, uint32_t nelems, uint32_t *nsigbits);
uint8_t* pc_bytes_sigbits_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems, size_t *bytes_sigbits_size);
#endif /* _PC_API_INTERNAL_H */

View File

@ -347,3 +347,234 @@ pc_sigbits_count(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems)
return count;
}
uint8_t *
pc_bytes_sigbits_encode_8(const uint8_t *bytes, uint32_t nelems, uint8_t commonvalue, uint8_t commonbits, size_t *bytes_size)
{
int i;
int shift;
/* How wide are our words? */
static int bitwidth = 8;
/* How wide are our unique values? */
int nbits = bitwidth - commonbits;
/* Size of output buffer */
size_t size_out = (nbits * nelems / 8) + 2;
uint8_t *bytes_out = pcalloc(size_out);
/* Use this to zero out the parts that are common */
uint8_t mask = (0xFF >> commonbits);
/* Write head */
uint8_t *byte_ptr = bytes_out + 1;
/* What bit are we writing to now? */
int bit = bitwidth;
/* Common value goes up front, unmolested */
bytes_out[0] = commonvalue;
for ( i = 0; i < nelems; i++ )
{
uint8_t val = bytes[i];
/* Clear off common parts */
val &= mask;
/* How far to move unique parts to get to write head? */
shift = bit - nbits;
/* If positive, we can fit this part into the current word */
if ( shift >= 0 )
{
val <<= shift;
*byte_ptr |= val;
bit -= nbits;
if ( bit <= 0 )
{
bit = bitwidth;
byte_ptr++;
}
}
/* If negative, then we need to split this part across words */
else
{
/* First the bit into the current word */
uint8_t v = val;
int s = abs(shift);
v >>= s;
*byte_ptr |= v;
/* The reset to write the next word */
bit = bitwidth;
byte_ptr++;
v = val;
shift = bit - s;
/* But only those parts we didn't already write */
v <<= shift;
*byte_ptr |= v;
bit -= s;
}
}
*bytes_size = size_out;
return bytes_out;
}
uint8_t *
pc_bytes_sigbits_encode_16(const uint8_t *bytes8, uint32_t nelems, uint16_t commonvalue, uint8_t commonbits, size_t *bytes_size)
{
int i;
int shift;
uint16_t *bytes = (uint16_t*)bytes8;
/* How wide are our words? */
static int bitwidth = 16;
/* How wide are our unique values? */
int nbits = bitwidth - commonbits;
/* Size of output buffer */
size_t size_out = (nbits * nelems / 8) + 4;
uint16_t *bytes_out = pcalloc(size_out);
/* Use this to zero out the parts that are common */
uint16_t mask = (0xFFFF >> commonbits);
/* Write head */
uint16_t *byte_ptr = bytes_out + 1;
/* What bit are we writing to now? */
int bit = bitwidth;
/* Common value goes up front, unmolested */
bytes_out[0] = commonvalue;
for ( i = 0; i < nelems; i++ )
{
uint16_t val = bytes[i];
/* Clear off common parts */
val &= mask;
/* How far to move unique parts to get to write head? */
shift = bit - nbits;
/* If positive, we can fit this part into the current word */
if ( shift >= 0 )
{
val <<= shift;
*byte_ptr |= val;
bit -= nbits;
if ( bit <= 0 )
{
bit = bitwidth;
byte_ptr++;
}
}
/* If negative, then we need to split this part across words */
else
{
/* First the bit into the current word */
uint16_t v = val;
int s = abs(shift);
v >>= s;
*byte_ptr |= v;
/* The reset to write the next word */
bit = bitwidth;
byte_ptr++;
v = val;
shift = bit - s;
/* But only those parts we didn't already write */
v <<= shift;
*byte_ptr |= v;
bit -= s;
}
}
*bytes_size = size_out;
return (uint8_t*)bytes_out;
}
uint8_t *
pc_bytes_sigbits_encode_32(const uint8_t *bytes8, uint32_t nelems, uint32_t commonvalue, uint8_t commonbits, size_t *bytes_size)
{
int i;
int shift;
uint32_t *bytes = (uint32_t*)bytes8;
/* How wide are our words? */
static int bitwidth = 32;
/* How wide are our unique values? */
int nbits = bitwidth - commonbits;
/* Size of output buffer */
size_t size_out = (nbits * nelems / 8) + 8;
uint32_t *bytes_out = pcalloc(size_out);
/* Use this to zero out the parts that are common */
uint32_t mask = (0xFFFFFFFF >> commonbits);
/* Write head */
uint32_t *byte_ptr = bytes_out + 1;
/* What bit are we writing to now? */
int bit = bitwidth;
/* Common value goes up front, unmolested */
bytes_out[0] = commonvalue;
for ( i = 0; i < nelems; i++ )
{
uint32_t val = bytes[i];
/* Clear off common parts */
val &= mask;
/* How far to move unique parts to get to write head? */
shift = bit - nbits;
/* If positive, we can fit this part into the current word */
if ( shift >= 0 )
{
val <<= shift;
*byte_ptr |= val;
bit -= nbits;
if ( bit <= 0 )
{
bit = bitwidth;
byte_ptr++;
}
}
/* If negative, then we need to split this part across words */
else
{
/* First the bit into the current word */
uint32_t v = val;
int s = abs(shift);
v >>= s;
*byte_ptr |= v;
/* The reset to write the next word */
bit = bitwidth;
byte_ptr++;
v = val;
shift = bit - s;
/* But only those parts we didn't already write */
v <<= shift;
*byte_ptr |= v;
bit -= s;
}
}
*bytes_size = size_out;
return (uint8_t*)bytes_out;
}
uint8_t *
pc_bytes_sigbits_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems, size_t *ebytes_size)
{
size_t size = INTERPRETATION_SIZES[interpretation];
uint32_t nbits;
switch ( size )
{
case 1:
{
uint8_t commonvalue = pc_sigbits_8(bytes, nelems, &nbits);
return pc_bytes_sigbits_encode_8(bytes, nelems, commonvalue, nbits, ebytes_size);
}
case 2:
{
uint16_t commonvalue = pc_sigbits_16(bytes, nelems, &nbits);
return pc_bytes_sigbits_encode_16(bytes, nelems, commonvalue, nbits, ebytes_size);
}
case 4:
{
uint16_t commonvalue = pc_sigbits_32(bytes, nelems, &nbits);
return pc_bytes_sigbits_encode_32(bytes, nelems, commonvalue, nbits, ebytes_size);
}
default:
{
pcerror("Uh oh");
}
}
pcerror("Uh Oh");
return NULL;
}