2 #include <ccan/crc/crc.h>
7 /* FIXME: That 64-bit CRC takes a while to warm the lower bits. Do
8 * some quantitative tests and replace it? Meanwhile, use upper bits. */
9 static uint64_t mask_of(unsigned int crcbits
)
11 return -1ULL << (64 - crcbits
);
14 void crc_of_blocks(const void *data
, size_t len
, unsigned int block_size
,
15 unsigned int crcbits
, uint64_t crc
[])
18 const uint8_t *buf
= data
;
19 uint64_t crcmask
= mask_of(crcbits
);
21 for (i
= 0; len
>= block_size
; i
++) {
22 crc
[i
] = (crc64_iso(0, buf
, block_size
) & crcmask
);
27 crc
[i
] = (crc64_iso(0, buf
, len
) & crcmask
);
34 /* Saved old buffer bytes (block_size bytes). */
36 size_t buffer_start
, buffer_end
;
38 /* Progress so far. */
44 /* Final block is special (if a different size) */
49 uint64_t uncrc_tab
[256];
51 /* This doesn't count the last CRC. */
52 unsigned int num_crcs
;
56 /* Calculate the how the crc changes when we take a give char out of the
58 static void init_uncrc_tab(uint64_t uncrc_tab
[], unsigned int wsize
)
62 uint8_t buffer
[wsize
];
64 /* Calculate crc(buffer+1, wsize-1) once, since it doesn't change. */
65 memset(buffer
, 0, wsize
);
66 part_crc
= crc64_iso(0, buffer
+1, wsize
-1);
68 for (i
= 0; i
< 256; i
++) {
70 uncrc_tab
[i
] = (crc64_iso(0, buffer
, wsize
) ^ part_crc
);
74 struct crc_context
*crc_context_new(size_t block_size
, unsigned crcbits
,
75 const uint64_t crc
[], unsigned num_crcs
,
78 struct crc_context
*ctx
;
81 assert(block_size
> 0);
82 assert(tail_size
< block_size
);
84 ctx
= malloc(sizeof(*ctx
) + sizeof(crc
[0])*num_crcs
);
86 ctx
->block_size
= block_size
;
87 ctx
->tail_size
= tail_size
;
89 ctx
->tail_crc
= crc
[--num_crcs
];
91 ctx
->crcmask
= mask_of(crcbits
);
92 ctx
->num_crcs
= num_crcs
;
93 memcpy(ctx
->crc
, crc
, sizeof(crc
[0])*num_crcs
);
95 ctx
->buffer_start
= 0;
97 ctx
->literal_bytes
= 0;
100 init_uncrc_tab(ctx
->uncrc_tab
, block_size
);
101 ctx
->buffer
= malloc(block_size
);
110 /* Return -1 or index into matching crc. */
111 static int crc_matches(const struct crc_context
*ctx
)
115 if (ctx
->literal_bytes
< ctx
->block_size
)
118 for (i
= 0; i
< ctx
->num_crcs
; i
++)
119 if ((ctx
->running_crc
& ctx
->crcmask
) == ctx
->crc
[i
])
124 static bool tail_matches(const struct crc_context
*ctx
)
126 if (ctx
->literal_bytes
!= ctx
->tail_size
)
129 return (ctx
->running_crc
& ctx
->crcmask
) == ctx
->tail_crc
;
132 static uint64_t crc_add_byte(uint64_t crc
, uint8_t newbyte
)
134 return crc64_iso(crc
, &newbyte
, 1);
137 static uint64_t crc_remove_byte(uint64_t crc
, uint8_t oldbyte
,
138 const uint64_t uncrc_tab
[])
140 return crc
^ uncrc_tab
[oldbyte
];
143 static uint64_t crc_roll(uint64_t crc
, uint8_t oldbyte
, uint8_t newbyte
,
144 const uint64_t uncrc_tab
[])
146 return crc_add_byte(crc_remove_byte(crc
, oldbyte
, uncrc_tab
), newbyte
);
149 static size_t buffer_size(const struct crc_context
*ctx
)
151 return ctx
->buffer_end
- ctx
->buffer_start
;
154 size_t crc_read_block(struct crc_context
*ctx
, long *result
,
155 const void *buf
, size_t buflen
)
157 size_t consumed
= 0, len
;
159 const uint8_t *old
, *p
= buf
;
161 /* Simple optimization, if we found a match last time. */
162 if (ctx
->have_match
>= 0) {
163 crcmatch
= ctx
->have_match
;
167 /* old is the trailing edge of the checksum window. */
168 if (buffer_size(ctx
) >= ctx
->block_size
)
169 old
= ctx
->buffer
+ ctx
->buffer_start
;
173 while (ctx
->literal_bytes
< ctx
->block_size
174 || (crcmatch
= crc_matches(ctx
)) < 0) {
175 if (consumed
== buflen
)
178 /* Increment these now in case we hit goto: below. */
179 ctx
->literal_bytes
++;
185 ctx
->running_crc
= crc_roll(ctx
->running_crc
,
189 /* End of stored buffer? Start on data they gave us. */
190 if (old
== ctx
->buffer
+ ctx
->buffer_end
)
193 ctx
->running_crc
= crc_add_byte(ctx
->running_crc
, *p
);
194 if (p
== (uint8_t *)buf
+ ctx
->block_size
- 1)
196 /* We don't roll this csum, we only look for it after
197 * a block match. It's simpler and faster. */
198 if (tail_matches(ctx
)) {
199 crcmatch
= ctx
->num_crcs
;
207 /* We have a match! */
208 if (ctx
->literal_bytes
> ctx
->block_size
) {
209 /* Output literal first. */
210 *result
= ctx
->literal_bytes
- ctx
->block_size
;
211 ctx
->literal_bytes
= ctx
->block_size
;
212 /* Remember for next time! */
213 ctx
->have_match
= crcmatch
;
216 *result
= -crcmatch
-1;
217 if (crcmatch
== ctx
->num_crcs
)
218 assert(ctx
->literal_bytes
== ctx
->tail_size
);
220 assert(ctx
->literal_bytes
== ctx
->block_size
);
221 ctx
->literal_bytes
= 0;
222 ctx
->have_match
= -1;
223 ctx
->running_crc
= 0;
224 /* Nothing more in the buffer. */
225 ctx
->buffer_start
= ctx
->buffer_end
= 0;
228 /* Output literal if it's more than 1 block ago. */
229 if (ctx
->literal_bytes
> ctx
->block_size
) {
230 *result
= ctx
->literal_bytes
- ctx
->block_size
;
231 ctx
->literal_bytes
-= *result
;
232 /* Advance buffer. */
233 if (*result
>= buffer_size(ctx
))
234 ctx
->buffer_start
= ctx
->buffer_end
= 0;
236 ctx
->buffer_start
+= *result
;
240 /* Now save any literal bytes we'll need in future. */
241 len
= ctx
->literal_bytes
- buffer_size(ctx
);
243 /* Move down old data if we don't have room. */
244 if (ctx
->buffer_end
+ len
> ctx
->block_size
) {
245 memmove(ctx
->buffer
, ctx
->buffer
+ ctx
->buffer_start
,
247 ctx
->buffer_end
-= ctx
->buffer_start
;
248 ctx
->buffer_start
= 0;
251 /* Copy len bytes from tail of buffer. */
252 memcpy(ctx
->buffer
+ ctx
->buffer_end
, buf
+ buflen
- len
, len
);
253 ctx
->buffer_end
+= len
;
254 assert(buffer_size(ctx
) <= ctx
->block_size
);
259 long crc_read_flush(struct crc_context
*ctx
)
263 /* We might have ended right on a matched block. */
264 if (ctx
->have_match
!= -1) {
265 ctx
->literal_bytes
-= ctx
->block_size
;
266 assert(ctx
->literal_bytes
== 0);
267 ret
= -ctx
->have_match
-1;
268 ctx
->have_match
= -1;
269 ctx
->running_crc
= 0;
270 /* Nothing more in the buffer. */
271 ctx
->buffer_start
= ctx
->buffer_end
;
275 /* The rest is just a literal. */
276 ret
= buffer_size(ctx
);
277 assert(ctx
->literal_bytes
== ret
);
278 ctx
->buffer_start
= ctx
->buffer_end
= 0;
279 ctx
->literal_bytes
= 0;
284 * crc_context_free - free a context returned from crc_context_new.
285 * @ctx: the context returned from crc_context_new, or NULL.
287 void crc_context_free(struct crc_context
*ctx
)