1 /** @file
2  *
3  *  A brief file description
4  *
5  *  @section license License
6  *
7  *  Licensed to the Apache Software Foundation (ASF) under one
8  *  or more contributor license agreements.  See the NOTICE file
9  *  distributed with this work for additional information
10  *  regarding copyright ownership.  The ASF licenses this file
11  *  to you under the Apache License, Version 2.0 (the
12  *  "License"); you may not use this file except in compliance
13  *  with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *  Unless required by applicable law or agreed to in writing, software
18  *  distributed under the License is distributed on an "AS IS" BASIS,
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  *  See the License for the specific language governing permissions and
21  *  limitations under the License.
22  */
23 
24 #include "QUICIntUtil.h"
25 #include "tscore/ink_endian.h"
26 #include <memory>
27 #include <cstring>
28 
29 size_t
size(const uint8_t * src)30 QUICVariableInt::size(const uint8_t *src)
31 {
32   return 1 << (src[0] >> 6);
33 }
34 
35 size_t
size(uint64_t src)36 QUICVariableInt::size(uint64_t src)
37 {
38   uint8_t flag = 0;
39   if (src > 4611686018427387903) {
40     // max usable bits is 62
41     return 0;
42   } else if (src > 1073741823) {
43     flag = 0x03;
44   } else if (src > 16383) {
45     flag = 0x02;
46   } else if (src > 63) {
47     flag = 0x01;
48   } else {
49     flag = 0x00;
50   }
51 
52   return 1 << flag;
53 }
54 
55 int
encode(uint8_t * dst,size_t dst_len,size_t & len,uint64_t src)56 QUICVariableInt::encode(uint8_t *dst, size_t dst_len, size_t &len, uint64_t src)
57 {
58   uint8_t flag = 0;
59   if (src > 4611686018427387903) {
60     // max usable bits is 62
61     return 1;
62   } else if (src > 1073741823) {
63     flag = 0x03;
64   } else if (src > 16383) {
65     flag = 0x02;
66   } else if (src > 63) {
67     flag = 0x01;
68   } else {
69     flag = 0x00;
70   }
71 
72   len = 1 << flag;
73   if (len > dst_len) {
74     return 1;
75   }
76 
77   size_t dummy = 0;
78   QUICIntUtil::write_uint_as_nbytes(src, len, dst, &dummy);
79   dst[0] |= (flag << 6);
80 
81   return 0;
82 }
83 
84 int
decode(uint64_t & dst,size_t & len,const uint8_t * src,size_t src_len)85 QUICVariableInt::decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t src_len)
86 {
87   if (src_len < 1) {
88     return -1;
89   }
90   len = 1 << (src[0] >> 6);
91   if (src_len < len) {
92     return 1;
93   }
94 
95   uint8_t buf[8] = {0};
96   memcpy(buf, src, len);
97   buf[0] &= 0x3f;
98 
99   dst = QUICIntUtil::read_nbytes_as_uint(buf, len);
100 
101   return 0;
102 }
103 
104 uint64_t
read_QUICVariableInt(const uint8_t * buf)105 QUICIntUtil::read_QUICVariableInt(const uint8_t *buf)
106 {
107   uint64_t dst = 0;
108   size_t len   = 0;
109   QUICVariableInt::decode(dst, len, buf, 8);
110   return dst;
111 }
112 
113 void
write_QUICVariableInt(uint64_t data,uint8_t * buf,size_t * len)114 QUICIntUtil::write_QUICVariableInt(uint64_t data, uint8_t *buf, size_t *len)
115 {
116   QUICVariableInt::encode(buf, 8, *len, data);
117 }
118 
119 uint64_t
read_nbytes_as_uint(const uint8_t * buf,uint8_t n)120 QUICIntUtil::read_nbytes_as_uint(const uint8_t *buf, uint8_t n)
121 {
122   uint64_t value = 0;
123   memcpy(&value, buf, n);
124   return be64toh(value << (64 - n * 8));
125 }
126 
127 void
write_uint_as_nbytes(uint64_t value,uint8_t n,uint8_t * buf,size_t * len)128 QUICIntUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len)
129 {
130   value = htobe64(value) >> (64 - n * 8);
131   memcpy(buf, reinterpret_cast<uint8_t *>(&value), n);
132   *len = n;
133 }
134