1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include <base/system.h>
4
5#include "compression.h"
6#include "packer.h"
7
8void CPacker::Reset()
9{
10 m_Error = false;
11 m_pCurrent = m_aBuffer;
12 m_pEnd = m_pCurrent + PACKER_BUFFER_SIZE;
13}
14
15void CPacker::AddInt(int i)
16{
17 if(m_Error)
18 return;
19
20 unsigned char *pNext = CVariableInt::Pack(pDst: m_pCurrent, i, DstSize: m_pEnd - m_pCurrent);
21 if(!pNext)
22 {
23 m_Error = true;
24 return;
25 }
26 m_pCurrent = pNext;
27}
28
29void CPacker::AddString(const char *pStr, int Limit)
30{
31 if(m_Error)
32 return;
33
34 if(Limit <= 0)
35 {
36 Limit = PACKER_BUFFER_SIZE;
37 }
38 while(*pStr && Limit != 0)
39 {
40 int Codepoint = str_utf8_decode(ptr: &pStr);
41 if(Codepoint == -1)
42 {
43 Codepoint = 0xfffd; // Unicode replacement character.
44 }
45 char aGarbage[4];
46 int Length = str_utf8_encode(ptr: aGarbage, chr: Codepoint);
47 if(Limit < Length)
48 {
49 break;
50 }
51 // Ensure space for the null termination.
52 if(m_pEnd - m_pCurrent < Length + 1)
53 {
54 m_Error = true;
55 break;
56 }
57 Length = str_utf8_encode(ptr: (char *)m_pCurrent, chr: Codepoint);
58 m_pCurrent += Length;
59 Limit -= Length;
60 }
61 *m_pCurrent++ = 0;
62}
63
64void CPacker::AddRaw(const void *pData, int Size)
65{
66 if(m_Error)
67 return;
68
69 if(m_pCurrent + Size > m_pEnd)
70 {
71 m_Error = true;
72 return;
73 }
74
75 mem_copy(dest: m_pCurrent, source: pData, size: Size);
76 m_pCurrent += Size;
77}
78
79void CUnpacker::Reset(const void *pData, int Size)
80{
81 m_Error = false;
82 m_pStart = (const unsigned char *)pData;
83 m_pEnd = m_pStart + Size;
84 m_pCurrent = m_pStart;
85}
86
87int CUnpacker::GetInt()
88{
89 if(m_Error)
90 return 0;
91
92 if(m_pCurrent >= m_pEnd)
93 {
94 m_Error = true;
95 return 0;
96 }
97
98 int i;
99 const unsigned char *pNext = CVariableInt::Unpack(pSrc: m_pCurrent, pInOut: &i, SrcSize: m_pEnd - m_pCurrent);
100 if(!pNext)
101 {
102 m_Error = true;
103 return 0;
104 }
105 m_pCurrent = pNext;
106 return i;
107}
108
109int CUnpacker::GetIntOrDefault(int Default)
110{
111 if(m_Error)
112 {
113 return 0;
114 }
115 if(m_pCurrent == m_pEnd)
116 {
117 return Default;
118 }
119 return GetInt();
120}
121
122int CUnpacker::GetUncompressedInt()
123{
124 if(m_Error)
125 return 0;
126
127 if(m_pCurrent + sizeof(int) > m_pEnd)
128 {
129 m_Error = true;
130 return 0;
131 }
132
133 int i;
134 mem_copy(dest: &i, source: m_pCurrent, size: sizeof(int));
135 m_pCurrent += sizeof(int);
136 return i;
137}
138
139int CUnpacker::GetUncompressedIntOrDefault(int Default)
140{
141 if(m_Error)
142 {
143 return 0;
144 }
145 if(m_pCurrent == m_pEnd)
146 {
147 return Default;
148 }
149 return GetUncompressedInt();
150}
151
152const char *CUnpacker::GetString(int SanitizeType)
153{
154 if(m_Error)
155 return "";
156
157 if(m_pCurrent >= m_pEnd)
158 {
159 m_Error = true;
160 return "";
161 }
162
163 char *pPtr = (char *)m_pCurrent;
164 while(*m_pCurrent) // skip the string
165 {
166 m_pCurrent++;
167 if(m_pCurrent == m_pEnd)
168 {
169 m_Error = true;
170 return "";
171 }
172 }
173 m_pCurrent++;
174
175 if(!str_utf8_check(str: pPtr))
176 {
177 m_Error = true;
178 return "";
179 }
180
181 // sanitize all strings
182 if(SanitizeType & SANITIZE)
183 str_sanitize(str: pPtr);
184 else if(SanitizeType & SANITIZE_CC)
185 str_sanitize_cc(str: pPtr);
186 return SanitizeType & SKIP_START_WHITESPACES ? str_utf8_skip_whitespaces(str: pPtr) : pPtr;
187}
188
189const unsigned char *CUnpacker::GetRaw(int Size)
190{
191 const unsigned char *pPtr = m_pCurrent;
192 if(m_Error)
193 return 0;
194
195 // check for nasty sizes
196 if(Size < 0 || m_pCurrent + Size > m_pEnd)
197 {
198 m_Error = true;
199 return 0;
200 }
201
202 // "unpack" the data
203 m_pCurrent += Size;
204 return pPtr;
205}
206