File Coverage

c-lib/s-bsdiff.c
Criterion Covered Total %
statement 220 268 82.0
branch 141 192 73.4
condition n/a
subroutine n/a
pod n/a
total 361 460 78.4


line stmt bran cond sub pod time code
1             /*@ Implementation of s-bsdipa-lib.h: s_bsdipa_diff() and support.
2             *
3             * SPDX-License-Identifier: BSD-2-Clause
4             *
5             * Copyright (c) 2024 - 2026 Steffen Nurpmeso .
6             * (Only technical surroundings, algorithm is solely Colin Percival.)
7             *
8             * Copyright 2003-2005 Colin Percival
9             * All rights reserved
10             *
11             * Redistribution and use in source and binary forms, with or without
12             * modification, are permitted providing that the following conditions
13             * are met:
14             * 1. Redistributions of source code must retain the above copyright
15             * notice, this list of conditions and the following disclaimer.
16             * 2. Redistributions in binary form must reproduce the above copyright
17             * notice, this list of conditions and the following disclaimer in the
18             * documentation and/or other materials provided with the distribution.
19             *
20             * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21             * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22             * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23             * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24             * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25             * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26             * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27             * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28             * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29             * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30             * POSSIBILITY OF SUCH DAMAGE.
31             */
32              
33             #include "s-bsdipa-lib.h"
34              
35             #include
36             #include
37              
38             #ifndef s_BSDIPA_SMALL
39             # define DIVSUFSORT_API static
40             # include "divsufsort.h"
41             #endif
42              
43             /* Number of control block instances per s_bsdipa_ctrl_chunk */
44             #define a_BSDIPA_CTRL_NO 41
45              
46             /* What seems a good default */
47             #ifndef s_BSDIPA_MAGIC_WINDOW
48             # define s_BSDIPA_MAGIC_WINDOW 16
49             #endif
50              
51             #ifdef s_BSDIPA_SMALL
52             # define saidx_t s_bsdipa_off_t
53             #endif
54              
55             /* */
56             #undef MIN
57             #define MIN(x,y) (((x) < (y)) ? (x) : (y))
58              
59             /* With 32-bit off_t for now only s_BSDIPA_32 mode is supported */
60             #ifndef s_BSDIPA_32
61             # define OFF_MAX (sizeof(off_t) == 4 ? INT32_MAX : INT64_MAX)
62             typedef char ASSERTION_failed__off_max[OFF_MAX != INT32_MAX ? 1 : -1];
63             # undef OFF_MAX
64             #endif
65              
66             /* Checks use saidx_t, but the patch code uses s_bsdipa_off_t, so these must be of EQ size! */
67             typedef char ASSERTION_failed__bsdipa_off_eq_saidx[sizeof(s_bsdipa_off_t) == sizeof(saidx_t) ? 1 : -1];
68              
69             /* (Could be shared with s-bspatch.c) */
70             static void *a_bsdiff_alloc(void *vp, size_t size);
71             static void a_bsdiff_free(void *vp, void *dat);
72              
73             static inline s_bsdipa_off_t a_bsdiff_matchlen(uint8_t const *aftdat, s_bsdipa_off_t aftlen,
74             uint8_t const *befdat, s_bsdipa_off_t beflen);
75             static s_bsdipa_off_t a_bsdiff_search(s_bsdipa_off_t const *Ip, uint8_t const *aftdat, s_bsdipa_off_t aftlen,
76             uint8_t const *befdat, s_bsdipa_off_t beflenp,
77             s_bsdipa_off_t st, s_bsdipa_off_t en, s_bsdipa_off_t *posp);
78             static inline void a_bsdiff_xout(s_bsdipa_off_t x, uint8_t *bp);
79              
80             /* Later imported original BSDiff suffix sort by Colin Percival; at EOF.
81             * (It was replaced with libdivsufsort in the FreeBSD codebase to which he pointed me due to "existing fixes",
82             * because of performance improvements: 10-15 percent for large binaries (megabytes); for smaller files his is better.)
83             * Except for types and names i did not adapt syntax to my style for those. */
84             static void a_bsdiff_split(s_bsdipa_off_t *I, s_bsdipa_off_t *V, s_bsdipa_off_t start, s_bsdipa_off_t len,
85             s_bsdipa_off_t h);
86             static int a_bsdiff_qsufsort(s_bsdipa_off_t *I, uint8_t const *aftdat, s_bsdipa_off_t aftlen,
87             struct s_bsdipa_diff_ctx *dcp);
88              
89             static void *
90 1200           a_bsdiff_alloc(void *vp, size_t size){
91             struct s_bsdipa_diff_ctx *dcp;
92              
93 1200           dcp = (struct s_bsdipa_diff_ctx*)vp;
94 1200           vp = (*dcp->dc_mem.mc_alloc)(size);
95              
96 1200           return vp;
97             }
98              
99             static void
100 1200           a_bsdiff_free(void *vp, void *dat){
101             struct s_bsdipa_diff_ctx *dcp;
102              
103 1200           dcp = (struct s_bsdipa_diff_ctx*)vp;
104 1200           (*dcp->dc_mem.mc_free)(dat);
105 1200           }
106              
107             static inline s_bsdipa_off_t
108 103826688           a_bsdiff_matchlen(uint8_t const *aftdat, s_bsdipa_off_t aftlen, uint8_t const *befdat, s_bsdipa_off_t beflen){
109             s_bsdipa_off_t i;
110              
111 103826688           aftlen = MIN(aftlen, beflen);
112 122910096 100         for(i = 0; i < aftlen; ++i)
113 119332824 100         if(aftdat[i] != befdat[i])
114 100249416           break;
115              
116 103826688           return i;
117             }
118              
119             static s_bsdipa_off_t
120 980911224           a_bsdiff_search(s_bsdipa_off_t const *Ip, uint8_t const *aftdat, s_bsdipa_off_t aftlen,
121             uint8_t const *befdat, s_bsdipa_off_t beflen,
122             s_bsdipa_off_t st, s_bsdipa_off_t en, s_bsdipa_off_t *posp){
123             s_bsdipa_off_t x, y, r;
124              
125 980911224 100         if(en - st < 2){
126 51913344           x = a_bsdiff_matchlen(aftdat + Ip[st], aftlen - Ip[st], befdat, beflen);
127 51913344           y = a_bsdiff_matchlen(aftdat + Ip[en], aftlen - Ip[en], befdat, beflen);
128              
129 51913344 50         if(x > y){
130 0           *posp = Ip[st];
131 0           r = x;
132             }else{
133 51913344           *posp = Ip[en];
134 51913344           r = y;
135             }
136             }else{
137 928997880           x = st + ((en - st) / 2);
138 928997880           y = aftlen - Ip[x];
139 928997880           y = MIN(y, beflen);
140 928997880 100         if(memcmp(aftdat + Ip[x], befdat, (size_t)y) < 0)
141 100873920           r = a_bsdiff_search(Ip, aftdat, aftlen, befdat, beflen, x, en, posp);
142             else
143 828123960           r = a_bsdiff_search(Ip, aftdat, aftlen, befdat, beflen, st, x, posp);
144             }
145              
146 980911224           return r;
147             }
148              
149             static inline void
150 2016           a_bsdiff_xout(s_bsdipa_off_t x, uint8_t *buf){ /* xxx use endian.h stuff */
151             s_bsdipa_off_t y;
152             int lt0;
153              
154 2016           lt0 = (x < 0);
155 2016 50         y = lt0 ? -x : x;
156              
157             #ifndef s_BSDIPA_32
158             buf[7] = (uint8_t)(y & 0xFF); y >>= 8;
159             buf[6] = (uint8_t)(y & 0xFF); y >>= 8;
160             buf[5] = (uint8_t)(y & 0xFF); y >>= 8;
161             buf[4] = (uint8_t)(y & 0xFF); y >>= 8;
162             #endif
163 2016           buf[3] = (uint8_t)(y & 0xFF); y >>= 8;
164 2016           buf[2] = (uint8_t)(y & 0xFF); y >>= 8;
165 2016           buf[1] = (uint8_t)(y & 0xFF); y >>= 8;
166 2016           buf[0] = (uint8_t)(y /*& 0xFF*/);
167 2016 50         if(lt0)
168 0           buf[0] |= 0x80;
169 2016           }
170              
171             void
172 0           s_bsdipa_i_to_buf(uint8_t *out, s_bsdipa_off_t in){
173 0           a_bsdiff_xout(in, out);
174 0           }
175              
176             enum s_bsdipa_state
177 288           s_bsdipa_diff(struct s_bsdipa_diff_ctx *dcp){
178             saidx_t *Ip;
179             uint8_t const *befdat, *aftdat;
180             uint8_t *extrap, *diffp;
181             s_bsdipa_off_t beflen, aftlen;
182             enum s_bsdipa_state rv;
183              
184 288 50         if(dcp->dc_mem.mc_alloc != NULL){
185 288           dcp->dc_mem.mc_custom_cookie = dcp;
186 288           dcp->dc_mem.mc_custom_alloc = &a_bsdiff_alloc;
187 288           dcp->dc_mem.mc_custom_free = &a_bsdiff_free;
188             }
189              
190 288 50         if(dcp->dc_magic_window <= 0)
191 288           dcp->dc_magic_window = s_BSDIPA_MAGIC_WINDOW;
192              
193             /* Enable s_bsdipa_diff_free() */
194 288           memset(&dcp->dc_ctrl_len, 0, sizeof(*dcp) - (size_t)((uint8_t*)&dcp->dc_ctrl_len - (uint8_t*)dcp));
195              
196 288           rv = s_BSDIPA_FBIG;
197              
198             /* Fail early if we cannot create a patch with a header and one control triple */
199 288 50         if(dcp->dc_before_len >= s_BSDIPA_OFF_MAX -sizeof(struct s_bsdipa_header) -sizeof(struct s_bsdipa_ctrl_triple))
200 0           goto jleave;
201 288 50         if(dcp->dc_before_len + 1 >= SIZE_MAX / sizeof(saidx_t))
202 0           goto jleave;
203 288           beflen = (s_bsdipa_off_t)dcp->dc_before_len;
204 288           befdat = dcp->dc_before_dat;
205              
206 288 50         if(dcp->dc_after_len >= s_BSDIPA_OFF_MAX)
207 0           goto jleave;
208 288 50         if(dcp->dc_after_len + 1 >= SIZE_MAX / sizeof(saidx_t))
209 0           goto jleave;
210 288           aftlen = (s_bsdipa_off_t)dcp->dc_after_len;
211 288           aftdat = dcp->dc_after_dat;
212              
213 288           rv = s_BSDIPA_NOMEM;
214              
215 288           dcp->dc_extra_dat =
216 288           extrap = (uint8_t*)(*dcp->dc_mem.mc_custom_alloc)(dcp->dc_mem.mc_custom_cookie, (size_t)(beflen + 1));
217 288 50         if(dcp->dc_extra_dat == NULL)
218 0           goto jleave;
219             /* Let's share that buffer */
220 288           dcp->dc_diff_dat = diffp = &dcp->dc_extra_dat[(size_t)(beflen + 1)];
221              
222 288           Ip = (saidx_t*)(*dcp->dc_mem.mc_custom_alloc)(dcp->dc_mem.mc_custom_cookie,
223 288           (size_t)(aftlen + 1) * sizeof(saidx_t));
224 288 50         if(Ip == NULL)
225 0           goto jleave;
226              
227             /* Compute the differences, writing ctrl as we go */
228 288 50         if(aftlen == 0 && beflen == 0)
    0          
229 0           dcp->dc_is_equal_data = 1;
230             else{
231             s_bsdipa_off_t ctrl_len_max, scan, len, pos, lastscan, lastpos, lastoff, super_pos, aftscore, i;
232             uint32_t ctrlno;
233             struct s_bsdipa_ctrl_chunk **ccpp, *ccp;
234             int maxoffdecr, isneq, need_dump;
235              
236 288           maxoffdecr = 0;
237 288 50         if(aftlen != 0 && beflen != 0){
    50          
238             #ifndef s_BSDIPA_SMALL
239             /* Limit is "a bit arbitrary", and surely also depends on memory cache performance etc */
240 288 100         if(aftlen > 4096l * 25){
241             /* divsufsort(): effectively only ENOMEM */
242 48 50         if(divsufsort(aftdat, Ip, aftlen, dcp))
243 0           goto jdone;
244 48           maxoffdecr = 1;
245             }else
246             #endif
247 240 50         if(a_bsdiff_qsufsort(Ip, aftdat, aftlen, dcp))
248 0           goto jdone;
249             }
250              
251 288           isneq = (aftlen != beflen);
252 288           need_dump = 0;
253 288           ccpp = NULL;
254 288           ccp = NULL; /* xxx UNINIT() */
255 288           ctrlno = 0; /* xxx UNINIT() */
256 288           ctrl_len_max = s_BSDIPA_OFF_MAX - beflen - 1;
257 288           scan = len = pos = lastscan = lastpos = lastoff = super_pos = 0;
258              
259             /* a_bsdiff_search() is called with aftlen-a_BSDIPA_DIVSUFSORT, so bypass algorithm as such, then */
260 288 50         if(aftlen == 0)
261 0           goto Jaftlen0_bypass;
262              
263 288984 100         while(scan < beflen){
264 288408           aftscore = 0;
265              
266 51913632 100         for(i = (scan += len); scan < beflen; ++scan){
267 51913344           len = a_bsdiff_search(Ip, aftdat, aftlen, befdat + scan, beflen - scan, 0,
268             aftlen - maxoffdecr, &pos);
269              
270 104763456 100         for(; i < scan + len; ++i)
271 52850112 100         if(i + lastoff < aftlen && aftdat[i + lastoff] == befdat[i])
    100          
272 1225008           ++aftscore;
273              
274 51913344 100         if((len == aftscore && len != 0) || len > aftscore + dcp->dc_magic_window)
    100          
    50          
275             break;
276              
277 51625224 100         if(scan + lastoff < aftlen && aftdat[scan + lastoff] == befdat[scan])
    50          
278 0           --aftscore;
279             }
280              
281 288408 100         if(len != aftscore || scan == beflen) Jaftlen0_bypass:{
    100          
282             s_bsdipa_off_t s, Sf, lenf, lenb, j;
283              
284 288 50         if(aftlen == 0){
285 0           lenf = lenb = 0;
286 0           j = scan = beflen;
287 0           goto j_aftlen0_bypass;
288             }
289              
290 288           s = Sf = lenf = 0;
291              
292 26090232 100         for(i = 0; lastscan + i < scan && lastpos + i < aftlen;){
    100          
293 26089944 100         if(aftdat[lastpos + i] == befdat[lastscan + i])
294 1225008           ++s;
295 26089944           ++i;
296 26089944 100         if((s * 2) - i > (Sf * 2) - lenf){
297 1225008           Sf = s;
298 1225008           lenf = i;
299             }
300             }
301              
302 288           lenb = 0;
303 288 50         if(scan < beflen){
304             s_bsdipa_off_t Sb;
305              
306 0           s = Sb = 0;
307 0 0         for(i = 1; scan >= lastscan + i && pos >= i; ++i){
    0          
308 0 0         if(aftdat[pos - i] == befdat[scan - i])
309 0           ++s;
310 0 0         if((s * 2) - i > (Sb * 2) - lenb){
311 0           Sb = s;
312 0           lenb = i;
313             }
314             }
315             }
316              
317 288 50         if(lastscan + lenf > scan - lenb){
318             s_bsdipa_off_t overlap, Ss, lens;
319              
320 0           overlap = (lastscan + lenf) - (scan - lenb);
321 0           s = Ss = lens = 0;
322 0 0         for(i = 0; i < overlap; ++i){
323 0           if(befdat[lastscan + lenf - overlap + i
324 0 0         ] == aftdat[lastpos + lenf - overlap + i])
325 0           ++s;
326 0 0         if(befdat[scan - lenb + i] == aftdat[pos - lenb + i])
327 0           --s;
328 0 0         if(s > Ss){
329 0           Ss = s;
330 0           lens = i + 1;
331             }
332             }
333              
334 0           lenf += lens - overlap;
335 0           lenb -= lens;
336             }
337              
338 1225296 100         for(i = 0; i < lenf; ++i){
339             uint8_t u;
340              
341 1225008           u = befdat[lastscan + i] - aftdat[lastpos + i];
342 1225008           isneq |= (u != 0);
343 1225008           *--diffp = u;
344             }
345 288           dcp->dc_diff_len += lenf;
346             assert(diffp > extrap);
347              
348 288           j = (scan - lenb) - (lastscan + lenf);
349 288           j_aftlen0_bypass:
350 51625512 100         for(i = 0; i < j; ++i)
351 51625224           *extrap++ = befdat[lastscan + lenf + i];
352 288           dcp->dc_extra_len += j;
353             assert(extrap <= diffp);
354              
355             /* Since v0.9.0 we only create control chunks with data (but the first) */
356 288 100         if(lenf != 0 || j != 0){
    50          
357 288 50         if(need_dump){
358 0           a_bsdiff_xout(super_pos, &ccp->cc_dat[ccp->cc_len]);
359 0           ccp->cc_len += sizeof(s_bsdipa_off_t);
360 0           super_pos = 0;
361             }
362              
363 288 50         if(ccpp == NULL || --ctrlno == 0){
    0          
364             /* xxx Do not: sizeof(struct s_bsdipa_ctrl_triple) * a_BSDIPA_CTRL_NO */
365 288           ccp = (struct s_bsdipa_ctrl_chunk*)(*dcp->dc_mem.mc_custom_alloc)
366             (dcp->dc_mem.mc_custom_cookie,
367             (sizeof(struct s_bsdipa_ctrl_chunk) +
368             (3 * sizeof(s_bsdipa_off_t) * a_BSDIPA_CTRL_NO)));
369 288 50         if(ccp == NULL)
370 0           goto jdone;
371 288 50         if(ccpp == NULL)
372 288           dcp->dc_ctrl = ccp;
373             else
374 0           *ccpp = ccp;
375 288           ccp->cc_next = NULL;
376 288           ccpp = &ccp->cc_next;
377 288           ccp->cc_len = 0;
378 288           ctrlno = a_BSDIPA_CTRL_NO;
379             }
380              
381 288           a_bsdiff_xout(lenf, &ccp->cc_dat[ccp->cc_len]);
382 288           ccp->cc_len += sizeof(s_bsdipa_off_t);
383 288           a_bsdiff_xout(j, &ccp->cc_dat[ccp->cc_len]);
384 288           ccp->cc_len += sizeof(s_bsdipa_off_t);
385 288           need_dump = 1;
386 288           dcp->dc_ctrl_len += sizeof(s_bsdipa_off_t) * 3;
387 288 50         if(dcp->dc_ctrl_len > ctrl_len_max){
388 0           rv = s_BSDIPA_FBIG;
389 0           goto jdone;
390             }
391             }
392              
393 288           super_pos += (pos - lenb) - (lastpos + lenf);
394 288           lastscan = scan - lenb;
395 288           lastpos = pos - lenb;
396 288           lastoff = pos - scan;
397             }
398             }
399              
400 288 50         if(need_dump){
401 288           a_bsdiff_xout(0, &ccp->cc_dat[ccp->cc_len]);
402 288           ccp->cc_len += sizeof(s_bsdipa_off_t);
403             /*need_dump = 0;*/
404             }
405              
406 288           dcp->dc_is_equal_data = !isneq;
407             }
408              
409 288           dcp->dc_diff_dat = diffp;
410              
411             /* Create readily prepared header; as documented, sum of lengths does not exceed _OFF_MAX */
412 288           a_bsdiff_xout(dcp->dc_ctrl_len, &dcp->dc_header[0]);
413 288           a_bsdiff_xout(dcp->dc_diff_len, &dcp->dc_header[sizeof(s_bsdipa_off_t)]);
414 288           a_bsdiff_xout(dcp->dc_extra_len, &dcp->dc_header[sizeof(s_bsdipa_off_t) * 2]);
415 288           a_bsdiff_xout(beflen, &dcp->dc_header[sizeof(s_bsdipa_off_t) * 3]);
416              
417 288           rv = s_BSDIPA_OK;
418 288           jdone:
419 288           (*dcp->dc_mem.mc_custom_free)(dcp->dc_mem.mc_custom_cookie, Ip);
420              
421 288           jleave:
422 288           return rv;
423             }
424              
425             void
426 288           s_bsdipa_diff_free(struct s_bsdipa_diff_ctx *dcp){
427             struct s_bsdipa_ctrl_chunk *ccp;
428              
429 576 100         while((ccp = dcp->dc_ctrl) != NULL){
430 288           dcp->dc_ctrl = ccp->cc_next;
431 288           (*dcp->dc_mem.mc_custom_free)(dcp->dc_mem.mc_custom_cookie, ccp);
432             }
433              
434 288 50         if(dcp->dc_extra_dat != NULL)
435 288           (*dcp->dc_mem.mc_custom_free)(dcp->dc_mem.mc_custom_cookie, dcp->dc_extra_dat);
436 288           }
437              
438             /*
439             * The algorithm(s) {{{
440             */
441              
442             static void
443 583488           a_bsdiff_split(s_bsdipa_off_t *I, s_bsdipa_off_t *V, s_bsdipa_off_t start, s_bsdipa_off_t len, s_bsdipa_off_t h){
444             s_bsdipa_off_t i,j,k,x,tmp,jj,kk;
445              
446 583488 100         if(len<16) {
447 3300840 100         for(k=start;k
448 3009576           j=1;x=V[I[k]+h];
449 18619728 100         for(i=1;k+i
450 15610152 100         if(V[I[k+i]+h]
451 13437816           x=V[I[k+i]+h];
452 13437816           j=0;
453             }
454 15610152 100         if(V[I[k+i]+h]==x) {
455 13441104           tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
456 13441104           j++;
457             }
458             }
459 6021792 100         for(i=0;i
460 3009576 100         if(j==1) I[k]=-1;
461             }
462 291264           return;
463             }
464              
465 292224           x=V[I[start+len/2]+h];
466 292224           jj=0;kk=0;
467 65706384 100         for(i=start;i
468 65414160 100         if(V[I[i]+h]
469 65414160 100         if(V[I[i]+h]==x) kk++;
470             }
471 292224           jj+=start;kk+=jj;
472              
473 292224           i=start;j=0;k=0;
474 54435384 100         while(i
475 54143160 100         if(V[I[i]+h]
476 12716712           i++;
477 41426448 100         } else if(V[I[i]+h]==x) {
478 32564736           tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
479 32564736           j++;
480             } else {
481 8861712           tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
482 8861712           k++;
483             }
484             }
485              
486 7430232 100         while(jj+j
487 7138008 100         if(V[I[jj+j]+h]==x) {
488 7099008           j++;
489             } else {
490 39000           tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
491 39000           k++;
492             }
493             }
494              
495 292224 100         if(jj>start) a_bsdiff_split(I,V,start,jj-start,h);
496              
497 39955968 100         for(i=0;i
498 292224 100         if(jj==kk-1) I[jj]=-1;
499              
500 292224 100         if(start+len>kk) a_bsdiff_split(I,V,kk,start+len-kk,h);
501             }
502              
503             static int
504 240           a_bsdiff_qsufsort(s_bsdipa_off_t *I,const uint8_t *aftdat,s_bsdipa_off_t aftlen,struct s_bsdipa_diff_ctx *dcp){
505             s_bsdipa_off_t *V;
506             s_bsdipa_off_t buckets[256];
507             s_bsdipa_off_t i,h,len;
508              
509 240           V = (s_bsdipa_off_t*)(*dcp->dc_mem.mc_custom_alloc)(dcp->dc_mem.mc_custom_cookie,
510 240           (size_t)(aftlen + 1) * sizeof(saidx_t));
511 240 50         if(V == NULL)
512 0           return 1;
513              
514 240           memset(buckets, 0, sizeof(buckets)); /*for(i=0;i<256;i++) buckets[i]=0;*/
515 3290232 100         for(i=0;i
516 61440 100         for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
517 61440 100         for(i=255;i>0;i--) buckets[i]=buckets[i-1];
518 240           buckets[0]=0;
519              
520 3290232 100         for(i=0;i
521 240           I[0]=aftlen;
522 3290232 100         for(i=0;i
523 240           V[aftlen]=0;
524 61440 100         for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
    100          
525 240           I[0]=-1;
526              
527 2952 100         for(h=1;I[0]!=-(aftlen+1);h+=h) {
528 2712           len=0;
529 3317160 100         for(i=0;i
530 3314448 100         if(I[i]<0) {
531 3301200           len-=I[i];
532 3301200           i-=I[i];
533             } else {
534 13248 100         if(len) I[i-len]=-len;
535 13248           len=V[I[i]]+1-i;
536 13248           a_bsdiff_split(I,V,i,len,h);
537 13248           i+=len;
538 13248           len=0;
539             }
540             }
541 2712 100         if(len) I[i-len]=-len;
542             }
543              
544 3290472 100         for(i=0;i
545              
546 240           (*dcp->dc_mem.mc_custom_free)(dcp->dc_mem.mc_custom_cookie, V);
547 240           return 0;
548             }
549              
550             #ifndef s_BSDIPA_SMALL
551             # include "libdivsufsort/divsufsort.c"
552             # undef lg_table
553             # define lg_table a_sssort_lg_table
554             # include "libdivsufsort/sssort.c"
555             # undef lg_table
556             # define lg_table a_trsort_lg_table
557             # include "libdivsufsort/trsort.c"
558             #endif
559             /* }}} */
560              
561             /* s-itt-mode */