1 /*
2  * encode.c:  various data encoding routines
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23 
24 #include "private/svn_subr_private.h"
25 
26 #include "svn_private_config.h"
27 
28 unsigned char *
svn__encode_uint(unsigned char * p,apr_uint64_t val)29 svn__encode_uint(unsigned char *p, apr_uint64_t val)
30 {
31   int n;
32   apr_uint64_t v;
33 
34   /* Figure out how many bytes we'll need.  */
35   v = val >> 7;
36   n = 1;
37   while (v > 0)
38     {
39       v = v >> 7;
40       n++;
41     }
42 
43   /* Encode the remaining bytes; n is always the number of bytes
44      coming after the one we're encoding.  */
45   while (--n >= 1)
46     *p++ = (unsigned char)(((val >> (n * 7)) | 0x80) & 0xff);
47 
48   *p++ = (unsigned char)(val & 0x7f);
49 
50   return p;
51 }
52 
53 unsigned char *
svn__encode_int(unsigned char * p,apr_int64_t val)54 svn__encode_int(unsigned char *p, apr_int64_t val)
55 {
56   apr_uint64_t value = val;
57   value = value & APR_UINT64_C(0x8000000000000000)
58         ? APR_UINT64_MAX - (2 * value)
59         : 2 * value;
60 
61   return svn__encode_uint(p, value);
62 }
63 
64 const unsigned char *
svn__decode_uint(apr_uint64_t * val,const unsigned char * p,const unsigned char * end)65 svn__decode_uint(apr_uint64_t *val,
66                  const unsigned char *p,
67                  const unsigned char *end)
68 {
69   apr_uint64_t temp = 0;
70 
71   if (end - p > SVN__MAX_ENCODED_UINT_LEN)
72     end = p + SVN__MAX_ENCODED_UINT_LEN;
73 
74   /* Decode bytes until we're done. */
75   while (SVN__PREDICT_TRUE(p < end))
76     {
77       unsigned int c = *p++;
78 
79       if (c < 0x80)
80         {
81           *val = (temp << 7) | c;
82           return p;
83         }
84       else
85         {
86           temp = (temp << 7) | (c & 0x7f);
87         }
88     }
89 
90   return NULL;
91 }
92 
93 const unsigned char *
svn__decode_int(apr_int64_t * val,const unsigned char * p,const unsigned char * end)94 svn__decode_int(apr_int64_t *val,
95                 const unsigned char *p,
96                 const unsigned char *end)
97 {
98   apr_uint64_t value;
99   const unsigned char *result = svn__decode_uint(&value, p, end);
100 
101   value = value & 1
102         ? (APR_UINT64_MAX - value / 2)
103         : value / 2;
104   *val = (apr_int64_t)value;
105 
106   return result;
107 }
108