ip.b 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. implement IP;
  2. #
  3. # Copyright © 2003,2004 Vita Nuova Holdings Limited. All rights reserved.
  4. #
  5. include "sys.m";
  6. sys: Sys;
  7. include "ip.m";
  8. init()
  9. {
  10. sys = load Sys Sys->PATH;
  11. v4prefix = array[] of {
  12. byte 0, byte 0, byte 0, byte 0,
  13. byte 0, byte 0, byte 0, byte 0,
  14. byte 0, byte 0, byte 16rFF, byte 16rFF,
  15. };
  16. v4bcast = IPaddr(array[] of {
  17. byte 0, byte 0, byte 0, byte 0,
  18. byte 0, byte 0, byte 0, byte 0,
  19. byte 0, byte 0, byte 16rFF, byte 16rFF,
  20. byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF,
  21. });
  22. v4allsys = IPaddr(array[] of {
  23. byte 0, byte 0, byte 0, byte 0,
  24. byte 0, byte 0, byte 0, byte 0,
  25. byte 0, byte 0, byte 16rFF, byte 16rFF,
  26. byte 16rE0, byte 0, byte 0, byte 16r01,
  27. });
  28. v4allrouter = IPaddr(array[] of {
  29. byte 0, byte 0, byte 0, byte 0,
  30. byte 0, byte 0, byte 0, byte 0,
  31. byte 0, byte 0, byte 16rFF, byte 16rFF,
  32. byte 16rE0, byte 0, byte 0, byte 16r02,
  33. });
  34. v4noaddr = IPaddr(array[] of {
  35. byte 0, byte 0, byte 0, byte 0,
  36. byte 0, byte 0, byte 0, byte 0,
  37. byte 0, byte 0, byte 16rFF, byte 16rFF,
  38. byte 0, byte 0, byte 0, byte 0,
  39. });
  40. selfv6 = IPaddr(array[] of {
  41. byte 0, byte 0, byte 0, byte 0,
  42. byte 0, byte 0, byte 0, byte 0,
  43. byte 0, byte 0, byte 0, byte 0,
  44. byte 0, byte 0, byte 0, byte 1,
  45. });
  46. selfv4 = IPaddr(array[] of {
  47. byte 0, byte 0, byte 0, byte 0,
  48. byte 0, byte 0, byte 0, byte 0,
  49. byte 0, byte 0, byte 16rFF, byte 16rFF,
  50. byte 127, byte 0, byte 0, byte 1,
  51. });
  52. noaddr = IPaddr(array[] of {0 to IPaddrlen-1 => byte 0});
  53. allbits = IPaddr(array[] of {0 to IPaddrlen-1 => byte 16rFF});
  54. }
  55. IPaddr.newv6(a: array of byte): IPaddr
  56. {
  57. b := array[IPaddrlen] of byte;
  58. b[0:] = a[0:IPaddrlen];
  59. return IPaddr(b);
  60. }
  61. IPaddr.newv4(a: array of byte): IPaddr
  62. {
  63. b := array[IPaddrlen] of byte;
  64. b[0:] = v4prefix;
  65. b[IPv4off:] = a[0:IPv4addrlen];
  66. return IPaddr(b);
  67. }
  68. IPaddr.copy(ip: self IPaddr): IPaddr
  69. {
  70. if(ip.a == nil)
  71. return noaddr.copy();
  72. a := array[IPaddrlen] of byte;
  73. a[0:] = ip.a;
  74. return IPaddr(a);
  75. }
  76. IPaddr.eq(ip: self IPaddr, v: IPaddr): int
  77. {
  78. a := ip.a;
  79. if(a == nil)
  80. a = noaddr.a;
  81. b := v.a;
  82. if(b == nil)
  83. b = noaddr.a;
  84. for(i := 0; i < IPaddrlen; i++)
  85. if(a[i] != b[i])
  86. return 0;
  87. return 1;
  88. }
  89. IPaddr.mask(a1: self IPaddr, a2: IPaddr): IPaddr
  90. {
  91. c := array[IPaddrlen] of byte;
  92. for(i := 0; i < IPaddrlen; i++)
  93. c[i] = a1.a[i] & a2.a[i];
  94. return IPaddr(c);
  95. }
  96. IPaddr.maskn(a1: self IPaddr, a2: IPaddr): IPaddr
  97. {
  98. c := array[IPaddrlen] of byte;
  99. for(i := 0; i < IPaddrlen; i++)
  100. c[i] = a1.a[i] & ~a2.a[i];
  101. return IPaddr(c);
  102. }
  103. IPaddr.isv4(ip: self IPaddr): int
  104. {
  105. for(i := 0; i < IPv4off; i++)
  106. if(ip.a[i] != v4prefix[i])
  107. return 0;
  108. return 1;
  109. }
  110. IPaddr.ismulticast(ip: self IPaddr): int
  111. {
  112. if(ip.isv4()){
  113. v := int ip.a[IPv4off];
  114. return v >= 16rE0 && v < 16rF0 || ip.eq(v4bcast); # rfc1112
  115. }
  116. return ip.a[0] == byte 16rFF;
  117. }
  118. IPaddr.isvalid(ip: self IPaddr): int
  119. {
  120. return !ip.eq(noaddr) && !ip.eq(v4noaddr);
  121. }
  122. IPaddr.v4(ip: self IPaddr): array of byte
  123. {
  124. if(!ip.isv4() && !ip.eq(noaddr))
  125. return nil;
  126. a := array[4] of byte;
  127. for(i := 0; i < 4; i++)
  128. a[i] = ip.a[IPv4off+i];
  129. return a;
  130. }
  131. IPaddr.v6(ip: self IPaddr): array of byte
  132. {
  133. a := array[IPaddrlen] of byte;
  134. a[0:] = ip.a;
  135. return a;
  136. }
  137. IPaddr.class(ip: self IPaddr): int
  138. {
  139. if(!ip.isv4())
  140. return 6;
  141. return int ip.a[IPv4off]>>6;
  142. }
  143. IPaddr.classmask(ip: self IPaddr): IPaddr
  144. {
  145. m := allbits.copy();
  146. if(!ip.isv4())
  147. return m;
  148. if((n := ip.class()) == 0)
  149. n = 1;
  150. for(i := IPaddrlen-4+n; i < IPaddrlen; i++)
  151. m.a[i] = byte 0;
  152. return m;
  153. }
  154. #
  155. # rfc2373
  156. #
  157. IPaddr.parse(s: string): (int, IPaddr)
  158. {
  159. a := noaddr.copy();
  160. col := 0;
  161. gap := 0;
  162. for(i:=0; i<IPaddrlen && s != ""; i+=2){
  163. c := 'x';
  164. v := 0;
  165. for(m := 0; m < len s && (c = s[m]) != '.' && c != ':'; m++){
  166. d := 0;
  167. if(c >= '0' && c <= '9')
  168. d = c-'0';
  169. else if(c >= 'a' && c <= 'f')
  170. d = c-'a'+10;
  171. else if(c >= 'A' && c <= 'F')
  172. d = c-'A'+10;
  173. else
  174. return (-1, a);
  175. v = (v<<4) | d;
  176. }
  177. if(c == '.'){
  178. if(parseipv4(a.a[i:], s) < 0)
  179. return (-1, noaddr.copy());
  180. i += IPv4addrlen;
  181. break;
  182. }
  183. if(v > 16rFFFF)
  184. return (-1, a);
  185. a.a[i] = byte (v>>8);
  186. a.a[i+1] = byte v;
  187. if(c == ':'){
  188. col = 1;
  189. if(++m < len s && s[m] == ':'){
  190. if(gap > 0)
  191. return (-1, a);
  192. gap = i+2;
  193. m++;
  194. }
  195. }
  196. s = s[m:];
  197. }
  198. if(i < IPaddrlen){ # mind the gap
  199. ns := i-gap;
  200. for(j := 1; j <= ns; j++){
  201. a.a[IPaddrlen-j] = a.a[i-j];
  202. a.a[i-j] = byte 0;
  203. }
  204. }
  205. if(!col)
  206. a.a[0:] = v4prefix;
  207. return (0, IPaddr(a));
  208. }
  209. IPaddr.parsemask(s: string): (int, IPaddr)
  210. {
  211. return parsemask(s, 128);
  212. }
  213. IPaddr.parsecidr(s: string): (int, IPaddr, IPaddr)
  214. {
  215. for(i := 0; i < len s && s[i] != '/'; i++)
  216. ;
  217. (ok, a) := IPaddr.parse(s[0:i]);
  218. if(i < len s){
  219. (ok2, m) := IPaddr.parsemask(s[i:]);
  220. if(ok < 0 || ok2 < 0)
  221. return (-1, a, m);
  222. return (0, a, m);
  223. }
  224. return (ok, a, allbits.copy());
  225. }
  226. parseipv4(b: array of byte, s: string): int
  227. {
  228. a := array[4] of {* => 0};
  229. o := 0;
  230. for(i := 0; i < 4 && o < len s; i++){
  231. for(m := o; m < len s && (c := s[m]) != '.'; m++)
  232. if(!(c >= '0' && c <= '9'))
  233. return -1;
  234. if(m == o)
  235. return -1;
  236. a[i] = int big s[o:m];
  237. b[i] = byte a[i];
  238. if(m < len s && s[m] == '.')
  239. m++;
  240. o = m;
  241. }
  242. case i {
  243. 1 => # 32 bit
  244. b[0] = byte (a[0] >> 24);
  245. b[1] = byte (a[0] >> 16);
  246. b[2] = byte (a[0] >> 8);
  247. b[3] = byte a[0];
  248. 2 =>
  249. if(a[0] < 256){ # 8/24
  250. b[0] = byte a[0];
  251. b[1] = byte (a[1]>>16);
  252. b[2] = byte (a[1]>>8);
  253. }else if(a[0] < 65536){ # 16/16
  254. b[0] = byte (a[0]>>8);
  255. b[1] = byte a[0];
  256. b[2] = byte (a[1]>>16);
  257. }else{ # 24/8
  258. b[0] = byte (a[0]>>16);
  259. b[1] = byte (a[0]>>8);
  260. b[2] = byte a[0];
  261. }
  262. b[3] = byte a[1];
  263. 3 => # 8/8/16
  264. b[0] = byte a[0];
  265. b[1] = byte a[1];
  266. b[2] = byte (a[2]>>16);
  267. b[3] = byte a[2];
  268. }
  269. return 0;
  270. }
  271. parsemask(s: string, abits: int): (int, IPaddr)
  272. {
  273. m := allbits.copy();
  274. if(s == nil)
  275. return (0, m);
  276. if(s[0] != '/'){
  277. (ok, a) := IPaddr.parse(s);
  278. if(ok < 0)
  279. return (0, m);
  280. if(a.isv4())
  281. a.a[0:] = m.a[0:IPv4off];
  282. return (0, a);
  283. }
  284. if(len s == 1)
  285. return (0, m);
  286. nbit := int s[1:];
  287. if(nbit < 0)
  288. return (-1, m);
  289. if(nbit > abits)
  290. return (0, m);
  291. nbit = abits-nbit;
  292. i := IPaddrlen;
  293. for(; nbit >= 8; nbit -= 8)
  294. m.a[--i] = byte 0;
  295. if(nbit > 0)
  296. m.a[i-1] &= byte (~0<<nbit);
  297. return (0, m);
  298. }
  299. IPaddr.text(a: self IPaddr): string
  300. {
  301. b := a.a;
  302. if(b == nil)
  303. return "::";
  304. if(a.isv4())
  305. return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]);
  306. cs := -1;
  307. nc := 0;
  308. for(i:=0; i<IPaddrlen; i+=2)
  309. if(int b[i] == 0 && int b[i+1] == 0){
  310. for(j:=i+2; j<IPaddrlen; j+=2)
  311. if(int b[j] != 0 || int b[j+1] != 0)
  312. break;
  313. if(j-i > nc){
  314. nc = j-i;
  315. cs = i;
  316. }
  317. }
  318. if(nc <= 2)
  319. cs = -1;
  320. s := "";
  321. for(i=0; i<IPaddrlen; ){
  322. if(i == cs){
  323. s += "::";
  324. i += nc;
  325. }else{
  326. if(s != "" && s[len s-1]!=':')
  327. s[len s] = ':';
  328. v := (int a.a[i] << 8) | int a.a[i+1];
  329. s += sys->sprint("%ux", v);
  330. i += 2;
  331. }
  332. }
  333. return s;
  334. }
  335. IPaddr.masktext(a: self IPaddr): string
  336. {
  337. b := a.a;
  338. if(b == nil)
  339. return "/0";
  340. for(i:=0; i<IPaddrlen; i++)
  341. if(i == IPv4off)
  342. return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]);
  343. else if(b[i] != byte 16rFF)
  344. break;
  345. for(j:=i+1; j<IPaddrlen; j++)
  346. if(b[j] != byte 0)
  347. return a.text();
  348. nbit := 8*i;
  349. if(i < IPaddrlen){
  350. v := int b[i];
  351. for(m := 16r80; m != 0; m >>= 1){
  352. if((v & m) == 0)
  353. break;
  354. v &= ~m;
  355. nbit++;
  356. }
  357. if(v != 0)
  358. return a.text();
  359. }
  360. return sys->sprint("/%d", nbit);
  361. }
  362. addressesof(ifcs: list of ref Ipifc, all: int): list of IPaddr
  363. {
  364. ra: list of IPaddr;
  365. runi: list of IPaddr;
  366. for(; ifcs != nil; ifcs = tl ifcs){
  367. for(ifcas :=(hd ifcs).addrs; ifcs != nil; ifcs = tl ifcs){
  368. a := (hd ifcas).ip;
  369. if(all || !(a.eq(noaddr) || a.eq(v4noaddr))){ # ignore unspecified and loopback
  370. if(a.ismulticast() || a.eq(selfv4) || a.eq(selfv6))
  371. ra = a :: ra;
  372. else
  373. runi = a :: runi;
  374. }
  375. }
  376. }
  377. # unicast first, then others, both sets in order as found
  378. # for ipv6, might want to give priority to unicast other than link- and site-local
  379. al: list of IPaddr;
  380. for(; ra != nil; ra = tl ra)
  381. al = hd ra :: al;
  382. for(; runi != nil; runi = tl runi)
  383. al = hd runi :: al;
  384. return al;
  385. }
  386. interfaceof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr)
  387. {
  388. for(; l != nil; l = tl l){
  389. ifc := hd l;
  390. for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){
  391. a := hd addrs;
  392. if(ip.mask(a.mask).eq(a.net))
  393. return (ifc, a);
  394. }
  395. }
  396. return (nil, nil);
  397. }
  398. ownerof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr)
  399. {
  400. for(; l != nil; l = tl l){
  401. ifc := hd l;
  402. for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){
  403. a := hd addrs;
  404. if(ip.eq(a.ip))
  405. return (ifc, a);
  406. }
  407. }
  408. return (nil, nil);
  409. }
  410. readipifc(net: string, index: int): (list of ref Ipifc, string)
  411. {
  412. if(net == nil)
  413. net = "/net";
  414. if(index < 0){
  415. ifcs: list of ref Ipifc;
  416. dirfd := sys->open(net+"/ipifc", Sys->OREAD);
  417. if(dirfd == nil)
  418. return (nil, sys->sprint("%r"));
  419. err: string;
  420. for(;;){
  421. (nd, dirs) := sys->dirread(dirfd);
  422. if(nd <= 0){
  423. if(nd < 0)
  424. err = sys->sprint("%r");
  425. break;
  426. }
  427. for(i:=0; i<nd; i++)
  428. if((dn := dirs[i].name) != nil && dn[0]>='0' && dn[0]<='9'){
  429. index = int dn;
  430. ifc := readstatus(net+"/ipifc/"+dn+"/status", index);
  431. if(ifc != nil)
  432. ifcs = ifc :: ifcs;
  433. }
  434. }
  435. l := ifcs;
  436. for(ifcs = nil; l != nil; l = tl l)
  437. ifcs = hd l :: ifcs;
  438. return (ifcs, err);
  439. }
  440. ifc := readstatus(net+"/ipifc/"+string index+"/status", index);
  441. if(ifc == nil)
  442. return (nil, sys->sprint("%r"));
  443. return (ifc :: nil, nil);
  444. }
  445. #
  446. # return data structure containing values read from status file:
  447. #
  448. # device /net/ether0 maxtu 1514 sendra 0 recvra 0 mflag 0 oflag 0 maxraint 600000 minraint 200000 linkmtu 0 reachtime 0 rxmitra 0 ttl 255 routerlt 1800000 pktin 47609 pktout 42322 errin 0 errout 0
  449. # 144.32.112.83 /119 144.32.112.0 4294967295 4294967295
  450. # ...
  451. #
  452. readstatus(file: string, index: int): ref Ipifc
  453. {
  454. fd := sys->open(file, Sys->OREAD);
  455. if(fd == nil)
  456. return nil;
  457. contents := slurp(fd);
  458. fd = nil;
  459. (nline, lines) := sys->tokenize(contents, "\n");
  460. if(nline <= 0){
  461. sys->werrstr("unexpected ipifc status file format");
  462. return nil;
  463. }
  464. (nil, details) := sys->tokenize(hd lines, " \t\n");
  465. lines = tl lines;
  466. ifc := ref Ipifc;
  467. ifc.index = index;
  468. ifc.dev = valof(details, "device");
  469. ifc.mtu = int valof(details, "maxtu");
  470. ifc.pktin = big valof(details, "pktin");
  471. ifc.pktout = big valof(details, "pktout");
  472. ifc.errin = big valof(details, "errin");
  473. ifc.errout = big valof(details, "errout");
  474. ifc.sendra = int valof(details, "sendra");
  475. ifc.recvra = int valof(details, "recvra");
  476. ifc.rp.mflag = int valof(details, "mflag");
  477. ifc.rp.oflag = int valof(details, "oflag");
  478. ifc.rp.maxraint = int valof(details, "maxraint");
  479. ifc.rp.minraint = int valof(details, "minraint");
  480. ifc.rp.linkmtu = int valof(details, "linkmtu");
  481. ifc.rp.reachtime = int valof(details, "reachtime");
  482. ifc.rp.rxmitra = int valof(details, "rxmitra");
  483. ifc.rp.ttl = int valof(details, "ttl");
  484. ifc.rp.routerlt = int valof(details, "routerlt");
  485. addrs: list of ref Ifcaddr;
  486. for(; lines != nil; lines = tl lines){
  487. (nf, fields) := sys->tokenize(hd lines, " \t\n");
  488. if(nf >= 3){
  489. addr := ref Ifcaddr;
  490. (nil, addr.ip) = IPaddr.parse(hd fields); fields = tl fields;
  491. (nil, addr.mask) = IPaddr.parsemask(hd fields); fields = tl fields;
  492. (nil, addr.net) = IPaddr.parse(hd fields); fields = tl fields;
  493. if(nf >= 5){
  494. addr.preflt = big hd fields; fields = tl fields;
  495. addr.validlt = big hd fields; fields = tl fields;
  496. }else{
  497. addr.preflt = big 0;
  498. addr.validlt = big 0;
  499. }
  500. addrs = addr :: addrs;
  501. }
  502. }
  503. for(; addrs != nil; addrs = tl addrs)
  504. ifc.addrs = hd addrs :: ifc.addrs;
  505. return ifc;
  506. }
  507. slurp(fd: ref Sys->FD): string
  508. {
  509. buf := array[2048] of byte;
  510. s := "";
  511. while((n := sys->read(fd, buf, len buf)) > 0)
  512. s += string buf[0:n];
  513. return s;
  514. }
  515. valof(l: list of string, attr: string): string
  516. {
  517. while(l != nil){
  518. label := hd l;
  519. l = tl l;
  520. if(label == attr){
  521. if(l == nil)
  522. return nil;
  523. return hd l;
  524. }
  525. if(l != nil)
  526. l = tl l;
  527. }
  528. return nil;
  529. }
  530. Udphdr.new(): ref Udphdr
  531. {
  532. return ref Udphdr(noaddr, noaddr, noaddr, 0, 0);
  533. }
  534. Udphdr.unpack(a: array of byte, n: int): ref Udphdr
  535. {
  536. case n {
  537. Udp4hdrlen =>
  538. u := ref Udphdr;
  539. u.raddr = IPaddr.newv4(a[0:]);
  540. u.laddr = IPaddr.newv4(a[IPv4addrlen:]);
  541. u.rport = get2(a, 2*IPv4addrlen);
  542. u.lport = get2(a, 2*IPv4addrlen+2);
  543. u.ifcaddr = u.laddr.copy();
  544. return u;
  545. OUdphdrlen =>
  546. u := ref Udphdr;
  547. u.raddr = IPaddr.newv6(a[0:]);
  548. u.laddr = IPaddr.newv6(a[IPaddrlen:]);
  549. u.rport = get2(a, 2*IPaddrlen);
  550. u.lport = get2(a, 2*IPaddrlen+2);
  551. u.ifcaddr = u.laddr.copy();
  552. return u;
  553. Udphdrlen =>
  554. u := ref Udphdr;
  555. u.raddr = IPaddr.newv6(a[0:]);
  556. u.laddr = IPaddr.newv6(a[IPaddrlen:]);
  557. u.ifcaddr = IPaddr.newv6(a[2*IPaddrlen:]);
  558. u.rport = get2(a, 3*IPaddrlen);
  559. u.lport = get2(a, 3*IPaddrlen+2);
  560. return u;
  561. * =>
  562. raise "Udphdr.unpack: bad length";
  563. }
  564. }
  565. Udphdr.pack(u: self ref Udphdr, a: array of byte, n: int)
  566. {
  567. case n {
  568. Udp4hdrlen =>
  569. a[0:] = u.raddr.v4();
  570. a[IPv4addrlen:] = u.laddr.v4();
  571. put2(a, 2*IPv4addrlen, u.rport);
  572. put2(a, 2*IPv4addrlen+2, u.lport);
  573. OUdphdrlen =>
  574. a[0:] = u.raddr.v6();
  575. a[IPaddrlen:] = u.laddr.v6();
  576. put2(a, 2*IPaddrlen, u.rport);
  577. put2(a, 2*IPaddrlen+2, u.lport);
  578. Udphdrlen =>
  579. a[0:] = u.raddr.v6();
  580. a[IPaddrlen:] = u.laddr.v6();
  581. a[2*IPaddrlen:] = u.ifcaddr.v6();
  582. put2(a, 3*IPaddrlen, u.rport);
  583. put2(a, 3*IPaddrlen+2, u.lport);
  584. * =>
  585. raise "Udphdr.pack: bad length";
  586. }
  587. }
  588. get2(a: array of byte, o: int): int
  589. {
  590. return (int a[o] << 8) | int a[o+1];
  591. }
  592. put2(a: array of byte, o: int, val: int): int
  593. {
  594. a[o] = byte (val>>8);
  595. a[o+1] = byte val;
  596. return o+2;
  597. }
  598. get4(a: array of byte, o: int): int
  599. {
  600. return (((((int a[o] << 8)| int a[o+1]) << 8) | int a[o+2]) << 8) | int a[o+3];
  601. }
  602. put4(a: array of byte, o: int, val: int): int
  603. {
  604. a[o] = byte (val>>24);
  605. a[o+1] = byte (val>>16);
  606. a[o+2] = byte (val>>8);
  607. a[o+3] = byte val;
  608. return o+4;
  609. }