blob: bcf63088880d8b001d9cba9b55abbd757a44bfe1 [file] [log] [blame]
Brian Silverman1662a0e2013-12-19 17:50:01 -08001#include "cape/cows.h"
Brian Silverman2df84412013-12-10 14:00:40 -08002
3#include <limits.h>
4
Brian Silverman803b7a52014-01-01 13:21:18 -08005#if __STDC_HOSTED__
6#include <assert.h>
7#else
8#define assert(...)
9#endif
10
Brian Silverman2df84412013-12-10 14:00:40 -080011// This implementation is based on
12// <http://www.jacquesf.com/2011/03/consistent-overhead-byte-stuffing/>.
13
Daniel Petti23dcf6c2013-12-19 08:56:41 -080014uint32_t cows_stuff(const void *__restrict__ source_in, size_t source_length,
15 void *__restrict__ destination_in) {
Brian Silverman803b7a52014-01-01 13:21:18 -080016 assert((source_length % 4) == 0);
Brian Silverman2df84412013-12-10 14:00:40 -080017 const uint32_t *restrict source = (const uint32_t *)source_in;
18 uint32_t *restrict destination = (uint32_t *)destination_in;
19 size_t source_index = 0;
20 size_t destination_index = 1;
21 size_t code_index = 0;
22 uint32_t code = 1;
23
Brian Silverman803b7a52014-01-01 13:21:18 -080024 while (source_index < source_length / 4) {
Brian Silverman2df84412013-12-10 14:00:40 -080025 if (source[source_index] == 0) {
26 destination[code_index] = code;
27 code = 1;
28 code_index = destination_index++;
29 ++source_index;
30 } else {
31 destination[destination_index++] = source[source_index++];
32 ++code;
33 if (code == UINT32_MAX) {
34 destination[code_index] = code;
35 code = 1;
36 code_index = destination_index++;
37 }
38 }
39 }
40 destination[code_index] = code;
41 return destination_index;
42}
43
Daniel Petti23dcf6c2013-12-19 08:56:41 -080044uint32_t cows_unstuff(const uint32_t *__restrict__ source, size_t source_length,
Brian Silverman54787962013-12-28 22:31:16 -080045 uint32_t *__restrict__ destination,
46 size_t destination_length) {
Brian Silverman803b7a52014-01-01 13:21:18 -080047 assert((source_length % 4) == 0);
48 assert((destination_length % 4) == 0);
Brian Silverman2df84412013-12-10 14:00:40 -080049 size_t source_index = 0;
50 size_t destination_index = 0;
51 uint32_t code;
52
Brian Silverman803b7a52014-01-01 13:21:18 -080053 while (1) {
Brian Silverman2df84412013-12-10 14:00:40 -080054 code = source[source_index];
Brian Silvermanac5dd402013-12-23 21:50:06 -080055 if (source_index + code > source_length / 4 && code != 1) {
Brian Silverman2df84412013-12-10 14:00:40 -080056 return 0;
57 }
58
59 ++source_index;
60
61 for (uint32_t i = 1; i < code; ++i) {
Brian Silverman803b7a52014-01-01 13:21:18 -080062 if (destination_index >= destination_length / 4) {
63 return 0;
64 }
Brian Silverman2df84412013-12-10 14:00:40 -080065 destination[destination_index++] = source[source_index++];
66 }
Brian Silverman803b7a52014-01-01 13:21:18 -080067 if (source_index == source_length / 4) {
68 return destination_index;
69 }
70 if (code != UINT32_MAX) {
71 if (destination_index >= destination_length / 4) {
72 return 0;
73 }
Brian Silverman2df84412013-12-10 14:00:40 -080074 destination[destination_index++] = 0;
Brian Silverman2df84412013-12-10 14:00:40 -080075 }
76 }
Brian Silverman2df84412013-12-10 14:00:40 -080077}