chiark / gitweb /
hexdecoct: slightly extend the unbase64mem() API and related
[elogind.git] / src / basic / hexdecoct.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <ctype.h>
21 #include <errno.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24
25 #include "alloc-util.h"
26 #include "hexdecoct.h"
27 #include "macro.h"
28 #include "string-util.h"
29 #include "util.h"
30
31 char octchar(int x) {
32         return '0' + (x & 7);
33 }
34
35 int unoctchar(char c) {
36
37         if (c >= '0' && c <= '7')
38                 return c - '0';
39
40         return -EINVAL;
41 }
42
43 char decchar(int x) {
44         return '0' + (x % 10);
45 }
46
47 int undecchar(char c) {
48
49         if (c >= '0' && c <= '9')
50                 return c - '0';
51
52         return -EINVAL;
53 }
54
55 char hexchar(int x) {
56         static const char table[16] = "0123456789abcdef";
57
58         return table[x & 15];
59 }
60
61 int unhexchar(char c) {
62
63         if (c >= '0' && c <= '9')
64                 return c - '0';
65
66         if (c >= 'a' && c <= 'f')
67                 return c - 'a' + 10;
68
69         if (c >= 'A' && c <= 'F')
70                 return c - 'A' + 10;
71
72         return -EINVAL;
73 }
74
75 char *hexmem(const void *p, size_t l) {
76         const uint8_t *x;
77         char *r, *z;
78
79         z = r = new(char, l * 2 + 1);
80         if (!r)
81                 return NULL;
82
83         for (x = p; x < (const uint8_t*) p + l; x++) {
84                 *(z++) = hexchar(*x >> 4);
85                 *(z++) = hexchar(*x & 15);
86         }
87
88         *z = 0;
89         return r;
90 }
91
92 int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
93         _cleanup_free_ uint8_t *r = NULL;
94         uint8_t *z;
95         const char *x;
96
97         assert(mem);
98         assert(len);
99         assert(p || l == 0);
100
101         if (l == (size_t) -1)
102                 l = strlen(p);
103
104         if (l % 2 != 0)
105                 return -EINVAL;
106
107         z = r = malloc((l + 1) / 2 + 1);
108         if (!r)
109                 return -ENOMEM;
110
111         for (x = p; x < p + l; x += 2) {
112                 int a, b;
113
114                 a = unhexchar(x[0]);
115                 if (a < 0)
116                         return a;
117
118                 b = unhexchar(x[1]);
119                 if (b < 0)
120                         return b;
121
122                 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
123         }
124
125         *z = 0;
126
127         *mem = r;
128         r = NULL;
129         *len = (l + 1) / 2;
130
131         return 0;
132 }
133
134 /* https://tools.ietf.org/html/rfc4648#section-6
135  * Notice that base32hex differs from base32 in the alphabet it uses.
136  * The distinction is that the base32hex representation preserves the
137  * order of the underlying data when compared as bytestrings, this is
138  * useful when representing NSEC3 hashes, as one can then verify the
139  * order of hashes directly from their representation. */
140 char base32hexchar(int x) {
141         static const char table[32] = "0123456789"
142                                       "ABCDEFGHIJKLMNOPQRSTUV";
143
144         return table[x & 31];
145 }
146
147 int unbase32hexchar(char c) {
148         unsigned offset;
149
150         if (c >= '0' && c <= '9')
151                 return c - '0';
152
153         offset = '9' - '0' + 1;
154
155         if (c >= 'A' && c <= 'V')
156                 return c - 'A' + offset;
157
158         return -EINVAL;
159 }
160
161 char *base32hexmem(const void *p, size_t l, bool padding) {
162         char *r, *z;
163         const uint8_t *x;
164         size_t len;
165
166         assert(p || l == 0);
167
168         if (padding)
169                 /* five input bytes makes eight output bytes, padding is added so we must round up */
170                 len = 8 * (l + 4) / 5;
171         else {
172                 /* same, but round down as there is no padding */
173                 len = 8 * l / 5;
174
175                 switch (l % 5) {
176                 case 4:
177                         len += 7;
178                         break;
179                 case 3:
180                         len += 5;
181                         break;
182                 case 2:
183                         len += 4;
184                         break;
185                 case 1:
186                         len += 2;
187                         break;
188                 }
189         }
190
191         z = r = malloc(len + 1);
192         if (!r)
193                 return NULL;
194
195         for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
196                 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
197                    x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
198                 *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
199                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
200                 *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
201                 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);  /* 000YZZZZ */
202                 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
203                 *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
204                 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5);  /* 000QQWWW */
205                 *(z++) = base32hexchar((x[4] & 31));                  /* 000WWWWW */
206         }
207
208         switch (l % 5) {
209         case 4:
210                 *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
211                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
212                 *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
213                 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);   /* 000YZZZZ */
214                 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
215                 *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
216                 *(z++) = base32hexchar((x[3] & 3) << 3);              /* 000QQ000 */
217                 if (padding)
218                         *(z++) = '=';
219
220                 break;
221
222         case 3:
223                 *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
224                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
225                 *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
226                 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
227                 *(z++) = base32hexchar((x[2] & 15) << 1);            /* 000ZZZZ0 */
228                 if (padding) {
229                         *(z++) = '=';
230                         *(z++) = '=';
231                         *(z++) = '=';
232                 }
233
234                 break;
235
236         case 2:
237                 *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
238                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
239                 *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
240                 *(z++) = base32hexchar((x[1] & 1) << 4);             /* 000Y0000 */
241                 if (padding) {
242                         *(z++) = '=';
243                         *(z++) = '=';
244                         *(z++) = '=';
245                         *(z++) = '=';
246                 }
247
248                 break;
249
250         case 1:
251                 *(z++) = base32hexchar(x[0] >> 3);       /* 000XXXXX */
252                 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
253                 if (padding) {
254                         *(z++) = '=';
255                         *(z++) = '=';
256                         *(z++) = '=';
257                         *(z++) = '=';
258                         *(z++) = '=';
259                         *(z++) = '=';
260                 }
261
262                 break;
263         }
264
265         *z = 0;
266         return r;
267 }
268
269 int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
270         _cleanup_free_ uint8_t *r = NULL;
271         int a, b, c, d, e, f, g, h;
272         uint8_t *z;
273         const char *x;
274         size_t len;
275         unsigned pad = 0;
276
277         assert(p || l == 0);
278         assert(mem);
279         assert(_len);
280
281         if (l == (size_t) -1)
282                 l = strlen(p);
283
284         /* padding ensures any base32hex input has input divisible by 8 */
285         if (padding && l % 8 != 0)
286                 return -EINVAL;
287
288         if (padding) {
289                 /* strip the padding */
290                 while (l > 0 && p[l - 1] == '=' && pad < 7) {
291                         pad++;
292                         l--;
293                 }
294         }
295
296         /* a group of eight input bytes needs five output bytes, in case of
297            padding we need to add some extra bytes */
298         len = (l / 8) * 5;
299
300         switch (l % 8) {
301         case 7:
302                 len += 4;
303                 break;
304         case 5:
305                 len += 3;
306                 break;
307         case 4:
308                 len += 2;
309                 break;
310         case 2:
311                 len += 1;
312                 break;
313         case 0:
314                 break;
315         default:
316                 return -EINVAL;
317         }
318
319         z = r = malloc(len + 1);
320         if (!r)
321                 return -ENOMEM;
322
323         for (x = p; x < p + (l / 8) * 8; x += 8) {
324                 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
325                    e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
326                 a = unbase32hexchar(x[0]);
327                 if (a < 0)
328                         return -EINVAL;
329
330                 b = unbase32hexchar(x[1]);
331                 if (b < 0)
332                         return -EINVAL;
333
334                 c = unbase32hexchar(x[2]);
335                 if (c < 0)
336                         return -EINVAL;
337
338                 d = unbase32hexchar(x[3]);
339                 if (d < 0)
340                         return -EINVAL;
341
342                 e = unbase32hexchar(x[4]);
343                 if (e < 0)
344                         return -EINVAL;
345
346                 f = unbase32hexchar(x[5]);
347                 if (f < 0)
348                         return -EINVAL;
349
350                 g = unbase32hexchar(x[6]);
351                 if (g < 0)
352                         return -EINVAL;
353
354                 h = unbase32hexchar(x[7]);
355                 if (h < 0)
356                         return -EINVAL;
357
358                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
359                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
360                 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
361                 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
362                 *(z++) = (uint8_t) g << 5 | (uint8_t) h;                         /* VVVRRRRR */
363         }
364
365         switch (l % 8) {
366         case 7:
367                 a = unbase32hexchar(x[0]);
368                 if (a < 0)
369                         return -EINVAL;
370
371                 b = unbase32hexchar(x[1]);
372                 if (b < 0)
373                         return -EINVAL;
374
375                 c = unbase32hexchar(x[2]);
376                 if (c < 0)
377                         return -EINVAL;
378
379                 d = unbase32hexchar(x[3]);
380                 if (d < 0)
381                         return -EINVAL;
382
383                 e = unbase32hexchar(x[4]);
384                 if (e < 0)
385                         return -EINVAL;
386
387                 f = unbase32hexchar(x[5]);
388                 if (f < 0)
389                         return -EINVAL;
390
391                 g = unbase32hexchar(x[6]);
392                 if (g < 0)
393                         return -EINVAL;
394
395                 /* g == 000VV000 */
396                 if (g & 7)
397                         return -EINVAL;
398
399                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
400                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
401                 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
402                 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
403
404                 break;
405         case 5:
406                 a = unbase32hexchar(x[0]);
407                 if (a < 0)
408                         return -EINVAL;
409
410                 b = unbase32hexchar(x[1]);
411                 if (b < 0)
412                         return -EINVAL;
413
414                 c = unbase32hexchar(x[2]);
415                 if (c < 0)
416                         return -EINVAL;
417
418                 d = unbase32hexchar(x[3]);
419                 if (d < 0)
420                         return -EINVAL;
421
422                 e = unbase32hexchar(x[4]);
423                 if (e < 0)
424                         return -EINVAL;
425
426                 /* e == 000SSSS0 */
427                 if (e & 1)
428                         return -EINVAL;
429
430                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
431                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
432                 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
433
434                 break;
435         case 4:
436                 a = unbase32hexchar(x[0]);
437                 if (a < 0)
438                         return -EINVAL;
439
440                 b = unbase32hexchar(x[1]);
441                 if (b < 0)
442                         return -EINVAL;
443
444                 c = unbase32hexchar(x[2]);
445                 if (c < 0)
446                         return -EINVAL;
447
448                 d = unbase32hexchar(x[3]);
449                 if (d < 0)
450                         return -EINVAL;
451
452                 /* d == 000W0000 */
453                 if (d & 15)
454                         return -EINVAL;
455
456                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
457                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
458
459                 break;
460         case 2:
461                 a = unbase32hexchar(x[0]);
462                 if (a < 0)
463                         return -EINVAL;
464
465                 b = unbase32hexchar(x[1]);
466                 if (b < 0)
467                         return -EINVAL;
468
469                 /* b == 000YYY00 */
470                 if (b & 3)
471                         return -EINVAL;
472
473                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
474
475                 break;
476         case 0:
477                 break;
478         default:
479                 return -EINVAL;
480         }
481
482         *z = 0;
483
484         *mem = r;
485         r = NULL;
486         *_len = len;
487
488         return 0;
489 }
490
491 /* https://tools.ietf.org/html/rfc4648#section-4 */
492 char base64char(int x) {
493         static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
494                                       "abcdefghijklmnopqrstuvwxyz"
495                                       "0123456789+/";
496         return table[x & 63];
497 }
498
499 int unbase64char(char c) {
500         unsigned offset;
501
502         if (c >= 'A' && c <= 'Z')
503                 return c - 'A';
504
505         offset = 'Z' - 'A' + 1;
506
507         if (c >= 'a' && c <= 'z')
508                 return c - 'a' + offset;
509
510         offset += 'z' - 'a' + 1;
511
512         if (c >= '0' && c <= '9')
513                 return c - '0' + offset;
514
515         offset += '9' - '0' + 1;
516
517         if (c == '+')
518                 return offset;
519
520         offset++;
521
522         if (c == '/')
523                 return offset;
524
525         return -EINVAL;
526 }
527
528 ssize_t base64mem(const void *p, size_t l, char **out) {
529         char *r, *z;
530         const uint8_t *x;
531
532         assert(p || l == 0);
533         assert(out);
534
535         /* three input bytes makes four output bytes, padding is added so we must round up */
536         z = r = malloc(4 * (l + 2) / 3 + 1);
537         if (!r)
538                 return -ENOMEM;
539
540         for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
541                 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
542                 *(z++) = base64char(x[0] >> 2);                    /* 00XXXXXX */
543                 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4);  /* 00XXYYYY */
544                 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
545                 *(z++) = base64char(x[2] & 63);                    /* 00ZZZZZZ */
546         }
547
548         switch (l % 3) {
549         case 2:
550                 *(z++) = base64char(x[0] >> 2);                   /* 00XXXXXX */
551                 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
552                 *(z++) = base64char((x[1] & 15) << 2);            /* 00YYYY00 */
553                 *(z++) = '=';
554
555                 break;
556         case 1:
557                 *(z++) = base64char(x[0] >> 2);        /* 00XXXXXX */
558                 *(z++) = base64char((x[0] & 3) << 4);  /* 00XX0000 */
559                 *(z++) = '=';
560                 *(z++) = '=';
561
562                 break;
563         }
564
565         *z = 0;
566         *out = r;
567         return z - r;
568 }
569
570 static int base64_append_width(
571                 char **prefix, int plen,
572                 const char *sep, int indent,
573                 const void *p, size_t l,
574                 int width) {
575
576         _cleanup_free_ char *x = NULL;
577         char *t, *s;
578         ssize_t slen, len, avail;
579         int line, lines;
580
581         len = base64mem(p, l, &x);
582         if (len <= 0)
583                 return len;
584
585         lines = (len + width - 1) / width;
586
587         slen = strlen_ptr(sep);
588         t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
589         if (!t)
590                 return -ENOMEM;
591
592         memcpy_safe(t + plen, sep, slen);
593
594         for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
595                 int act = MIN(width, avail);
596
597                 if (line > 0 || sep) {
598                         memset(s, ' ', indent);
599                         s += indent;
600                 }
601
602                 memcpy(s, x + width * line, act);
603                 s += act;
604                 *(s++) = line < lines - 1 ? '\n' : '\0';
605                 avail -= act;
606         }
607         assert(avail == 0);
608
609         *prefix = t;
610         return 0;
611 }
612
613 int base64_append(
614                 char **prefix, int plen,
615                 const void *p, size_t l,
616                 int indent, int width) {
617
618         if (plen > width / 2 || plen + indent > width)
619                 /* leave indent on the left, keep last column free */
620                 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
621         else
622                 /* leave plen on the left, keep last column free */
623                 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
624 }
625
626 int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
627         _cleanup_free_ uint8_t *r = NULL;
628         int a, b, c, d;
629         uint8_t *z;
630         const char *x;
631         size_t len;
632
633         assert(p || l == 0);
634         assert(mem);
635         assert(_len);
636
637         if (l == (size_t) -1)
638                 l = strlen(p);
639
640         /* padding ensures any base63 input has input divisible by 4 */
641         if (l % 4 != 0)
642                 return -EINVAL;
643
644         /* strip the padding */
645         if (l > 0 && p[l - 1] == '=')
646                 l--;
647         if (l > 0 && p[l - 1] == '=')
648                 l--;
649
650         /* a group of four input bytes needs three output bytes, in case of
651            padding we need to add two or three extra bytes */
652         len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
653
654         z = r = malloc(len + 1);
655         if (!r)
656                 return -ENOMEM;
657
658         for (x = p; x < p + (l / 4) * 4; x += 4) {
659                 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
660                 a = unbase64char(x[0]);
661                 if (a < 0)
662                         return -EINVAL;
663
664                 b = unbase64char(x[1]);
665                 if (b < 0)
666                         return -EINVAL;
667
668                 c = unbase64char(x[2]);
669                 if (c < 0)
670                         return -EINVAL;
671
672                 d = unbase64char(x[3]);
673                 if (d < 0)
674                         return -EINVAL;
675
676                 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
677                 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
678                 *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
679         }
680
681         switch (l % 4) {
682
683         case 3:
684                 a = unbase64char(x[0]);
685                 if (a < 0)
686                         return -EINVAL;
687
688                 b = unbase64char(x[1]);
689                 if (b < 0)
690                         return -EINVAL;
691
692                 c = unbase64char(x[2]);
693                 if (c < 0)
694                         return -EINVAL;
695
696                 /* c == 00ZZZZ00 */
697                 if (c & 3)
698                         return -EINVAL;
699
700                 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
701                 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
702
703                 break;
704         case 2:
705                 a = unbase64char(x[0]);
706                 if (a < 0)
707                         return -EINVAL;
708
709                 b = unbase64char(x[1]);
710                 if (b < 0)
711                         return -EINVAL;
712
713                 /* b == 00YY0000 */
714                 if (b & 15)
715                         return -EINVAL;
716
717                 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
718
719                 break;
720         case 0:
721
722                 break;
723         default:
724                 return -EINVAL;
725         }
726
727         *z = 0;
728
729         *mem = r;
730         r = NULL;
731         *_len = len;
732
733         return 0;
734 }
735
736 void hexdump(FILE *f, const void *p, size_t s) {
737         const uint8_t *b = p;
738         unsigned n = 0;
739
740         assert(s == 0 || b);
741
742         while (s > 0) {
743                 size_t i;
744
745                 fprintf(f, "%04x  ", n);
746
747                 for (i = 0; i < 16; i++) {
748
749                         if (i >= s)
750                                 fputs("   ", f);
751                         else
752                                 fprintf(f, "%02x ", b[i]);
753
754                         if (i == 7)
755                                 fputc(' ', f);
756                 }
757
758                 fputc(' ', f);
759
760                 for (i = 0; i < 16; i++) {
761
762                         if (i >= s)
763                                 fputc(' ', f);
764                         else
765                                 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
766                 }
767
768                 fputc('\n', f);
769
770                 if (s < 16)
771                         break;
772
773                 n += 16;
774                 b += 16;
775                 s -= 16;
776         }
777 }