Updated license
[anna.git] / source / core / DataBlock.cpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <ctype.h>
38 #include <stdio.h>
39
40 #include <anna/core/DataBlock.hpp>
41 #include <anna/core/RuntimeException.hpp>
42 #include <anna/core/functions.hpp>
43
44 using namespace std;
45 using namespace anna;
46
47 #define anna_call_extend(a) \
48    if ((a_size + (a)) >= a_maxSize) extend ((a));
49
50 DataBlock::DataBlock(const char* buffer, const int size, const bool deepCopy)
51 throw(RuntimeException) :
52   a_buffer(NULL),
53   a_size(0),
54   a_deepCopy(deepCopy),
55   a_maxSize(0) {
56   initialize(buffer, size);
57 }
58
59 DataBlock::DataBlock(const DataBlock& other)
60 throw(RuntimeException) :
61   a_buffer(NULL),
62   a_size(0),
63   a_deepCopy(other.a_deepCopy),
64   a_maxSize(0) {
65   initialize(other.a_buffer, other.a_size);
66 }
67
68 DataBlock::~DataBlock() {
69   if(a_deepCopy)
70     delete [] a_buffer;
71 }
72
73 void DataBlock::initialize(const char* buffer, const int size)
74 throw(RuntimeException) {
75   if(a_deepCopy == false) {
76     a_buffer = const_cast <char*>(buffer);
77     a_size = size;
78   } else {
79     if((a_maxSize = a_size = size) > 0) {
80       if((a_buffer = new char [size]) != NULL)
81         anna_memcpy(a_buffer, buffer, size);
82       else
83         throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION);
84     } else
85       a_buffer = NULL;
86   }
87 }
88
89 void DataBlock::setSize(const int size)
90 throw(RuntimeException) {
91 //   if (size > a_maxSize) {
92 //      string msg ("DataBlock::setSize | MaxSize: ");
93 //      msg += functions::asString (a_maxSize);
94 //      msg += " | Size: ";
95 //      msg += functions::asString (size);
96 //      msg += " | Invalid size";
97 //      throw RuntimeException (msg, ANNA_FILE_LOCATION);
98 //   }
99 //
100 //   a_currentMessage.assign (a_buffer.getData () + a_offset, remainingSize);
101 //
102 // Sin embargo, el fetch() de nuestro clientSocket hace esto:
103 //   a_buffer.setup (a_data.getData () + a_offset, remainingSize);
104 //
105 // Y el setup no hace reserva, solo asocia (buffer y size)
106   a_size = size;
107 }
108
109 void DataBlock::allocate(const int nbytes)
110 throw(RuntimeException) {
111   if(nbytes > a_size) {
112     if(a_maxSize == 0) {
113       if(a_deepCopy == false)
114         throw RuntimeException("Deep-Copy was not active", ANNA_FILE_LOCATION);
115
116       if((a_buffer = new char [a_maxSize = nbytes]) == NULL)
117         throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION);
118     } else
119       extend(nbytes - a_size);
120
121     a_size = nbytes;
122   }
123 }
124
125 void DataBlock::assign(const char* buffer, const int size)
126 throw(RuntimeException) {
127   if(a_deepCopy == false) {
128     a_buffer = const_cast <char*>(buffer);
129     a_size = size;
130   } else {
131     delete a_buffer;
132     a_maxSize = a_size = 0;
133     initialize(buffer, size);
134   }
135 }
136
137 DataBlock& DataBlock::operator = (const DataBlock & right)
138 throw(RuntimeException) {
139   if(this != &right) {
140     if(a_deepCopy) {
141       a_size = 0;
142       append(right.a_buffer, right.a_size);
143     } else {
144       a_buffer = right.a_buffer;
145       a_size = right.a_size;
146     }
147   }
148
149   return *this;
150 }
151
152 const char DataBlock::operator [](const int pos) const
153 throw(RuntimeException) {
154   if(pos >= a_size) {
155     std::string msg("Position: ");
156     msg += functions::asString(pos);
157     msg += " | Out of range [0,";
158     msg += functions::asString(a_size);
159     msg += ')';
160     throw RuntimeException(msg, ANNA_FILE_LOCATION);
161   }
162
163   return a_buffer [pos];
164 }
165
166 char& DataBlock::operator [](const int pos)
167 throw(RuntimeException) {
168   if(pos >= a_size) {
169     std::string msg("Position: ");
170     msg += functions::asString(pos);
171     msg += " | Out of range [0,";
172     msg += functions::asString(a_size);
173     msg += ')';
174     throw RuntimeException(msg, ANNA_FILE_LOCATION);
175   }
176
177   char* aux = const_cast <char*>(a_buffer);
178   return aux[pos];
179 }
180
181 void DataBlock::append(const char* data, const int len)
182 throw(RuntimeException) {
183   if(a_buffer == data && data != NULL && len > 0)
184     throw RuntimeException("Can not append myself", ANNA_FILE_LOCATION);
185
186   if((a_size + len) >= a_maxSize) extend(len);
187
188   register char* w = a_buffer + a_size;
189
190   switch(len) {
191   case 0: break;
192   case 1: *w = *data; a_size ++; break;
193   case 2: *w = *data; *(w + 1) = *(data + 1); a_size += 2; break;
194   case 3: *w = *data; *(w + 1) = *(data + 1); *(w + 2) = *(data + 2); a_size += 3; break;
195   case 4: *w = *data; *(w + 1) = *(data + 1); *(w + 2) = *(data + 2); *(w + 3) = *(data + 3); a_size += 4; break;
196   default: anna_memcpy(w, data, len); a_size += len; break;
197   }
198 }
199
200 void DataBlock::remove(const int pos, const int nbytes)
201 throw(RuntimeException) {
202   if(a_deepCopy == false)
203     throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION);
204
205   if(pos >= a_size || pos < 0)
206     throw RuntimeException("Position to remove is out of range", ANNA_FILE_LOCATION);
207
208   const int nbytesToMove = a_size - (pos + nbytes);
209
210   if(nbytesToMove < 0)
211     throw RuntimeException("nbytes to remove are out of range", ANNA_FILE_LOCATION);
212
213   if(nbytesToMove > 0)
214     anna_memmove(a_buffer + pos, a_buffer + pos + nbytes, nbytesToMove);
215
216   a_size -= nbytes;
217 }
218
219 void DataBlock::remove(const int nbytes)
220 throw(RuntimeException) {
221   if(a_deepCopy == false)
222     throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION);
223
224   if(nbytes == 0)
225     return;
226
227   const int nbytesToMove = a_size - nbytes;
228
229   if(nbytesToMove < 0)
230     throw RuntimeException("nbytes to remove are out of range", ANNA_FILE_LOCATION);
231
232   if(nbytesToMove > 0)
233     anna_memmove(a_buffer, a_buffer + nbytes, nbytesToMove);
234
235   a_size -= nbytes;
236 }
237
238 void DataBlock::extend(const int nbytes)
239 throw(RuntimeException) {
240   if(a_deepCopy == false)
241     throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION);
242
243   if((a_size + nbytes) < a_maxSize)
244     return;
245
246   int newSize = ((a_size + nbytes)  << 1) - ((a_size + nbytes)  >> 1);
247   char* newBuffer = new char [newSize];
248
249   if(newBuffer == NULL)
250     throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION);
251
252   if(a_size > 0)
253     anna_memcpy(newBuffer, a_buffer, a_size);
254
255   delete [] a_buffer;
256   a_buffer = newBuffer;
257   a_maxSize = newSize;
258 }
259
260 std::string DataBlock::asString(const int characterByLine) const
261 throw() {
262   char aux [8];
263   std::string numbers;
264   std::string characters;
265   unsigned char c;
266   int i;
267   std::string result;
268
269   if(a_size == 0) {
270     result = "<null>";
271     return result;
272   }
273
274   result += " (";
275   result += functions::asHexString(anna_ptrnumber_cast(a_buffer));
276   result += "):";
277
278   for(i = 0; i < a_size; i ++) {
279     if((i % characterByLine) == 0) {
280       if(i > 0) {
281         result += '\n';
282         result += numbers;
283         result += "  ";
284         result += characters;
285         characters.clear();
286       }
287
288       sprintf(aux, "%4d: ", i);
289       numbers = aux;
290     }
291
292     c = (unsigned char) a_buffer [i];
293     sprintf(aux, "%02x ", c);
294     numbers += aux;
295     characters += (isprint(c) ? (char) c : '.');
296   }
297
298   result += '\n';
299   result += numbers;
300
301   while((i % characterByLine) != 0) {
302     result += "   ";
303     i ++;
304   }
305
306   result += "  ";
307   return result += characters;
308 }