mirror of https://github.com/ARMmbed/mbed-os.git
commit
a0a9b54e97
|
@ -0,0 +1,145 @@
|
|||
"""
|
||||
Copyright (c) 2018 ARM Limited
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
"""
|
||||
This script is the host script for trng test sequence, it send the
|
||||
step signaling sequence and receive and transmit data to the device after
|
||||
reset if necesarry (default loading and storing mechanism while reseting the device
|
||||
is NVstore, in case NVstore isn't enabled we'll use current infrastructure,
|
||||
for more details see main.cpp file)
|
||||
"""
|
||||
|
||||
import time
|
||||
from mbed_host_tests import BaseHostTest
|
||||
from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector
|
||||
from time import sleep
|
||||
|
||||
DEFAULT_CYCLE_PERIOD = 1.0
|
||||
MSG_VALUE_DUMMY = '0'
|
||||
MSG_TRNG_READY = 'ready'
|
||||
MSG_TRNG_BUFFER = 'buffer'
|
||||
MSG_TRNG_TEST_STEP1 = 'check_step1'
|
||||
MSG_TRNG_TEST_STEP2 = 'check_step2'
|
||||
MSG_KEY_SYNC = '__sync'
|
||||
MSG_KEY_RESET_COMPLETE = 'reset_complete'
|
||||
MSG_KEY_TEST_SUITE_ENDED = 'Test_suite_ended'
|
||||
MSG_KEY_EXIT = 'exit'
|
||||
|
||||
class TRNGResetTest(BaseHostTest):
|
||||
"""Test for the TRNG API.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(TRNGResetTest, self).__init__()
|
||||
self.did_reset = False
|
||||
self.ready = False
|
||||
self.suite_ended = False
|
||||
self.buffer = 0
|
||||
self.test_steps_sequence = self.test_steps()
|
||||
# Advance the coroutine to it's first yield statement.
|
||||
self.test_steps_sequence.send(None)
|
||||
|
||||
#define callback functions for msg handling
|
||||
def setup(self):
|
||||
self.register_callback(MSG_TRNG_READY, self.cb_device_ready)
|
||||
self.register_callback(MSG_TRNG_BUFFER, self.cb_trng_buffer)
|
||||
self.register_callback(MSG_KEY_TEST_SUITE_ENDED, self.cb_device_test_suit_ended)
|
||||
self.register_callback(MSG_KEY_RESET_COMPLETE, self.cb_reset_complete)
|
||||
|
||||
#receive sent data from device before reset
|
||||
def cb_trng_buffer(self, key, value, timestamp):
|
||||
"""Acknowledge device rebooted correctly and feed the test execution
|
||||
"""
|
||||
self.buffer = value
|
||||
|
||||
try:
|
||||
if self.test_steps_sequence.send(value):
|
||||
self.notify_complete(True)
|
||||
except (StopIteration, RuntimeError) as exc:
|
||||
self.notify_complete(False)
|
||||
|
||||
def cb_device_ready(self, key, value, timestamp):
|
||||
"""Acknowledge device rebooted correctly and feed the test execution
|
||||
"""
|
||||
self.ready = True
|
||||
|
||||
try:
|
||||
if self.test_steps_sequence.send(value):
|
||||
self.notify_complete(True)
|
||||
except (StopIteration, RuntimeError) as exc:
|
||||
self.notify_complete(False)
|
||||
|
||||
def cb_reset_complete(self, key, value, timestamp):
|
||||
"""Acknowledge reset complete
|
||||
"""
|
||||
self.did_reset = True
|
||||
|
||||
try:
|
||||
if self.test_steps_sequence.send(value):
|
||||
self.notify_complete(True)
|
||||
except (StopIteration, RuntimeError) as exc:
|
||||
self.notify_complete(False)
|
||||
|
||||
def cb_device_test_suit_ended(self, key, value, timestamp):
|
||||
"""Acknowledge device finished a test step correctly and feed the test execution
|
||||
"""
|
||||
self.suite_ended = True
|
||||
|
||||
try:
|
||||
if self.test_steps_sequence.send(value):
|
||||
self.notify_complete(True)
|
||||
except (StopIteration, RuntimeError) as exc:
|
||||
self.notify_complete(False)
|
||||
|
||||
#define test steps and actions
|
||||
def test_steps(self):
|
||||
"""Test step 1
|
||||
"""
|
||||
wait_for_communication = yield
|
||||
|
||||
self.ready = False
|
||||
self.did_reset = False
|
||||
self.suite_ended = False
|
||||
self.send_kv(MSG_TRNG_TEST_STEP1, MSG_VALUE_DUMMY)
|
||||
wait_for_communication = yield
|
||||
if self.buffer == 0:
|
||||
raise RuntimeError('Phase 1: No buffer received.')
|
||||
|
||||
self.reset()
|
||||
|
||||
"""Test step 2 (After reset)
|
||||
"""
|
||||
wait_for_communication = yield
|
||||
if self.did_reset == False:
|
||||
raise RuntimeError('Phase 1: Platform did not reset as expected.')
|
||||
|
||||
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||
|
||||
wait_for_communication = yield
|
||||
|
||||
if self.ready == False:
|
||||
raise RuntimeError('Phase 1: Platform not ready as expected.')
|
||||
|
||||
self.send_kv(MSG_TRNG_TEST_STEP2, self.buffer)
|
||||
|
||||
wait_for_communication = yield
|
||||
|
||||
if self.suite_ended == False:
|
||||
raise RuntimeError('Test failed.')
|
||||
|
||||
self.send_kv(MSG_KEY_EXIT, MSG_VALUE_DUMMY)
|
||||
|
||||
# The sequence is correct -- test passed.
|
||||
yield
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "base64b.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static char IntToBase64Char(uint8_t intVal)
|
||||
{
|
||||
const char *base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
return base64Digits[intVal & 0x3F];
|
||||
}
|
||||
|
||||
#define BASE_64_PAD 0xFF
|
||||
static base64_result_e Base64CharToInt(char base64, uint8_t *intVal)
|
||||
{
|
||||
if (NULL == intVal) {
|
||||
return BASE64_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((base64 >= 'A') && (base64 <= 'Z')) {
|
||||
*intVal = base64 - 'A' ;
|
||||
} else if ((base64 >= 'a') && (base64 <= 'z')) {
|
||||
*intVal = base64 - 'a' + 26;
|
||||
} else if ((base64 >= '0') && (base64 <= '9')) {
|
||||
*intVal = base64 - '0' + 52;
|
||||
} else if (base64 == '+') {
|
||||
*intVal = 62;
|
||||
} else if (base64 == '/') {
|
||||
*intVal = 63;
|
||||
} else if (base64 == '=') {
|
||||
*intVal = BASE_64_PAD;
|
||||
} else {
|
||||
return BASE64_ERROR;
|
||||
}
|
||||
|
||||
return BASE64_SUCCESS;
|
||||
}
|
||||
|
||||
base64_result_e trng_DecodeNBase64(const char *string,
|
||||
uint32_t stringMaxSize,
|
||||
void *buffer,
|
||||
uint32_t bufferSize,
|
||||
uint32_t *lengthWritten,
|
||||
uint32_t *charsProcessed)
|
||||
{
|
||||
base64_result_e result = BASE64_SUCCESS;
|
||||
uint32_t bitOffset = 0;
|
||||
uint8_t *writePtr = (uint8_t *)buffer;
|
||||
uint8_t *bufferEnd = (uint8_t *)buffer + bufferSize;
|
||||
uint8_t tempVal = 0;
|
||||
uint32_t currPos = 0;
|
||||
uint32_t localBytesWritten = 0;
|
||||
uint32_t localCharsProcessed = 0;
|
||||
bool isEndOfString = false;
|
||||
|
||||
if ((NULL == string) || (NULL == buffer) || (bufferSize == 0)) {
|
||||
return BASE64_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*writePtr = 0;
|
||||
while (( currPos < stringMaxSize ) &&
|
||||
( string[currPos] != 0 ) &&
|
||||
( writePtr < bufferEnd ) &&
|
||||
( !isEndOfString )) {
|
||||
uint8_t val;
|
||||
|
||||
if (string[currPos] == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
result = Base64CharToInt(string[currPos++], &val);
|
||||
if (result != BASE64_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (val != BASE_64_PAD) {
|
||||
if (bitOffset <= 2) {
|
||||
tempVal |= val << (2 - bitOffset);
|
||||
if (bitOffset == 2) {
|
||||
*writePtr++ = tempVal;
|
||||
tempVal = 0;
|
||||
}
|
||||
} else {
|
||||
*writePtr++ = (uint8_t)(tempVal | (val >> (bitOffset - 2)));
|
||||
tempVal = (uint8_t)(val << (10 - bitOffset));
|
||||
}
|
||||
} else { // found BASE_64_PAD
|
||||
// At most two pad characters may occur at the end of the encoded stream
|
||||
if (bitOffset == 2) {
|
||||
isEndOfString = true; // The last padding byte has been processed.
|
||||
} else if (bitOffset != 4) {
|
||||
return BASE64_ERROR; // Incorrect padding
|
||||
}
|
||||
}
|
||||
|
||||
bitOffset = (bitOffset + 6) & 0x7;
|
||||
if (bitOffset == 0) {
|
||||
localBytesWritten = (uint32_t)(writePtr - (uint8_t *)buffer);
|
||||
localCharsProcessed = currPos;
|
||||
}
|
||||
}
|
||||
if (charsProcessed == NULL) {
|
||||
localBytesWritten = (uint32_t)(writePtr - (uint8_t *)buffer);
|
||||
} else {
|
||||
*charsProcessed = localCharsProcessed;
|
||||
}
|
||||
if (lengthWritten != NULL) {
|
||||
*lengthWritten = localBytesWritten;
|
||||
} else if (bufferSize != localBytesWritten) {
|
||||
return BASE64_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
// Check if additional bytes should have been processed but buffer isn't sufficient.
|
||||
if (( result == BASE64_SUCCESS ) &&
|
||||
( !isEndOfString ) &&
|
||||
( currPos < stringMaxSize ) &&
|
||||
( string[currPos] != 0 ) &&
|
||||
( string[currPos] != '=' ) ) {
|
||||
return BASE64_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (result != BASE64_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return BASE64_SUCCESS;
|
||||
}
|
||||
|
||||
base64_result_e trng_EncodeBase64(const void *buffer, uint32_t bufferSize, char *string, uint32_t stringSize)
|
||||
{
|
||||
uint32_t bitOffset = 0;
|
||||
|
||||
const uint8_t *readPtr = (const uint8_t *)buffer;
|
||||
const uint8_t *bufferEnd = (const uint8_t *)buffer + bufferSize;
|
||||
|
||||
char *writePtr = string;
|
||||
char *stringEnd = string + stringSize - 1;
|
||||
|
||||
if ((NULL == string) || (NULL == buffer) || (stringSize == 0)) {
|
||||
return BASE64_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
stringSize--;
|
||||
while (readPtr < bufferEnd && writePtr < stringEnd) {
|
||||
uint8_t tempVal = 0;
|
||||
switch (bitOffset) {
|
||||
case 0:
|
||||
*writePtr++ = IntToBase64Char(*readPtr >> 2); // take upper 6 bits
|
||||
break;
|
||||
case 6:
|
||||
tempVal = *readPtr++ << 4;
|
||||
if (readPtr < bufferEnd) {
|
||||
tempVal |= *readPtr >> 4;
|
||||
}
|
||||
*writePtr++ = IntToBase64Char(tempVal);
|
||||
break;
|
||||
case 4:
|
||||
tempVal = *readPtr++ << 2;
|
||||
if (readPtr < bufferEnd) {
|
||||
tempVal |= *readPtr >> 6;
|
||||
}
|
||||
*writePtr++ = IntToBase64Char(tempVal);
|
||||
break;
|
||||
case 2:
|
||||
*writePtr++ = IntToBase64Char(*readPtr++);
|
||||
break;
|
||||
default:
|
||||
return BASE64_ERROR; // we should never reach this code.
|
||||
}
|
||||
bitOffset = (bitOffset + 6) & 0x7;
|
||||
}
|
||||
while (bitOffset > 0 && writePtr < stringEnd) {
|
||||
*writePtr++ = '=';
|
||||
bitOffset = (bitOffset + 6) & 0x7;
|
||||
}
|
||||
*writePtr = 0;
|
||||
|
||||
if ((readPtr < bufferEnd) || (bitOffset != 0)) {
|
||||
return (BASE64_BUFFER_TOO_SMALL);
|
||||
}
|
||||
|
||||
return (BASE64_SUCCESS);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
typedef enum {
|
||||
BASE64_SUCCESS = 0,
|
||||
BASE64_INVALID_PARAMETER = 1,
|
||||
BASE64_BUFFER_TOO_SMALL = 2,
|
||||
BASE64_ERROR = 3,
|
||||
} base64_result_e;
|
||||
|
||||
base64_result_e trng_EncodeBase64(const void *buffer, uint32_t bufferSize, char *string, uint32_t stringSize);
|
||||
base64_result_e trng_DecodeNBase64(const char *string, uint32_t stringMaxSize, void *buffer, uint32_t bufferSize,
|
||||
uint32_t *lengthWritten, uint32_t *charsProcessed);
|
||||
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The test is based on the assumption that trng will generate random data, random so
|
||||
* there will not be any similar patterns in it, that kind of data will be impossible to
|
||||
* compress, if compression will occur the test will result in failure.
|
||||
*
|
||||
* The test is composed out of three parts:
|
||||
* the first, generate a trng buffer and try to compress it, at the end of first part
|
||||
* we will reset the device.
|
||||
* In second part we will generate a trng buffer with a different buffer size and try to
|
||||
* compress it.
|
||||
* In the third part we will again generate a trng buffer to see that the same trng output
|
||||
* is not generated as the stored trng buffer from part one (before reseting), the new trng data will
|
||||
* be concatenated to the trng data from the first part and then try to compress it
|
||||
* together, if there are similar patterns the compression will succeed.
|
||||
*
|
||||
* We need to store and load the first part data before and after reset, the mechanism
|
||||
* we will use is the mbed greentea platform for sending and receving the data from the device
|
||||
* to the host running the test and back, the problem with this mechanism is that it doesn't
|
||||
* handle well certain characters, especially non ASCII ones, so we use the base64 algorithm
|
||||
* to ensure all characters will be transmitted correctly.
|
||||
*/
|
||||
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity/unity.h"
|
||||
#include "utest/utest.h"
|
||||
#include "hal/trng_api.h"
|
||||
#include "base64b.h"
|
||||
#include "pithy.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if !DEVICE_TRNG
|
||||
#error [NOT_SUPPORTED] TRNG API not supported for this target
|
||||
#endif
|
||||
|
||||
#define MSG_VALUE_DUMMY "0"
|
||||
#define MSG_VALUE_LEN 64
|
||||
#define MSG_KEY_LEN 32
|
||||
|
||||
#define BUFFER_LEN (MSG_VALUE_LEN/2)
|
||||
|
||||
#define MSG_TRNG_READY "ready"
|
||||
#define MSG_TRNG_BUFFER "buffer"
|
||||
#define MSG_TRNG_EXIT "exit"
|
||||
|
||||
#define MSG_TRNG_TEST_STEP1 "check_step1"
|
||||
#define MSG_TRNG_TEST_STEP2 "check_step2"
|
||||
#define MSG_TRNG_TEST_SUITE_ENDED "Test_suite_ended"
|
||||
|
||||
#define RESULT_SUCCESS 0
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
static int fill_buffer_trng(uint8_t *buffer, trng_t *trng_obj, size_t trng_len)
|
||||
{
|
||||
size_t temp_size = 0, output_length = 0;
|
||||
int trng_res = 0;
|
||||
uint8_t *temp_in_buf = buffer;
|
||||
|
||||
trng_init(trng_obj);
|
||||
memset(buffer, 0, BUFFER_LEN);
|
||||
|
||||
while (true) {
|
||||
trng_res = trng_get_bytes(trng_obj, temp_in_buf, trng_len - temp_size, &output_length);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, trng_res, "trng_get_bytes error!");
|
||||
temp_size += output_length;
|
||||
temp_in_buf += output_length;
|
||||
if (temp_size >= trng_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
temp_in_buf = NULL;
|
||||
trng_free(trng_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_array(uint8_t *buffer, size_t size)
|
||||
{
|
||||
for (size_t i=0; i < size; i++) {
|
||||
utest_printf("%02x", buffer[i]);
|
||||
}
|
||||
utest_printf("\n");
|
||||
}
|
||||
|
||||
static void compress_and_compare(char *key, char *value)
|
||||
{
|
||||
trng_t trng_obj;
|
||||
uint8_t *out_comp_buf, *buffer;
|
||||
uint8_t *input_buf, *temp_buf;
|
||||
size_t comp_sz = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
#define OUT_COMP_BUF_SIZE ((BUFFER_LEN * 5) + 32)
|
||||
#define TEMP_BUF_SIZE (BUFFER_LEN * 2)
|
||||
|
||||
out_comp_buf = new uint8_t[OUT_COMP_BUF_SIZE];
|
||||
buffer = new uint8_t[BUFFER_LEN];
|
||||
temp_buf = new uint8_t[BUFFER_LEN * 2];
|
||||
input_buf = new uint8_t[BUFFER_LEN * 4];
|
||||
|
||||
/*At the begining of step 2 load trng buffer from step 1*/
|
||||
if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
|
||||
/*Using base64 to decode data sent from host*/
|
||||
uint32_t lengthWritten = 0;
|
||||
uint32_t charsProcessed = 0;
|
||||
result = trng_DecodeNBase64((const char *)value,
|
||||
MSG_VALUE_LEN,
|
||||
buffer,
|
||||
BUFFER_LEN,
|
||||
&lengthWritten,
|
||||
&charsProcessed);
|
||||
TEST_ASSERT_EQUAL(0, result);
|
||||
memcpy(input_buf, buffer, BUFFER_LEN);
|
||||
}
|
||||
|
||||
if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
|
||||
/*Fill buffer with trng values*/
|
||||
result = fill_buffer_trng(buffer, &trng_obj, BUFFER_LEN);
|
||||
TEST_ASSERT_EQUAL(0, result);
|
||||
memcpy(input_buf, buffer, BUFFER_LEN);
|
||||
}
|
||||
/*pithy_Compress will try to compress the random data, if it succeeded it means the data is not really random*/
|
||||
else if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
|
||||
|
||||
comp_sz = pithy_Compress((char *)buffer,
|
||||
BUFFER_LEN,
|
||||
(char *)out_comp_buf,
|
||||
OUT_COMP_BUF_SIZE,
|
||||
9);
|
||||
if (comp_sz <= BUFFER_LEN){
|
||||
print_array(buffer, BUFFER_LEN);
|
||||
}
|
||||
TEST_ASSERT_MESSAGE(comp_sz > BUFFER_LEN,
|
||||
"TRNG_TEST_STEP1: trng_get_bytes was able to compress thus not random");
|
||||
|
||||
/*pithy_Compress will try to compress the random data with a different buffer size*/
|
||||
result = fill_buffer_trng(temp_buf, &trng_obj, TEMP_BUF_SIZE);
|
||||
TEST_ASSERT_EQUAL(0, result);
|
||||
|
||||
comp_sz = pithy_Compress((char *)temp_buf,
|
||||
TEMP_BUF_SIZE,
|
||||
(char *)out_comp_buf,
|
||||
OUT_COMP_BUF_SIZE,
|
||||
9);
|
||||
if (comp_sz <= TEMP_BUF_SIZE){
|
||||
print_array(temp_buf, TEMP_BUF_SIZE);
|
||||
}
|
||||
TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE,
|
||||
"TRNG_TEST_STEP2: trng_get_bytes was able to compress thus not random");
|
||||
|
||||
memcpy(input_buf + BUFFER_LEN, temp_buf, TEMP_BUF_SIZE);
|
||||
/*pithy_Compress will try to compress the random data from before reset concatenated with new random data*/
|
||||
comp_sz = pithy_Compress((char *)input_buf,
|
||||
TEMP_BUF_SIZE + BUFFER_LEN,
|
||||
(char *)out_comp_buf,
|
||||
OUT_COMP_BUF_SIZE,
|
||||
9);
|
||||
if (comp_sz <= TEMP_BUF_SIZE + BUFFER_LEN){
|
||||
print_array(input_buf, TEMP_BUF_SIZE + BUFFER_LEN);
|
||||
}
|
||||
TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE + BUFFER_LEN,
|
||||
"TRNG_TEST_STEP3: concatenated buffer after reset was able to compress thus not random");
|
||||
|
||||
greentea_send_kv(MSG_TRNG_TEST_SUITE_ENDED, MSG_VALUE_DUMMY);
|
||||
}
|
||||
|
||||
/*At the end of step 1 store trng buffer and reset the device*/
|
||||
if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
|
||||
int result = 0;
|
||||
/*Using base64 to encode data sending from host*/
|
||||
result = trng_EncodeBase64(buffer,
|
||||
BUFFER_LEN,
|
||||
(char *)out_comp_buf,
|
||||
OUT_COMP_BUF_SIZE);
|
||||
TEST_ASSERT_EQUAL(RESULT_SUCCESS, result);
|
||||
|
||||
greentea_send_kv(MSG_TRNG_BUFFER, (const char *)out_comp_buf);
|
||||
}
|
||||
|
||||
delete[] out_comp_buf;
|
||||
delete[] buffer;
|
||||
delete[] input_buf;
|
||||
delete[] temp_buf;
|
||||
}
|
||||
|
||||
/*This method call first and second steps, it directs by the key received from the host*/
|
||||
void trng_test()
|
||||
{
|
||||
greentea_send_kv(MSG_TRNG_READY, MSG_VALUE_DUMMY);
|
||||
|
||||
char key[MSG_KEY_LEN + 1] = { };
|
||||
char *value = new char[MSG_VALUE_LEN + 1];
|
||||
do {
|
||||
memset(key, 0, MSG_KEY_LEN + 1);
|
||||
memset(value, 0, MSG_VALUE_LEN + 1);
|
||||
|
||||
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||
|
||||
if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
|
||||
/*create trng data buffer and try to compress it, store it for later checks*/
|
||||
compress_and_compare(key, value);
|
||||
}
|
||||
|
||||
if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
|
||||
/*create another trng data buffer and concatenate it to the stored trng data buffer
|
||||
try to compress them both*/
|
||||
compress_and_compare(key, value);
|
||||
}
|
||||
} while (strcmp(key, MSG_TRNG_EXIT) != 0);
|
||||
|
||||
delete[] value;
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("TRNG: trng_test", trng_test),
|
||||
};
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(100, "trng_reset");
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
||||
|
||||
int main()
|
||||
{
|
||||
bool ret = !Harness::run(specification);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,795 @@
|
|||
//
|
||||
// pithy.c
|
||||
// http://github.com/johnezang/pithy
|
||||
// Licensed under the terms of the BSD License, as specified below.
|
||||
//
|
||||
|
||||
/*
|
||||
Copyright (c) 2011, John Engelhart
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the Zang Industries nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__arm__) && defined(__ARM_NEON__)
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#include "pithy.h"
|
||||
|
||||
#define kBlockLog 20ul
|
||||
#define kBlockSize ((size_t)(1 << kBlockLog))
|
||||
|
||||
// The maximum size that can be compressed while still allowing for the worst case compression expansion.
|
||||
#define PITHY_UNCOMPRESSED_MAX_LENGTH 0xdb6db6bfu // 0xdb6db6bf == 3681400511, or 3510.857 Mbytes.
|
||||
|
||||
typedef const char *pithy_hashOffset_t;
|
||||
|
||||
enum {
|
||||
PITHY_LITERAL = 0,
|
||||
PITHY_COPY_1_BYTE_OFFSET = 1,
|
||||
PITHY_COPY_2_BYTE_OFFSET = 2,
|
||||
PITHY_COPY_3_BYTE_OFFSET = 3
|
||||
};
|
||||
|
||||
|
||||
#if defined (__GNUC__) && (__GNUC__ >= 3)
|
||||
#define PITHY_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__))
|
||||
#define PITHY_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect))
|
||||
#define PITHY_EXPECT_T(cond) PITHY_EXPECTED(cond, 1u)
|
||||
#define PITHY_EXPECT_F(cond) PITHY_EXPECTED(cond, 0u)
|
||||
#define PITHY_PREFETCH(ptr) __builtin_prefetch(ptr)
|
||||
#else // defined (__GNUC__) && (__GNUC__ >= 3)
|
||||
#define PITHY_ATTRIBUTES(attr, ...)
|
||||
#define PITHY_EXPECTED(cond, expect) (cond)
|
||||
#define PITHY_EXPECT_T(cond) (cond)
|
||||
#define PITHY_EXPECT_F(cond) (cond)
|
||||
#define PITHY_PREFETCH(ptr)
|
||||
#endif // defined (__GNUC__) && (__GNUC__ >= 3)
|
||||
|
||||
#define PITHY_STATIC_INLINE static inline PITHY_ATTRIBUTES(always_inline)
|
||||
#define PITHY_ALIGNED(x) PITHY_ATTRIBUTES(aligned(x))
|
||||
|
||||
#if defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG)
|
||||
#define NDEBUG
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define DCHECK(condition)
|
||||
#else
|
||||
#define DCHECK(condition) do { \
|
||||
if(PITHY_EXPECT_F(!(condition))) { \
|
||||
fprintf(stderr, "%s / %s @ %ld: Invalid parameter not satisfying: %s", \
|
||||
__FILE__, __PRETTY_FUNCTION__, (long)__LINE__, #condition); fflush(stderr); \
|
||||
abort(); \
|
||||
} \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *OUTPUT);
|
||||
PITHY_STATIC_INLINE char *pithy_Encode32(char *ptr, uint32_t v);
|
||||
|
||||
PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset);
|
||||
PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift);
|
||||
PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit);
|
||||
PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path);
|
||||
PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len);
|
||||
PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len);
|
||||
PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len);
|
||||
|
||||
PITHY_STATIC_INLINE uint16_t pithy_Load16(const void *p) { uint16_t t; memcpy(&t, p, sizeof(t)); return (t); }
|
||||
PITHY_STATIC_INLINE uint32_t pithy_Load32(const void *p) { uint32_t t; memcpy(&t, p, sizeof(t)); return (t); }
|
||||
PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return (t); }
|
||||
PITHY_STATIC_INLINE void pithy_Store16(void *p, uint16_t v) { memcpy(p, &v, sizeof(v)); }
|
||||
PITHY_STATIC_INLINE void pithy_Store32(void *p, uint32_t v) { memcpy(p, &v, sizeof(v)); }
|
||||
PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); }
|
||||
|
||||
#define pithy_Move64(dst,src) pithy_Store64(dst, pithy_Load64(src));
|
||||
#define pithy_Move128(dst,src) pithy_Move64(dst, src); pithy_Move64(dst + 8ul, src + 8ul);
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h>
|
||||
#define pithy_bswap_16(x) _byteswap_ushort(x)
|
||||
#define pithy_bswap_32(x) _byteswap_ulong(x)
|
||||
#define pithy_bswap_64(x) _byteswap_uint64(x)
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
// Mac OS X / Darwin features
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define pithy_bswap_16(x) OSSwapInt16(x)
|
||||
#define pithy_bswap_32(x) OSSwapInt32(x)
|
||||
#define pithy_bswap_64(x) OSSwapInt64(x)
|
||||
#else
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#endif // __BIG_ENDIAN__
|
||||
|
||||
// Conversion functions.
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define pithy_FromHost16(x) ((uint16_t)pithy_bswap_16(x))
|
||||
#define pithy_ToHost16(x) ((uint16_t)pithy_bswap_16(x))
|
||||
#define pithy_FromHost32(x) ((uint32_t)pithy_bswap_32(x))
|
||||
#define pithy_ToHost32(x) ((uint32_t)pithy_bswap_32(x))
|
||||
#define pithy_IsLittleEndian() (0)
|
||||
|
||||
#else // !defined(__BIG_ENDIAN__)
|
||||
#define pithy_FromHost16(x) ((uint16_t)(x))
|
||||
#define pithy_ToHost16(x) ((uint16_t)(x))
|
||||
#define pithy_FromHost32(x) ((uint32_t)(x))
|
||||
#define pithy_ToHost32(x) ((uint32_t)(x))
|
||||
#define pithy_IsLittleEndian() (1)
|
||||
|
||||
#endif // !defined(__BIG_ENDIAN__)
|
||||
|
||||
#define pithy_LoadHost16(p) pithy_ToHost16(pithy_Load16((const void *)(p)))
|
||||
#define pithy_StoreHost16(p, v) pithy_Store16((void *)(p), pithy_FromHost16(v))
|
||||
#define pithy_LoadHost32(p) pithy_ToHost32(pithy_Load32((p)))
|
||||
#define pithy_StoreHost32(p, v) pithy_Store32((p), pithy_FromHost32(v))
|
||||
|
||||
PITHY_STATIC_INLINE void pithy_StoreHost24(char *p, uint32_t v)
|
||||
{
|
||||
*p++ = (v & 0xffu);
|
||||
*p++ = ((v >> 8) & 0xffu);
|
||||
*p++ = ((v >> 16) & 0xffu);
|
||||
}
|
||||
|
||||
#if defined (__GNUC__) && (__GNUC__ >= 3)
|
||||
|
||||
#define pithy_Log2Floor(n) ({typeof(n) _n = (n); _n == 0 ? (int)-1 : (int)(31 ^ __builtin_clz(_n));})
|
||||
#define pithy_FindLSBSetNonZero32(n) ((int)__builtin_ctz((uint32_t)(n)))
|
||||
#define pithy_FindLSBSetNonZero64(n) ((int)__builtin_ctzll((uint64_t)(n)))
|
||||
#define pithy_FindMSBSetNonZero32(n) ((int)__builtin_clz((uint32_t)(n)))
|
||||
#define pithy_FindMSBSetNonZero64(n) ((int)__builtin_clzll((uint64_t)(n)))
|
||||
|
||||
#else // Portable versions, !GNUC || GNUC < 3
|
||||
|
||||
PITHY_STATIC_INLINE int pithy_Log2Floor(uint32_t n)
|
||||
{
|
||||
if (n == 0u) {
|
||||
return (-1);
|
||||
}
|
||||
int i = 0, log = 0;
|
||||
uint32_t value = n;
|
||||
for (i = 4; i >= 0; --i) {
|
||||
int shift = (1 << i);
|
||||
uint32_t x = value >> shift;
|
||||
if (x != 0u) {
|
||||
value = x;
|
||||
log += shift;
|
||||
}
|
||||
}
|
||||
DCHECK(value == 1);
|
||||
return (log);
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero32(uint32_t n)
|
||||
{
|
||||
int i = 0, rc = 31, shift = 0;
|
||||
for (i = 4, shift = 1 << 4; i >= 0; --i) {
|
||||
const uint32_t x = n << shift;
|
||||
if (x != 0u) {
|
||||
n = x;
|
||||
rc -= shift;
|
||||
}
|
||||
shift >>= 1;
|
||||
}
|
||||
return (rc);
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero64(uint64_t n)
|
||||
{
|
||||
const uint32_t bottomBits = n;
|
||||
if (bottomBits == 0u) {
|
||||
return (32 + pithy_FindLSBSetNonZero32((n >> 32)));
|
||||
} else {
|
||||
return (pithy_FindLSBSetNonZero32(bottomBits));
|
||||
}
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero32(uint32_t n)
|
||||
{
|
||||
int i;
|
||||
uint32_t x, rc = 32, shift = 1 << 4;
|
||||
for (i = 3; i >= 0; --i) {
|
||||
x = n >> shift;
|
||||
if (x != 0) {
|
||||
rc -= shift;
|
||||
n = x;
|
||||
}
|
||||
shift >>= 1;
|
||||
}
|
||||
x = n >> shift;
|
||||
return (rc - ((x != 0) ? 2 : n));
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero64(uint64_t n)
|
||||
{
|
||||
const uint32_t upperBits = n >> 32;
|
||||
if (upperBits == 0u) {
|
||||
return (32 + pithy_FindMSBSetNonZero32((n)));
|
||||
} else {
|
||||
return (pithy_FindMSBSetNonZero32(upperBits));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // End portable versions.
|
||||
|
||||
PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *resultOut)
|
||||
{
|
||||
const unsigned char *ptr = (const unsigned char *)p, *limit = (const unsigned char *)l;
|
||||
size_t resultShift = 0ul, result = 0ul;
|
||||
uint32_t encodedByte = 0u;
|
||||
|
||||
for (resultShift = 0ul; resultShift <= 28ul; resultShift += 7ul) {
|
||||
if (ptr >= limit) {
|
||||
return (NULL);
|
||||
}
|
||||
encodedByte = *(ptr++);
|
||||
result |= (encodedByte & 127u) << resultShift;
|
||||
if (encodedByte < ((resultShift == 28ul) ? 16u : 128u)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
done:
|
||||
*resultOut = result;
|
||||
return ((const char *)ptr);
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE char *pithy_Encode32(char *sptr, uint32_t v)
|
||||
{
|
||||
unsigned char *ptr = (unsigned char *)sptr;
|
||||
if (v < (1u << 7)) {
|
||||
*(ptr++) = v;
|
||||
} else if (v < (1u << 14)) {
|
||||
*(ptr++) = v | 0x80u;
|
||||
*(ptr++) = (v >> 7);
|
||||
} else if (v < (1u << 21)) {
|
||||
*(ptr++) = v | 0x80u;
|
||||
*(ptr++) = (v >> 7) | 0x80u;
|
||||
*(ptr++) = (v >> 14);
|
||||
} else if (v < (1u << 28)) {
|
||||
*(ptr++) = v | 0x80u;
|
||||
*(ptr++) = (v >> 7) | 0x80u;
|
||||
*(ptr++) = (v >> 14) | 0x80u;
|
||||
*(ptr++) = (v >> 21);
|
||||
} else {
|
||||
*(ptr++) = v | 0x80u;
|
||||
*(ptr++) = (v >> 7) | 0x80u;
|
||||
*(ptr++) = (v >> 14) | 0x80u;
|
||||
*(ptr++) = (v >> 21) | 0x80u;
|
||||
*(ptr++) = (v >> 28);
|
||||
}
|
||||
return ((char *)ptr);
|
||||
}
|
||||
|
||||
|
||||
PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset)
|
||||
{
|
||||
DCHECK(offset <= 4);
|
||||
return (v >> (pithy_IsLittleEndian() ? (8u * offset) : (32u - (8u * offset))));
|
||||
}
|
||||
|
||||
|
||||
PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift)
|
||||
{
|
||||
uint32_t kMul = 0x1e35a7bdU;
|
||||
return ((bytes * kMul) >> shift);
|
||||
}
|
||||
|
||||
|
||||
PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit)
|
||||
{
|
||||
DCHECK(s2_limit >= s2);
|
||||
const char *ms1 = s1, *ms2 = s2;
|
||||
|
||||
#if defined(__LP64__)
|
||||
while (PITHY_EXPECT_T(ms2 < (s2_limit - 8ul))) {
|
||||
uint64_t x = pithy_Load64(ms1) ^ pithy_Load64(ms2);
|
||||
if (PITHY_EXPECT_F(x == 0ul)) {
|
||||
ms1 += 8ul;
|
||||
ms2 += 8ul;
|
||||
} else {
|
||||
return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero64(x) >> 3) :
|
||||
(pithy_FindMSBSetNonZero64(x) >> 3))));
|
||||
}
|
||||
}
|
||||
#else
|
||||
while (PITHY_EXPECT_T(ms2 < (s2_limit - 4u ))) {
|
||||
uint32_t x = pithy_Load32(ms1) ^ pithy_Load32(ms2);
|
||||
if (PITHY_EXPECT_F(x == 0u)) {
|
||||
ms1 += 4u;
|
||||
ms2 += 4u;
|
||||
} else {
|
||||
return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ?
|
||||
(pithy_FindLSBSetNonZero32(x) >> 3) : (pithy_FindMSBSetNonZero32(x) >> 3))));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
while (PITHY_EXPECT_T(ms2 < s2_limit)) {
|
||||
if (PITHY_EXPECT_T(*ms1 == *ms2)) {
|
||||
ms1++;
|
||||
ms2++;
|
||||
} else {
|
||||
return (ms1 - s1);
|
||||
}
|
||||
}
|
||||
return (ms1 - s1);
|
||||
}
|
||||
|
||||
|
||||
PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path)
|
||||
{
|
||||
int n = len - 1l;
|
||||
if (PITHY_EXPECT_T(n < 60l)) {
|
||||
*op++ = PITHY_LITERAL | (n << 2);
|
||||
if (PITHY_EXPECT_T(allow_fast_path) && PITHY_EXPECT_T(len <= 16ul)) {
|
||||
pithy_Move128(op, literal);
|
||||
return (op + len);
|
||||
}
|
||||
} else {
|
||||
char *base = op;
|
||||
int count = 0;
|
||||
op++;
|
||||
while (n > 0l) {
|
||||
*op++ = n & 0xff;
|
||||
n >>= 8;
|
||||
count++;
|
||||
}
|
||||
DCHECK((count >= 1) && (count <= 4));
|
||||
*base = PITHY_LITERAL | ((59 + count) << 2);
|
||||
}
|
||||
memcpy(op, literal, len);
|
||||
return (op + len);
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len)
|
||||
{
|
||||
DCHECK((len < 65536ul) && (len >= 63ul) && (offset < kBlockSize));
|
||||
if (PITHY_EXPECT_T(offset < 65536ul)) {
|
||||
if (PITHY_EXPECT_T(len < (256ul + 63ul))) {
|
||||
*op++ = PITHY_COPY_2_BYTE_OFFSET | (62 << 2);
|
||||
pithy_StoreHost16(op, offset);
|
||||
op += 2ul;
|
||||
*op++ = (len - 63ul);
|
||||
} else {
|
||||
*op++ = PITHY_COPY_2_BYTE_OFFSET | (63 << 2);
|
||||
pithy_StoreHost16(op, offset);
|
||||
op += 2ul;
|
||||
pithy_StoreHost16(op, len);
|
||||
op += 2ul;
|
||||
}
|
||||
} else {
|
||||
if (PITHY_EXPECT_T(len < (256ul + 63ul))) {
|
||||
*op++ = PITHY_COPY_3_BYTE_OFFSET | (62 << 2);
|
||||
pithy_StoreHost24(op, offset);
|
||||
op += 3ul;
|
||||
*op++ = (len - 63ul);
|
||||
} else {
|
||||
*op++ = PITHY_COPY_3_BYTE_OFFSET | (63 << 2);
|
||||
pithy_StoreHost24(op, offset);
|
||||
op += 3ul;
|
||||
pithy_StoreHost16(op, len);
|
||||
op += 2ul;
|
||||
}
|
||||
}
|
||||
return (op);
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len)
|
||||
{
|
||||
DCHECK((len < 63ul) && (len >= 4ul) && (offset < kBlockSize));
|
||||
if (PITHY_EXPECT_T(len < 12ul) && PITHY_EXPECT_T(offset < 2048ul)) {
|
||||
int lenMinus4 = len - 4l;
|
||||
DCHECK(lenMinus4 < 8l);
|
||||
*op++ = PITHY_COPY_1_BYTE_OFFSET | (lenMinus4 << 2) | ((offset >> 8) << 5);
|
||||
*op++ = offset & 0xff;
|
||||
} else {
|
||||
if (PITHY_EXPECT_T(offset < 65536ul)) {
|
||||
*op++ = PITHY_COPY_2_BYTE_OFFSET | ((len - 1ul) << 2);
|
||||
pithy_StoreHost16(op, offset);
|
||||
op += 2ul;
|
||||
} else {
|
||||
*op++ = PITHY_COPY_3_BYTE_OFFSET | ((len - 1ul) << 2);
|
||||
pithy_StoreHost24(op, offset);
|
||||
op += 3ul;
|
||||
}
|
||||
}
|
||||
return (op);
|
||||
}
|
||||
|
||||
PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len)
|
||||
{
|
||||
while (PITHY_EXPECT_F(len >= 63ul)) {
|
||||
op = pithy_EmitCopyGreaterThan63(op, offset, (len >= 65539ul) ? 65535ul : len);
|
||||
len -= (len >= 65539ul) ? 65535ul : len;
|
||||
}
|
||||
DCHECK((len > 0ul) ? ((len >= 4ul) && (len < 63ul)) : 1);
|
||||
if ( PITHY_EXPECT_T(len > 0ul)) {
|
||||
op = pithy_EmitCopyLessThan63(op, offset, len);
|
||||
len -= len;
|
||||
}
|
||||
return (op);
|
||||
}
|
||||
|
||||
size_t pithy_MaxCompressedLength(size_t inputLength)
|
||||
{
|
||||
return ((inputLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ? 0ul : 32ul + inputLength + (inputLength / 6ul));
|
||||
}
|
||||
|
||||
size_t pithy_Compress(const char *uncompressed,
|
||||
size_t uncompressedLength,
|
||||
char *compressedOut,
|
||||
size_t compressedOutLength,
|
||||
int compressionLevel)
|
||||
{
|
||||
|
||||
if ((pithy_MaxCompressedLength(uncompressedLength) > compressedOutLength) ||
|
||||
(uncompressedLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ||
|
||||
(uncompressedLength == 0ul)) {
|
||||
return (0ul);
|
||||
}
|
||||
|
||||
char *compressedPtr = compressedOut;
|
||||
|
||||
size_t hashTableSize = 0x100ul, maxHashTableSize = 1 << (12ul + (((compressionLevel < 0) ? 0 :
|
||||
(compressionLevel > 9) ? 9 : compressionLevel) / 2ul));
|
||||
while ((hashTableSize < maxHashTableSize) && (hashTableSize < uncompressedLength)) {
|
||||
hashTableSize <<= 1;
|
||||
}
|
||||
pithy_hashOffset_t stackHashTable[hashTableSize], *heapHashTable = NULL, *hashTable = stackHashTable;
|
||||
if ((sizeof(pithy_hashOffset_t) * hashTableSize) >= (1024ul * 128ul)) {
|
||||
if ((heapHashTable = malloc(sizeof(pithy_hashOffset_t) * hashTableSize)) == NULL) {
|
||||
return (0ul);
|
||||
}
|
||||
hashTable = heapHashTable;
|
||||
}
|
||||
size_t x = 0ul;
|
||||
for (x = 0ul; x < hashTableSize; x++) {
|
||||
hashTable[x] = uncompressed;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
char *const compressedOutEnd = compressedOut + compressedOutLength;
|
||||
#endif
|
||||
compressedPtr = pithy_Encode32(compressedPtr, uncompressedLength);
|
||||
DCHECK(compressedPtr <= compressedOutEnd);
|
||||
{
|
||||
const char *uncompressedPtr = uncompressed;
|
||||
const char *uncompressedEnd = uncompressed + uncompressedLength;
|
||||
const char *nextEmitUncompressedPtr = uncompressedPtr;
|
||||
DCHECK((hashTableSize & (hashTableSize - 1l)) == 0);
|
||||
const int shift = 32 - pithy_Log2Floor(hashTableSize);
|
||||
DCHECK((UINT32_MAX >> shift) == (hashTableSize - 1l));
|
||||
size_t skip = 32ul;
|
||||
|
||||
if (PITHY_EXPECT_T(uncompressedLength >= 15ul)) {
|
||||
const char *uncompressedEndLimit = uncompressed + uncompressedLength - 15ul;
|
||||
uint32_t uncompressedBytes;
|
||||
uint32_t nextUncompressedBytes = pithy_Load32(++uncompressedPtr);
|
||||
uint32_t nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
|
||||
|
||||
while (1) {
|
||||
DCHECK(nextEmitUncompressedPtr < uncompressedPtr);
|
||||
const char *nextUncompressedPtr = uncompressedPtr, *matchCandidatePtr = NULL;
|
||||
|
||||
skip = (((skip - 32ul) * 184ul) >> 8) + 32ul;
|
||||
|
||||
do {
|
||||
uncompressedPtr = nextUncompressedPtr;
|
||||
uncompressedBytes = nextUncompressedBytes;
|
||||
uint32_t uncompressedBytesHash = nextUncompressedBytesHash;
|
||||
DCHECK(uncompressedBytesHash == pithy_HashBytes(uncompressedBytes, shift));
|
||||
size_t skipBytesBetweenHashLookups = skip >> 5;
|
||||
skip += ((skip * 7ul) >> 11) + 1ul;
|
||||
nextUncompressedPtr = uncompressedPtr + skipBytesBetweenHashLookups;
|
||||
if (PITHY_EXPECT_F(nextUncompressedPtr > uncompressedEndLimit)) {
|
||||
goto emit_remainder;
|
||||
}
|
||||
nextUncompressedBytes = pithy_Load32(nextUncompressedPtr);
|
||||
nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
|
||||
matchCandidatePtr = hashTable[uncompressedBytesHash];
|
||||
DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
|
||||
hashTable[uncompressedBytesHash] = uncompressedPtr;
|
||||
} while ((PITHY_EXPECT_T(uncompressedBytes != pithy_Load32(matchCandidatePtr))) ||
|
||||
PITHY_EXPECT_F((uncompressedPtr - matchCandidatePtr) >= ((int)(kBlockSize - 2ul))));
|
||||
|
||||
DCHECK((nextEmitUncompressedPtr + 16ul) <= uncompressedEnd);
|
||||
compressedPtr = pithy_EmitLiteral(compressedPtr,
|
||||
nextEmitUncompressedPtr,
|
||||
uncompressedPtr - nextEmitUncompressedPtr,
|
||||
1);
|
||||
DCHECK(compressedPtr <= compressedOutEnd);
|
||||
uint64_t uncompressedBytes64 = 0ul;
|
||||
|
||||
do {
|
||||
if (compressionLevel > 2) {
|
||||
DCHECK((uncompressedPtr + 5ul) <= uncompressedEnd);
|
||||
uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr + 1ul);
|
||||
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] =
|
||||
uncompressedPtr + 1ul;
|
||||
if (compressionLevel > 4) {
|
||||
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] =
|
||||
uncompressedPtr + 2ul;
|
||||
}
|
||||
}
|
||||
|
||||
DCHECK((matchCandidatePtr >= uncompressed) &&
|
||||
(matchCandidatePtr <= uncompressedPtr) &&
|
||||
((matchCandidatePtr + 4ul) <= uncompressedEnd) &&
|
||||
((uncompressedPtr + 4ul) <= uncompressedEnd));
|
||||
|
||||
size_t matchCandidateLength = 4ul + pithy_FindMatchLength(matchCandidatePtr + 4ul,
|
||||
uncompressedPtr + 4ul,
|
||||
uncompressedEnd);
|
||||
DCHECK(((matchCandidatePtr + matchCandidateLength) >= uncompressed) &&
|
||||
((matchCandidatePtr + matchCandidateLength) <= uncompressedEnd));
|
||||
DCHECK(0 == memcmp(uncompressedPtr, matchCandidatePtr, matchCandidateLength));
|
||||
compressedPtr = pithy_EmitCopy(compressedPtr,
|
||||
uncompressedPtr - matchCandidatePtr,
|
||||
matchCandidateLength);
|
||||
DCHECK(compressedPtr <= compressedOutEnd);
|
||||
uncompressedPtr += matchCandidateLength;
|
||||
DCHECK(uncompressedPtr <= uncompressedEnd);
|
||||
nextEmitUncompressedPtr = uncompressedPtr;
|
||||
if (PITHY_EXPECT_F(uncompressedPtr >= uncompressedEndLimit)) {
|
||||
goto emit_remainder;
|
||||
}
|
||||
|
||||
DCHECK(((uncompressedPtr - 3ul) >= uncompressed) && (uncompressedPtr <= uncompressedEnd));
|
||||
|
||||
uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr - 3ul);
|
||||
|
||||
if (compressionLevel > 0) {
|
||||
if (compressionLevel > 8) {
|
||||
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] =
|
||||
uncompressedPtr - 3ul;
|
||||
}
|
||||
if (compressionLevel > 6) {
|
||||
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] =
|
||||
uncompressedPtr - 2ul;
|
||||
}
|
||||
hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 2u), shift)] =
|
||||
uncompressedPtr - 1ul;
|
||||
}
|
||||
|
||||
uncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 3u);
|
||||
uint32_t uncompressedBytesHash = pithy_HashBytes(uncompressedBytes, shift);
|
||||
matchCandidatePtr = hashTable[uncompressedBytesHash];
|
||||
DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
|
||||
hashTable[uncompressedBytesHash] = uncompressedPtr;
|
||||
} while (PITHY_EXPECT_F(uncompressedBytes == pithy_Load32(matchCandidatePtr)) &&
|
||||
PITHY_EXPECT_T((uncompressedPtr - matchCandidatePtr) < ((int)(kBlockSize - 2ul))));
|
||||
|
||||
nextUncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 4u);
|
||||
nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
|
||||
uncompressedPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
emit_remainder:
|
||||
if (nextEmitUncompressedPtr < uncompressedEnd) {
|
||||
compressedPtr = pithy_EmitLiteral(compressedPtr,
|
||||
nextEmitUncompressedPtr,
|
||||
uncompressedEnd - nextEmitUncompressedPtr,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
pithy_Store32(compressedPtr, 0);
|
||||
compressedPtr += 4;
|
||||
|
||||
DCHECK((size_t)(compressedPtr - compressedOut) <= compressedOutLength);
|
||||
if (heapHashTable != NULL) {
|
||||
free(heapHashTable);
|
||||
heapHashTable = NULL;
|
||||
hashTable = NULL;
|
||||
}
|
||||
return (compressedPtr - compressedOut);
|
||||
}
|
||||
|
||||
|
||||
static const uint32_t pithy_wordmask[] = {
|
||||
0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu
|
||||
};
|
||||
|
||||
|
||||
static const uint16_t pithy_charTable[256] = {
|
||||
0x0001, 0x0804, 0x1001, 0x1801, 0x0002, 0x0805, 0x1002, 0x1802,
|
||||
0x0003, 0x0806, 0x1003, 0x1803, 0x0004, 0x0807, 0x1004, 0x1804,
|
||||
0x0005, 0x0808, 0x1005, 0x1805, 0x0006, 0x0809, 0x1006, 0x1806,
|
||||
0x0007, 0x080a, 0x1007, 0x1807, 0x0008, 0x080b, 0x1008, 0x1808,
|
||||
0x0009, 0x0904, 0x1009, 0x1809, 0x000a, 0x0905, 0x100a, 0x180a,
|
||||
0x000b, 0x0906, 0x100b, 0x180b, 0x000c, 0x0907, 0x100c, 0x180c,
|
||||
0x000d, 0x0908, 0x100d, 0x180d, 0x000e, 0x0909, 0x100e, 0x180e,
|
||||
0x000f, 0x090a, 0x100f, 0x180f, 0x0010, 0x090b, 0x1010, 0x1810,
|
||||
0x0011, 0x0a04, 0x1011, 0x1811, 0x0012, 0x0a05, 0x1012, 0x1812,
|
||||
0x0013, 0x0a06, 0x1013, 0x1813, 0x0014, 0x0a07, 0x1014, 0x1814,
|
||||
0x0015, 0x0a08, 0x1015, 0x1815, 0x0016, 0x0a09, 0x1016, 0x1816,
|
||||
0x0017, 0x0a0a, 0x1017, 0x1817, 0x0018, 0x0a0b, 0x1018, 0x1818,
|
||||
0x0019, 0x0b04, 0x1019, 0x1819, 0x001a, 0x0b05, 0x101a, 0x181a,
|
||||
0x001b, 0x0b06, 0x101b, 0x181b, 0x001c, 0x0b07, 0x101c, 0x181c,
|
||||
0x001d, 0x0b08, 0x101d, 0x181d, 0x001e, 0x0b09, 0x101e, 0x181e,
|
||||
0x001f, 0x0b0a, 0x101f, 0x181f, 0x0020, 0x0b0b, 0x1020, 0x1820,
|
||||
0x0021, 0x0c04, 0x1021, 0x1821, 0x0022, 0x0c05, 0x1022, 0x1822,
|
||||
0x0023, 0x0c06, 0x1023, 0x1823, 0x0024, 0x0c07, 0x1024, 0x1824,
|
||||
0x0025, 0x0c08, 0x1025, 0x1825, 0x0026, 0x0c09, 0x1026, 0x1826,
|
||||
0x0027, 0x0c0a, 0x1027, 0x1827, 0x0028, 0x0c0b, 0x1028, 0x1828,
|
||||
0x0029, 0x0d04, 0x1029, 0x1829, 0x002a, 0x0d05, 0x102a, 0x182a,
|
||||
0x002b, 0x0d06, 0x102b, 0x182b, 0x002c, 0x0d07, 0x102c, 0x182c,
|
||||
0x002d, 0x0d08, 0x102d, 0x182d, 0x002e, 0x0d09, 0x102e, 0x182e,
|
||||
0x002f, 0x0d0a, 0x102f, 0x182f, 0x0030, 0x0d0b, 0x1030, 0x1830,
|
||||
0x0031, 0x0e04, 0x1031, 0x1831, 0x0032, 0x0e05, 0x1032, 0x1832,
|
||||
0x0033, 0x0e06, 0x1033, 0x1833, 0x0034, 0x0e07, 0x1034, 0x1834,
|
||||
0x0035, 0x0e08, 0x1035, 0x1835, 0x0036, 0x0e09, 0x1036, 0x1836,
|
||||
0x0037, 0x0e0a, 0x1037, 0x1837, 0x0038, 0x0e0b, 0x1038, 0x1838,
|
||||
0x0039, 0x0f04, 0x1039, 0x1839, 0x003a, 0x0f05, 0x103a, 0x183a,
|
||||
0x003b, 0x0f06, 0x103b, 0x183b, 0x003c, 0x0f07, 0x103c, 0x183c,
|
||||
0x0801, 0x0f08, 0x103d, 0x183d, 0x1001, 0x0f09, 0x103e, 0x183e,
|
||||
0x1801, 0x0f0a, 0x103f, 0x183f, 0x2001, 0x0f0b, 0x1040, 0x1840
|
||||
};
|
||||
|
||||
|
||||
int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult)
|
||||
{
|
||||
const char *compressedEnd = compressed + compressedLength;
|
||||
size_t decompressedLength = 0ul;
|
||||
if (pithy_Parse32WithLimit(compressed, compressedEnd, &decompressedLength) != NULL) {
|
||||
*decompressedOutLengthResult = decompressedLength;
|
||||
return (1);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut,
|
||||
size_t decompressedOutLength)
|
||||
{
|
||||
const char *nextCompressedPtr = NULL, *compressedEnd = (compressed + compressedLength);
|
||||
size_t parsedDecompressedLength = 0ul;
|
||||
if (((nextCompressedPtr = pithy_Parse32WithLimit(compressed, compressedEnd, &parsedDecompressedLength)) == NULL) ||
|
||||
(parsedDecompressedLength > decompressedOutLength)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *decompressedPtr = decompressedOut, *decompressedEnd = decompressedOut + parsedDecompressedLength;
|
||||
|
||||
while (1) {
|
||||
const char *compressedPtr = nextCompressedPtr;
|
||||
DCHECK(compressedPtr <= compressedEnd);
|
||||
if (PITHY_EXPECT_F(compressedPtr >= compressedEnd)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const unsigned char c = *((const unsigned char *)(compressedPtr++));
|
||||
const unsigned char cLowerBits = (c & 0x3u);
|
||||
const int spaceLeft = (decompressedEnd - decompressedPtr);
|
||||
|
||||
if ((cLowerBits == PITHY_LITERAL)) {
|
||||
size_t literalLength = (c >> 2) + 1;
|
||||
if (PITHY_EXPECT_T(literalLength <= 16ul) && PITHY_EXPECT_T((compressedEnd - compressedPtr) >= 16l) &&
|
||||
PITHY_EXPECT_T(spaceLeft >= 16l)) {
|
||||
pithy_Move128(decompressedPtr, compressedPtr);
|
||||
} else {
|
||||
if (PITHY_EXPECT_F(literalLength > 60)) {
|
||||
if (PITHY_EXPECT_F((compressedPtr + 4) > compressedEnd)) {
|
||||
break;
|
||||
}
|
||||
size_t literalLengthBytes = literalLength - 60;
|
||||
literalLength = (pithy_LoadHost32(compressedPtr) & pithy_wordmask[literalLengthBytes]) + 1;
|
||||
compressedPtr += literalLengthBytes;
|
||||
}
|
||||
if (PITHY_EXPECT_F(spaceLeft < (int)literalLength) ||
|
||||
PITHY_EXPECT_F((compressedPtr + literalLength) > compressedEnd)) {
|
||||
break;
|
||||
}
|
||||
memcpy(decompressedPtr, compressedPtr, literalLength);
|
||||
}
|
||||
nextCompressedPtr = compressedPtr + literalLength;
|
||||
decompressedPtr += literalLength;
|
||||
} else {
|
||||
const uint32_t entry = pithy_charTable[c];
|
||||
const size_t trailer = pithy_LoadHost32(compressedPtr) & pithy_wordmask[cLowerBits];
|
||||
size_t length = entry & 0xffu;
|
||||
const size_t copyOffset = ((entry & 0x700u) + trailer);
|
||||
|
||||
compressedPtr += cLowerBits;
|
||||
|
||||
DCHECK((compressedPtr <= compressedEnd) && (copyOffset > 0ul) && (spaceLeft > 0l) && (length > 0ul));
|
||||
|
||||
if (PITHY_EXPECT_F((decompressedPtr - decompressedOut) <= ((int)copyOffset - 1l))) {
|
||||
break;
|
||||
}
|
||||
if (PITHY_EXPECT_T(length <= 16ul) &&
|
||||
PITHY_EXPECT_T(copyOffset >= 16ul) &&
|
||||
PITHY_EXPECT_T(spaceLeft >= 16l)) {
|
||||
pithy_Move128(decompressedPtr, decompressedPtr - copyOffset);
|
||||
} else {
|
||||
if (PITHY_EXPECT_F(length >= 63ul)) {
|
||||
if (PITHY_EXPECT_T(length == 63ul)) {
|
||||
if (PITHY_EXPECT_F((compressedPtr + 1) > compressedEnd)) {
|
||||
break;
|
||||
}
|
||||
length = (*((unsigned char *)compressedPtr++)) + 63ul;
|
||||
} else {
|
||||
if (PITHY_EXPECT_F((compressedPtr + 2) > compressedEnd)) {
|
||||
break;
|
||||
}
|
||||
length = pithy_LoadHost16(compressedPtr);
|
||||
compressedPtr += 2ul;
|
||||
}
|
||||
}
|
||||
|
||||
char *copyFrom = decompressedPtr - copyOffset, *copyTo = decompressedPtr;
|
||||
int copyLength = (int)length;
|
||||
|
||||
if (PITHY_EXPECT_F(copyLength > 256l) && PITHY_EXPECT_T(copyOffset > (size_t)copyLength)) {
|
||||
if (PITHY_EXPECT_F(spaceLeft < copyLength)) {
|
||||
break;
|
||||
}
|
||||
memcpy(copyTo, copyFrom, copyLength);
|
||||
} else {
|
||||
if (PITHY_EXPECT_T(spaceLeft >= (copyLength + 24)) && PITHY_EXPECT_T(copyLength > 0l)) {
|
||||
while ((copyTo - copyFrom) < 16l) {
|
||||
pithy_Move128(copyTo, copyFrom);
|
||||
copyLength -= copyTo - copyFrom;
|
||||
copyTo += copyTo - copyFrom;
|
||||
}
|
||||
while (copyLength > 0l) {
|
||||
pithy_Move128(copyTo, copyFrom);
|
||||
copyFrom += 16l;
|
||||
copyTo += 16l;
|
||||
copyLength -= 16l;
|
||||
}
|
||||
} else {
|
||||
if (PITHY_EXPECT_F(spaceLeft < copyLength) || PITHY_EXPECT_F(copyLength <= 0l)) {
|
||||
break;
|
||||
}
|
||||
do {
|
||||
*copyTo++ = *copyFrom++;
|
||||
} while (--copyLength > 0l);
|
||||
}
|
||||
}
|
||||
}
|
||||
nextCompressedPtr = compressedPtr;
|
||||
decompressedPtr += length;
|
||||
}
|
||||
}
|
||||
|
||||
return (decompressedPtr == decompressedEnd);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// pithy.h
|
||||
// http://github.com/johnezang/pithy
|
||||
// Licensed under the terms of the BSD License, as specified below.
|
||||
//
|
||||
|
||||
/*
|
||||
Copyright (c) 2011, John Engelhart
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the Zang Industries nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _PITHY_H_
|
||||
#define _PITHY_H_
|
||||
|
||||
// compressionLevel >= 0 && compressionLevel <= 9. Values out side this range will be clamped to this range.
|
||||
size_t pithy_Compress (const char *uncompressed, size_t uncompressedLength, char *compressedOut,
|
||||
size_t compressedOutLength, int compressionLevel);
|
||||
int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut,
|
||||
size_t decompressedOutLength);
|
||||
|
||||
size_t pithy_MaxCompressedLength(size_t inputLength);
|
||||
int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength,
|
||||
size_t *decompressedOutLengthResult);
|
||||
|
||||
#endif // _PITHY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
Loading…
Reference in New Issue