changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > ventivac / appl/lib/venti.b

changeset 128: 42396bd501da
parent: 7f377ffc9ad3
author: Mechiel Lukkien <mechiel@ueber.net>
date: Mon, 20 Aug 2007 13:54:40 +0200
permissions: -rw-r--r--
description: no empty line at end of file
1 implement Venti;
2 
3 include "sys.m";
4  sys: Sys;
5 include "venti.m";
6 
7 BIT8SZ: con 1;
8 BIT16SZ: con 2;
9 BIT32SZ: con 4;
10 BIT48SZ: con 6;
11 BIT64SZ: con 8;
12 SCORE: con 20;
13 STR: con BIT16SZ;
14 H: con BIT16SZ+BIT8SZ+BIT8SZ; # minimum header length: size[2] op[1] tid[1]
15 Rootnamelen: con 128;
16 
17 versions := array[] of {"02"};
18 
19 blankroot: Root;
20 blankentry: Entry;
21 
22 init()
23 {
24  sys = load Sys Sys->PATH;
25 }
26 
27 hdrlen := array[Tmax] of {
28 Rerror => H+STR, # size[2] Rerror tid[1] error[s]
29 Tping => H, # size[2] Tping tid[1]
30 Rping => H, # size[2] Rping tid[1]
31 Thello => H+STR+STR+BIT8SZ+BIT8SZ+BIT8SZ, # size[2] Thello tid[1] version[s] uid[s] crypto[1] cryptos[n] codecs[n]
32 Rhello => H+STR+BIT8SZ+BIT8SZ, # size[2] Rhello tid[1] sid[s] crypto[1] codec[1]
33 Tgoodbye => H, # size[2] Tgoodbye tid[1]
34 Tread => H+SCORE+BIT8SZ+BIT8SZ+BIT16SZ, # size[2] Tread tid[1] score[20] type[1] pad[1] n[2]
35 Rread => H, # size[2] Rread tid[1] data
36 Twrite => H+BIT8SZ+3, # size[2] Twrite tid[1] type[1] pad[3]
37 Rwrite => H+SCORE, # size[2] Rwrite tid[1] score[20
38 Tsync => H, # size[2] Tsync tid[1]
39 Rsync => H, # size[2] Rsync tid[1]
40 };
41 
42 tag2type := array[] of {
43 tagof Vmsg.Rerror => Rerror,
44 tagof Vmsg.Tping => Tping,
45 tagof Vmsg.Rping => Rping,
46 tagof Vmsg.Thello => Thello,
47 tagof Vmsg.Rhello => Rhello,
48 tagof Vmsg.Tgoodbye => Tgoodbye,
49 tagof Vmsg.Tread => Tread,
50 tagof Vmsg.Rread => Rread,
51 tagof Vmsg.Twrite => Twrite,
52 tagof Vmsg.Rwrite => Rwrite,
53 tagof Vmsg.Tsync => Tsync,
54 tagof Vmsg.Rsync => Rsync,
55 };
56 
57 msgname := array[] of {
58 tagof Vmsg.Rerror => "Rerror",
59 tagof Vmsg.Tping => "Tping",
60 tagof Vmsg.Rping => "Rping",
61 tagof Vmsg.Thello => "Thello",
62 tagof Vmsg.Rhello => "Rhello",
63 tagof Vmsg.Tgoodbye => "Tgoodbye",
64 tagof Vmsg.Tread => "Tread",
65 tagof Vmsg.Rread => "Rread",
66 tagof Vmsg.Twrite => "Twrite",
67 tagof Vmsg.Rwrite => "Rwrite",
68 tagof Vmsg.Tsync => "Tsync",
69 tagof Vmsg.Rsync => "Rsync",
70 };
71 
72 zero := array[] of {
73  byte 16rda, byte 16r39, byte 16ra3, byte 16ree, byte 16r5e,
74  byte 16r6b, byte 16r4b, byte 16r0d, byte 16r32, byte 16r55,
75  byte 16rbf, byte 16ref, byte 16r95, byte 16r60, byte 16r18,
76  byte 16r90, byte 16raf, byte 16rd8, byte 16r07, byte 16r09
77 };
78 
79 
80 Vmsg.read(fd: ref Sys->FD): (ref Vmsg, string)
81 {
82  (msg, err) := readmsg(fd);
83  if(err != nil)
84  return (nil, err);
85  if(msg == nil)
86  return (nil, "eof reading message");
87  (nil, m) := Vmsg.unpack(msg);
88  if(m == nil)
89  return (nil, sys->sprint("bad venti message format: %r"));
90  return (m, nil);
91 }
92 
93 Vmsg.unpack(f: array of byte): (int, ref Vmsg)
94 {
95  if(len f < H) {
96  sys->werrstr("message too small");
97  return (0, nil);
98  }
99  size := (int f[0] << 8) | int f[1]; # size does not include self
100  size += BIT16SZ;
101  if(len f != size){
102  if(len f < size){
103  sys->werrstr("need more data");
104  return (0, nil); # need more data
105  }
106  f = f[0:size]; # trim to exact length
107  }
108  mtype := int f[2];
109  if(mtype >= len hdrlen || size < hdrlen[mtype]){
110  sys->werrstr("mtype out of range");
111  return (-1, nil);
112  }
113  tid := int f[3];
114  m: ref Vmsg;
115  case mtype {
116  Thello =>
117  uid: string;
118  cryptos, codecs: array of byte;
119 
120  (version, o) := gstring(f, H);
121  (uid, o) = gstring(f, o);
122  if(o < 0 || o >= len f)
123  break;
124  cryptostrength := int f[o++];
125  (cryptos, o) = gbytes(f, o);
126  (codecs, o) = gbytes(f, o);
127  if(o != len f)
128  break;
129  m = ref Vmsg.Thello(1, tid, version, uid, cryptostrength, cryptos, codecs);
130  Tping =>
131  m = ref Vmsg.Tping(1, tid);
132  Tgoodbye =>
133  m = ref Vmsg.Tgoodbye(1, tid);
134  Tread =>
135  score := Score(f[H:H+SCORE]);
136  etype := int f[H+SCORE];
137  n := (int f[H+SCORE+2] << 8) | int f[H+SCORE+3];
138  m = ref Vmsg.Tread(1, tid, score, etype, n);
139  Twrite =>
140  etype := int f[H];
141  m = ref Vmsg.Twrite(1, tid, etype, f[H+4:]);
142  Tsync =>
143  m = ref Vmsg.Tsync(1, tid);
144  Rhello =>
145  (sid, o) := gstring(f, H);
146  if(o+2 != len f)
147  break;
148  crypto := int f[o++];
149  codec := int f[o++];
150  m = ref Vmsg.Rhello(0, tid, sid, crypto, codec);
151  Rping =>
152  m = ref Vmsg.Rping(0, tid);
153  Rread =>
154  m = ref Vmsg.Rread(0, tid, f[H:]);
155  Rwrite =>
156  m = ref Vmsg.Rwrite(0, tid, Score(f[H:H+SCORE]));
157  Rsync =>
158  m = ref Vmsg.Rsync(0, tid);
159  Rerror =>
160  (err, o) := gstring(f, H);
161  if(o < 0)
162  break;
163  m = ref Vmsg.Rerror(0, tid, err);
164  * =>
165  sys->werrstr("unrecognised mtype " + string mtype);
166  return (-1, nil);
167  }
168  if(m == nil) {
169  sys->werrstr("bad message size");
170  return (-1, nil);
171  }
172  return (size, m);
173 }
174 
175 Vmsg.pack(gm: self ref Vmsg): array of byte
176 {
177  if(gm == nil)
178  return nil;
179  ds := gm.packedsize();
180  if(ds <= 0)
181  return nil;
182  d := array[ds] of byte;
183  d[0] = byte ((ds - 2) >> 8);
184  d[1] = byte (ds - 2);
185  d[2] = byte tag2type[tagof gm];
186  d[3] = byte gm.tid;
187  pick m := gm {
188  Thello =>
189  o := pstring(d, H, m.version);
190  o = pstring(d, o, m.uid);
191  d[o++] = byte m.cryptostrength;
192  d[o++] = byte len m.cryptos;
193  d[o:] = m.cryptos;
194  o += len m.cryptos;
195  d[o++] = byte len m.codecs;
196  d[o:] = m.codecs;
197  o += len m.codecs;
198  Tping =>
199  ;
200  Tgoodbye =>
201  ;
202  Tread =>
203  d[H:] = m.score.a;
204  d[H+SCORE] = byte m.etype;
205  d[H+SCORE+2] = byte (m.n >> 8);
206  d[H+SCORE+3] = byte m.n;
207  Twrite =>
208  d[H] = byte m.etype;
209  d[H+4:] = m.data;
210  Tsync =>
211  ;
212  Rhello =>
213  o := pstring(d, H, m.sid);
214  d[o++] = byte m.crypto;
215  d[o++] = byte m.codec;
216  Rping =>
217  ;
218  Rread =>
219  d[H:] = m.data;
220  Rwrite =>
221  d[H:] = m.score.a;
222  Rsync =>
223  ;
224  Rerror =>
225  pstring(d, H, m.e);
226  * =>
227  return nil;
228  }
229  return d;
230 }
231 
232 Vmsg.packedsize(gm: self ref Vmsg): int
233 {
234  mtype := tag2type[tagof gm];
235  if(mtype <= 0)
236  return 0;
237  ml := hdrlen[mtype];
238  pick m := gm {
239  Thello =>
240  ml += utflen(m.version) + utflen(m.uid) + len m.cryptos + len m.codecs;
241  Rhello =>
242  ml += utflen(m.sid);
243  Rread =>
244  ml += len m.data;
245  Twrite =>
246  ml += len m.data;
247  Rerror =>
248  ml += utflen(m.e);
249  }
250  return ml;
251 }
252 
253 Vmsg.text(gm: self ref Vmsg): string
254 {
255  if(gm == nil)
256  return "(nil)";
257  s := sys->sprint("%s(%d", msgname[tagof gm], gm.tid);
258  pick m := gm {
259  * =>
260  s += ",ILLEGAL";
261  Thello =>
262  s += sys->sprint(", %#q, %#q, %d, [", m.version, m.uid, m.cryptostrength);
263  if(len m.cryptos > 0){
264  s += string int m.cryptos[0];
265  for(i := 1; i < len m.cryptos; i++)
266  s += "," + string int m.cryptos[i];
267  }
268  s += "], [";
269  if(len m.codecs > 0){
270  s += string int m.codecs[0];
271  for(i := 1; i < len m.codecs; i++)
272  s += "," + string int m.codecs[i];
273  }
274  s += "]";
275  Tping =>
276  ;
277  Tgoodbye =>
278  ;
279  Tread =>
280  s += sys->sprint(", %s, %d, %d", m.score.text(), m.etype, m.n);
281  Twrite =>
282  s += sys->sprint(", %d, data[%d]", m.etype, len m.data);
283  Tsync =>
284  ;
285  Rhello =>
286  s += sys->sprint(", %#q, %d, %d", m.sid, m.crypto, m.codec);
287  Rping =>
288  Rread =>
289  s += sys->sprint(", data[%d]", len m.data);
290  Rwrite =>
291  s += ", " + m.score.text();
292  Rsync =>
293  ;
294  Rerror =>
295  s += sys->sprint(", %#q", m.e);
296  }
297  return s + ")";
298 }
299 
300 Session.new(fd: ref Sys->FD): ref Session
301 {
302  s := "venti-";
303  for(i := 0; i < len versions; i++){
304  if(i != 0)
305  s[len s] = ':';
306  s += versions[i];
307  }
308  s += "-libventi\n";
309  d := array of byte s;
310  if(sys->write(fd, d, len d) != len d)
311  return nil;
312  version := readversion(fd, "venti-", versions);
313  if(version == nil)
314  return nil;
315  session := ref Session(fd, version);
316  (r, e) := session.rpc(ref Vmsg.Thello(1, 0, version, nil, 0, nil, nil));
317  if(r == nil){
318  sys->werrstr("hello failed: " + e);
319  return nil;
320  }
321  return ref Session(fd, version);
322 }
323 
324 Session.read(s: self ref Session, score: Score, etype: int, maxn: int): array of byte
325 {
326  (gm, err) := s.rpc(ref Vmsg.Tread(1, 0, score, etype, maxn));
327  if(gm == nil){
328  sys->werrstr(err);
329  return nil;
330  }
331  pick m := gm {
332  Rread =>
333  return m.data;
334  }
335  return nil;
336 }
337 
338 Session.write(s: self ref Session, etype: int, data: array of byte): (int, Score)
339 {
340  (gm, err) := s.rpc(ref Vmsg.Twrite(1, 0, etype, data));
341  if(gm == nil){
342  sys->werrstr(err);
343  return (-1, Score(nil));
344  }
345  pick m := gm {
346  Rwrite =>
347  return (0, m.score);
348  }
349  return (-1, Score(nil));
350 }
351 
352 Session.sync(s: self ref Session): int
353 {
354  (gm, err) := s.rpc(ref Vmsg.Tsync(1, 0));
355  if(gm == nil){
356  sys->werrstr(err);
357  return -1;
358  }
359  return 0;
360 }
361 
362 Session.rpc(s: self ref Session, m: ref Vmsg): (ref Vmsg, string)
363 {
364  d := m.pack();
365  if(sys->write(s.fd, d, len d) != len d)
366  return (nil, "write failed");
367  (grm, err) := Vmsg.read(s.fd);
368  if(grm == nil)
369  return (nil, err);
370  if(grm.tid != m.tid)
371  return (nil, "message tags don't match");
372  if(grm.istmsg)
373  return (nil, "reply message is a t-message");
374  pick rm := grm {
375  Rerror =>
376  return (nil, rm.e);
377  }
378  if(tagof(grm) != tagof(m) + 1)
379  return (nil, "reply message is of wrong type");
380  return (grm, nil);
381 }
382 
383 readversion(fd: ref Sys->FD, prefix: string, versions: array of string): string
384 {
385  buf := array[Maxstringsize] of byte;
386  i := 0;
387  for(;;){
388  if(i >= len buf){
389  sys->werrstr("initial version string too long");
390  return nil;
391  }
392  if(readn(fd, buf[i:], 1) != 1){
393  sys->werrstr("eof on version string");
394  return nil;
395  }
396  c := int buf[i];
397  if(c == '\n')
398  break;
399  if(c < ' ' || c > 16r7f || i < len prefix && prefix[i] != c){
400  sys->werrstr("bad version string");
401  return nil;
402  }
403  i++;
404  }
405  if(i < len prefix){
406  sys->werrstr("bad version string");
407  return nil;
408  }
409 #sys->fprint(sys->fildes(2), "read version %#q\n", string buf[0:i]);
410  v := string buf[len prefix:i];
411  i = 0;
412  for(;;){
413  for(j := i; j < len v && v[j] != ':' && v[j] != '-'; j++)
414  ;
415  vv := v[i:j];
416 #sys->fprint(sys->fildes(2), "checking %#q\n", vv);
417  for(k := 0; k < len versions; k++)
418  if(versions[k] == vv)
419  return vv;
420  i = j;
421  if(i >= len v || v[i] != ':'){
422  sys->werrstr("unknown version");
423  return nil;
424  }
425  i++;
426  }
427  sys->werrstr("unknown version");
428  return nil;
429 }
430 
431 
432 Score.eq(a: self Score, b: Score): int
433 {
434  for(i := 0; i < SCORE; i++)
435  if(a.a[i] != b.a[i])
436  return 0;
437  return 1;
438 }
439 
440 Score.zero(): Score
441 {
442  return Score(zero);
443 }
444 
445 Score.parse(s: string): (int, Score)
446 {
447  if(len s != Scoresize * 2)
448  return (-1, Score(nil));
449  score := array[Scoresize] of {* => byte 0};
450  for(i := 0; i < len s; i++){
451  c := s[i];
452  case s[i] {
453  '0' to '9' =>
454  c -= '0';
455  'a' to 'f' =>
456  c -= 'a' - 10;
457  'A' to 'F' =>
458  c -= 'A' - 10;
459  * =>
460  return (-1, Score(nil));
461  }
462  if((i & 1) == 0)
463  c <<= 4;
464  score[i>>1] |= byte c;
465  }
466  return (0, Score(score));
467 }
468 
469 Score.text(a: self Score): string
470 {
471  s := "";
472  for(i := 0; i < SCORE; i++)
473  s += sys->sprint("%.2ux", int a.a[i]);
474  return s;
475 }
476 
477 
478 Root.new(name, rtype: string, score: Score, blocksize: int, prev: ref Score): ref Root
479 {
480  return ref Root(Rootversion, name, rtype, score, blocksize, prev);
481 }
482 
483 Root.pack(r: self ref Root): array of byte
484 {
485  d := array[Rootsize] of byte;
486  i := 0;
487  i = p16(d, i, r.version);
488  i = ptstring(d, i, r.name, Rootnamelen);
489  if(i < 0)
490  return nil;
491  i = ptstring(d, i, r.rtype, Rootnamelen);
492  if(i < 0)
493  return nil;
494  i = pscore(d, i, r.score);
495  i = p16(d, i, r.blocksize);
496  if(r.prev == nil) {
497  for(j := 0; j < Scoresize; j++)
498  d[i+j] = byte 0;
499  i += Scoresize;
500  } else
501  i = pscore(d, i, *r.prev);
502  if(i != len d) {
503  sys->werrstr("root pack, bad length: "+string i);
504  return nil;
505  }
506  return d;
507 }
508 
509 Root.unpack(d: array of byte): ref Root
510 {
511  if(len d != Rootsize){
512  sys->werrstr("root entry is wrong length");
513  return nil;
514  }
515  r := ref blankroot;
516  r.version = g16(d, 0);
517  if(r.version != Rootversion && r.version != Rootversionvar){
518  sys->werrstr("unknown root version");
519  return nil;
520  }
521  o := BIT16SZ;
522  r.name = gtstring(d, o, Rootnamelen);
523  o += Rootnamelen;
524  r.rtype = gtstring(d, o, Rootnamelen);
525  o += Rootnamelen;
526  r.score = gscore(d, o);
527  o += Scoresize;
528  r.blocksize = g16(d, o);
529  o += BIT16SZ;
530  r.prev = ref gscore(d, o);
531  return r;
532 }
533 
534 
535 Entry.new(psize, dsize, flags: int, size: big, score: Venti->Score): ref Entry
536 {
537  return ref Entry(0, psize, dsize, (flags&Entrydepthmask)>>Entrydepthshift, flags, size, score);
538 }
539 
540 Entry.pack(e: self ref Entry): array of byte
541 {
542  d := array[Entrysize] of byte;
543  i := 0;
544  i = p32(d, i, e.gen);
545  i = p16(d, i, e.psize);
546  i = p16(d, i, e.dsize);
547  e.flags |= e.depth<<Entrydepthshift;
548  d[i++] = byte e.flags;
549  for(j := 0; j < 5; j++)
550  d[i++] = byte 0;
551  i = p48(d, i, e.size);
552  i = pscore(d, i, e.score);
553  if(i != len d) {
554  sys->werrstr(sys->sprint("bad length, have %d, want %d", i, len d));
555  return nil;
556  }
557  return d;
558 }
559 
560 Entry.unpack(d: array of byte): ref Entry
561 {
562  if(len d != Entrysize){
563  sys->werrstr("entry is wrong length");
564  return nil;
565  }
566  e := ref blankentry;
567  i := 0;
568  e.gen = g32(d, i);
569  i += BIT32SZ;
570  e.psize = g16(d, i);
571  i += BIT16SZ;
572  e.dsize = g16(d, i);
573  i += BIT16SZ;
574  e.flags = int d[i];
575  e.depth = (e.flags & Entrydepthmask) >> Entrydepthshift;
576  e.flags &= ~Entrydepthmask;
577  i += BIT8SZ;
578  i += 5; # padding
579  e.size = g48(d, i);
580  i += BIT48SZ;
581  e.score = gscore(d, i);
582  i += Scoresize;
583  if((e.flags & Entryactive) == 0)
584  return e;
585  varblocks := e.flags&Entryvarblocks;
586  if(!checksize(e.psize) || (varblocks && e.dsize != 0 || !varblocks && !checksize(e.dsize))){
587  sys->werrstr(sys->sprint("bad blocksize (%d or %d)", e.psize, e.dsize));
588  return nil;
589  }
590  return e;
591 }
592 
593 
594 readn(fd: ref Sys->FD, buf: array of byte, nb: int): int
595 {
596  for(nr := 0; nr < nb;){
597  n := sys->read(fd, buf[nr:], nb-nr);
598  if(n <= 0){
599  if(nr == 0)
600  return n;
601  break;
602  }
603  nr += n;
604  }
605  return nr;
606 }
607 
608 readmsg(fd: ref Sys->FD): (array of byte, string)
609 {
610  sbuf := array[BIT16SZ] of byte;
611  if((n := readn(fd, sbuf, BIT16SZ)) != BIT16SZ){
612  if(n == 0)
613  return (nil, nil);
614  return (nil, sys->sprint("%r"));
615  }
616  ml := (int sbuf[0] << 8) | int sbuf[1];
617  if(ml < BIT16SZ)
618  return (nil, "invalid venti message size");
619  buf := array[ml + BIT16SZ] of byte;
620  buf[0:] = sbuf;
621  if((n = readn(fd, buf[BIT16SZ:], ml)) != ml){
622  if(n == 0)
623  return (nil, "venti message truncated");
624  return (nil, sys->sprint("%r"));
625  }
626  return (buf, nil);
627 }
628 
629 pstring(a: array of byte, o: int, s: string): int
630 {
631  sa := array of byte s; # could do conversion ourselves
632  n := len sa;
633  a[o] = byte (n >> 8);
634  a[o+1] = byte n;
635  a[o+2:] = sa;
636  return o+STR+n;
637 }
638 
639 gstring(a: array of byte, o: int): (string, int)
640 {
641  if(o < 0 || o+STR > len a)
642  return (nil, -1);
643  l := (int a[o] << 8) | int a[o+1];
644  if(l > Maxstringsize)
645  return (nil, -1);
646  o += STR;
647  e := o+l;
648  if(e > len a)
649  return (nil, -1);
650  return (string a[o:e], e);
651 }
652 
653 gbytes(a: array of byte, o: int): (array of byte, int)
654 {
655  if(o < 0 || o+1 > len a)
656  return (nil, -1);
657  n := int a[o];
658  if(1+n > len a)
659  return (nil, -1);
660  no := o+1+n;
661  return (a[o+1:no], no);
662 }
663 
664 utflen(s: string): int
665 {
666  # the domain is 16-bit unicode only, which is all that Inferno now implements
667  n := l := len s;
668  for(i:=0; i<l; i++)
669  if((c := s[i]) > 16r7F){
670  n++;
671  if(c > 16r7FF)
672  n++;
673  }
674  return n;
675 }
676 
677 checksize(n: int): int
678 {
679  if(n < 256 || n > Venti->Maxlumpsize) {
680  sys->werrstr("bad block size");
681  return 0;
682  }
683  return 1;
684 }
685 
686 gtstring(a: array of byte, o: int, n: int): string
687 {
688  e := o + n;
689  if(e > len a)
690  return nil;
691  for(i := o; i < e; i++)
692  if(a[i] == byte 0)
693  break;
694  return string a[o:i];
695 }
696 
697 gscore(f: array of byte, i: int): Score
698 {
699  s := Score(array[Scoresize] of byte);
700  s.a[0:] = f[i:i+Scoresize];
701  return s;
702 }
703 
704 g16(f: array of byte, i: int): int
705 {
706  return (int f[i] << 8) | int f[i+1];
707 }
708 
709 g32(f: array of byte, i: int): int
710 {
711  return (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
712 }
713 
714 g48(f: array of byte, i: int): big
715 {
716  b1 := (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
717  b0 := (int f[i+4] << 8) | int f[i+5];
718  return (big b1 << 16) | big b0;
719 }
720 
721 p16(d: array of byte, i: int, v: int): int
722 {
723  d[i+0] = byte (v>>8);
724  d[i+1] = byte v;
725  return i+BIT16SZ;
726 }
727 
728 p32(d: array of byte, i: int, v: int): int
729 {
730  p16(d, i+0, v>>16);
731  p16(d, i+2, v);
732  return i+BIT32SZ;
733 }
734 
735 p48(d: array of byte, i: int, v: big): int
736 {
737  p16(d, i+0, int (v>>32));
738  p32(d, i+2, int v);
739  return i+BIT48SZ;
740 }
741 
742 ptstring(d: array of byte, i: int, s: string, l: int): int
743 {
744  a := array of byte s;
745  if(len a > l) {
746  sys->werrstr("string too long: "+s);
747  return -1;
748  }
749  for(j := 0; j < len a; j++)
750  d[i+j] = a[j];
751  while(j < l)
752  d[i+j++] = byte 0;
753  return i+l;
754 }
755 
756 pscore(d: array of byte, i: int, s: Score): int
757 {
758  for(j := 0; j < Scoresize; j++)
759  d[i+j] = s.a[j];
760  return i+Scoresize;
761 }