/Library/lidgren-network/Lidgren.Network/NetBuffer.cs
C# | 213 lines | 135 code | 20 blank | 58 comment | 11 complexity | 8840d95343971eaa14fda12963d8266d MD5 | raw file
1/* Copyright (c) 2008 Michael Lidgren
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4and associated documentation files (the "Software"), to deal in the Software without
5restriction, including without limitation the rights to use, copy, modify, merge, publish,
6distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
7the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or
10substantial portions of the Software.
11
12THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
15LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
16TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
17USE OR OTHER DEALINGS IN THE SOFTWARE.
18*/
19using System;
20using System.Collections.Generic;
21using System.Diagnostics.CodeAnalysis;
22using System.Text;
23
24namespace Lidgren.Network
25{
26 /// <summary>
27 /// Wrapper around a byte array with methods for reading/writing at bit level
28 /// </summary>
29 public sealed partial class NetBuffer
30 {
31 // how many NetMessages are using this buffer?
32 internal int m_refCount;
33
34 internal int m_bitLength;
35 internal int m_readPosition;
36
37 [SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]
38 public byte[] Data;
39
40 /// <summary>
41 /// User application data
42 /// </summary>
43 public object Tag;
44
45 /// <summary>
46 /// Creates a new NetBuffer
47 /// </summary>
48 public NetBuffer()
49 {
50 Data = new byte[8];
51 }
52
53 /// <summary>
54 /// Creates a new NetBuffer initially capable of holding 'capacity' bytes
55 /// </summary>
56 public NetBuffer(int capacityBytes)
57 {
58 if (capacityBytes < 0)
59 capacityBytes = 4;
60 Data = new byte[capacityBytes];
61 }
62
63 /// <summary>
64 /// Creates a new NetBuffer and copies the data supplied
65 /// </summary>
66 public NetBuffer(byte[] copyData)
67 {
68 if (copyData != null)
69 {
70 Data = new byte[copyData.Length];
71 Buffer.BlockCopy(copyData, 0, Data, 0, copyData.Length);
72 m_bitLength = copyData.Length * 8;
73 }
74 else
75 {
76 Data = new byte[4];
77 }
78 }
79
80 public NetBuffer(string str)
81 {
82 if (string.IsNullOrEmpty(str))
83 {
84 Data = new byte[1];
85 WriteVariableUInt32(0);
86 return;
87 }
88
89 byte[] strData = Encoding.UTF8.GetBytes(str);
90 Data = new byte[1 + strData.Length];
91 WriteVariableUInt32((uint)strData.Length);
92 Write(strData);
93 }
94
95 /// <summary>
96 /// Data is NOT copied; but now owned by the NetBuffer
97 /// </summary>
98 public static NetBuffer FromData(byte[] data)
99 {
100 NetBuffer retval = new NetBuffer(false);
101 retval.Data = data;
102 retval.LengthBytes = data.Length;
103 return retval;
104 }
105
106 internal NetBuffer(bool createDataStorage)
107 {
108 if (createDataStorage)
109 Data = new byte[8];
110 }
111
112 /// <summary>
113 /// Gets or sets the length of the buffer in bytes
114 /// </summary>
115 public int LengthBytes {
116 get { return (m_bitLength >> 3) + ((m_bitLength & 7) > 0 ? 1 : 0); }
117 set
118 {
119 m_bitLength = value * 8;
120 InternalEnsureBufferSize(m_bitLength);
121 }
122 }
123
124 /// <summary>
125 /// Gets or sets the length of the buffer in bits
126 /// </summary>
127 public int LengthBits
128 {
129 get { return m_bitLength; }
130 set
131 {
132 m_bitLength = value;
133 InternalEnsureBufferSize(m_bitLength);
134 }
135 }
136
137 /// <summary>
138 /// Gets or sets the read position in the buffer, in bits (not bytes)
139 /// </summary>
140 public int Position
141 {
142 get { return m_readPosition; }
143 set { m_readPosition = value; }
144 }
145
146 /// <summary>
147 /// Resets read and write pointers
148 /// </summary>
149 public void Reset()
150 {
151 m_readPosition = 0;
152 m_bitLength = 0;
153 m_refCount = 0;
154 Tag = null;
155 }
156
157 /// <summary>
158 /// Resets read and write pointers
159 /// </summary>
160 internal void Reset(int readPos, int writePos)
161 {
162 m_readPosition = readPos;
163 m_bitLength = writePos;
164 m_refCount = 0;
165 Tag = null;
166 }
167
168 /// <summary>
169 /// Ensures this buffer can hold the specified number of bits prior to a write operation
170 /// </summary>
171 public void EnsureBufferSize(int numberOfBits)
172 {
173 int byteLen = (numberOfBits >> 3) + ((numberOfBits & 7) > 0 ? 1 : 0);
174 if (Data == null)
175 {
176 Data = new byte[byteLen + 4]; // overallocate 4 bytes
177 return;
178 }
179 if (Data.Length < byteLen)
180 Array.Resize<byte>(ref Data, byteLen + 4); // overallocate 4 bytes
181 return;
182 }
183
184 internal void InternalEnsureBufferSize(int numberOfBits)
185 {
186 int byteLen = (numberOfBits >> 3) + ((numberOfBits & 7) > 0 ? 1 : 0);
187 if (Data == null)
188 {
189 Data = new byte[byteLen];
190 return;
191 }
192 if (Data.Length < byteLen)
193 Array.Resize<byte>(ref Data, byteLen);
194 return;
195 }
196
197 /// <summary>
198 /// Copies the content of the buffer to a new byte array
199 /// </summary>
200 public byte[] ToArray()
201 {
202 int len = LengthBytes;
203 byte[] copy = new byte[len];
204 Array.Copy(Data, copy, copy.Length);
205 return copy;
206 }
207
208 public override string ToString()
209 {
210 return "[NetBuffer " + m_bitLength + " bits, " + m_readPosition + " read]";
211 }
212 }
213}