summaryrefslogtreecommitdiff
path: root/vere/pkg/noun/jets/e/adler.c
blob: d7e12118e657971ebba0b8f4144a291cc7c7cff4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <imprison.h>
#include <jets/k.h>
#include <log.h>
#include <nock.h>
#include <retrieve.h>
#include <types.h>
#include <xtract.h>

static void _x_octs(u3_noun octs, u3_atom* p_octs, u3_atom* q_octs) {

  if (c3n == u3r_mean(octs,
             2, p_octs,
             3, q_octs, 0)){
    u3m_bail(c3__exit);
  }

  if (c3n == u3a_is_atom(*p_octs) ||
      c3n == u3a_is_atom(*q_octs)) {
    u3m_bail(c3__exit);
  }
}

static c3_o _x_octs_buffer(u3_atom* p_octs, u3_atom *q_octs,
                           c3_w* p_octs_w, c3_y** buf_y,
                           c3_w* len_w, c3_w* lead_w)
{
  if (c3n == u3r_safe_word(*p_octs, p_octs_w)) {
    return c3n;
  }

  *len_w = u3r_met(3, *q_octs);

  if (c3y == u3a_is_cat(*q_octs)) {
    *buf_y = (c3_y*)q_octs;
  }
  else {
    u3a_atom* ptr_a = u3a_to_ptr(*q_octs);
    *buf_y = (c3_y*)ptr_a->buf_w;
  }

  *lead_w = 0;

  if (*p_octs_w > *len_w) {
    *lead_w = *p_octs_w - *len_w;
  }
  else {
    *len_w = *p_octs_w;
  }

  return c3y;
}

#define BASE 65521
#define NMAX 5552

u3_noun _qe_adler32(u3_noun octs)
{
  u3_atom p_octs, q_octs;

  _x_octs(octs, &p_octs, &q_octs);

  c3_w p_octs_w, len_w, lead_w;
  c3_y *buf_y;

  if (c3n == _x_octs_buffer(&p_octs, &q_octs,
                            &p_octs_w, &buf_y,
                            &len_w, &lead_w)) {
    return u3_none;
  }

  c3_w adler_w, sum2_w;

  adler_w = 0x1;
  sum2_w = 0x0;

  c3_w pos_w = 0;

  // Process all non-zero bytes
  //
  while (pos_w < len_w) {

    c3_w rem_w = (len_w - pos_w);

    if (rem_w > NMAX) {
      rem_w = NMAX;
    }

    while (rem_w--) {
      adler_w += *(buf_y + pos_w++);
      sum2_w += adler_w;
    }

    adler_w %= BASE;
    sum2_w %= BASE;
  }

  // Process leading zeros
  //
  while (pos_w < p_octs_w) {

    c3_w rem_w = (p_octs_w - pos_w);

    if (rem_w > NMAX) {
      rem_w = NMAX;
    }

    // leading zeros: adler sum is unchanged
    sum2_w += rem_w*adler_w;
    pos_w += rem_w;

    adler_w %= BASE;
    sum2_w %= BASE;
  }

  return u3i_word(sum2_w << 16 | adler_w);
}


u3_noun 
u3we_adler32(u3_noun cor)
{
  u3_noun octs;

  u3x_mean(cor, u3x_sam, &octs, 0);

  return _qe_adler32(octs);
}