Improve dynamic test provision
[anna.git] / source / core / DataBlock.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <ctype.h>
10 #include <stdio.h>
11
12 #include <anna/core/DataBlock.hpp>
13 #include <anna/core/RuntimeException.hpp>
14 #include <anna/core/functions.hpp>
15
16 using namespace std;
17 using namespace anna;
18
19 #define anna_call_extend(a) \
20    if ((a_size + (a)) >= a_maxSize) extend ((a));
21
22 DataBlock::DataBlock(const char* buffer, const int size, const bool deepCopy)
23 throw(RuntimeException) :
24   a_buffer(NULL),
25   a_size(0),
26   a_deepCopy(deepCopy),
27   a_maxSize(0) {
28   initialize(buffer, size);
29 }
30
31 DataBlock::DataBlock(const DataBlock& other)
32 throw(RuntimeException) :
33   a_buffer(NULL),
34   a_size(0),
35   a_deepCopy(other.a_deepCopy),
36   a_maxSize(0) {
37   initialize(other.a_buffer, other.a_size);
38 }
39
40 DataBlock::~DataBlock() {
41   if(a_deepCopy)
42     delete [] a_buffer;
43 }
44
45 void DataBlock::initialize(const char* buffer, const int size)
46 throw(RuntimeException) {
47   if(a_deepCopy == false) {
48     a_buffer = const_cast <char*>(buffer);
49     a_size = size;
50   } else {
51     if((a_maxSize = a_size = size) > 0) {
52       if((a_buffer = new char [size]) != NULL)
53         anna_memcpy(a_buffer, buffer, size);
54       else
55         throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION);
56     } else
57       a_buffer = NULL;
58   }
59 }
60
61 void DataBlock::setSize(const int size)
62 throw(RuntimeException) {
63 //   if (size > a_maxSize) {
64 //      string msg ("DataBlock::setSize | MaxSize: ");
65 //      msg += functions::asString (a_maxSize);
66 //      msg += " | Size: ";
67 //      msg += functions::asString (size);
68 //      msg += " | Invalid size";
69 //      throw RuntimeException (msg, ANNA_FILE_LOCATION);
70 //   }
71 //
72 //   a_currentMessage.assign (a_buffer.getData () + a_offset, remainingSize);
73 //
74 // Sin embargo, el fetch() de nuestro clientSocket hace esto:
75 //   a_buffer.setup (a_data.getData () + a_offset, remainingSize);
76 //
77 // Y el setup no hace reserva, solo asocia (buffer y size)
78   a_size = size;
79 }
80
81 void DataBlock::allocate(const int nbytes)
82 throw(RuntimeException) {
83   if(nbytes > a_size) {
84     if(a_maxSize == 0) {
85       if(a_deepCopy == false)
86         throw RuntimeException("Deep-Copy was not active", ANNA_FILE_LOCATION);
87
88       if((a_buffer = new char [a_maxSize = nbytes]) == NULL)
89         throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION);
90     } else
91       extend(nbytes - a_size);
92
93     a_size = nbytes;
94   }
95 }
96
97 void DataBlock::assign(const char* buffer, const int size)
98 throw(RuntimeException) {
99   if(a_deepCopy == false) {
100     a_buffer = const_cast <char*>(buffer);
101     a_size = size;
102   } else {
103     delete a_buffer;
104     a_maxSize = a_size = 0;
105     initialize(buffer, size);
106   }
107 }
108
109 DataBlock& DataBlock::operator = (const DataBlock & right)
110 throw(RuntimeException) {
111   if(this != &right) {
112     if(a_deepCopy) {
113       a_size = 0;
114       append(right.a_buffer, right.a_size);
115     } else {
116       a_buffer = right.a_buffer;
117       a_size = right.a_size;
118     }
119   }
120
121   return *this;
122 }
123
124 const char DataBlock::operator [](const int pos) const
125 throw(RuntimeException) {
126   if(pos >= a_size) {
127     std::string msg("Position: ");
128     msg += functions::asString(pos);
129     msg += " | Out of range [0,";
130     msg += functions::asString(a_size);
131     msg += ')';
132     throw RuntimeException(msg, ANNA_FILE_LOCATION);
133   }
134
135   return a_buffer [pos];
136 }
137
138 char& DataBlock::operator [](const int pos)
139 throw(RuntimeException) {
140   if(pos >= a_size) {
141     std::string msg("Position: ");
142     msg += functions::asString(pos);
143     msg += " | Out of range [0,";
144     msg += functions::asString(a_size);
145     msg += ')';
146     throw RuntimeException(msg, ANNA_FILE_LOCATION);
147   }
148
149   char* aux = const_cast <char*>(a_buffer);
150   return aux[pos];
151 }
152
153 void DataBlock::append(const char* data, const int len)
154 throw(RuntimeException) {
155   if(a_buffer == data && data != NULL && len > 0)
156     throw RuntimeException("Can not append myself", ANNA_FILE_LOCATION);
157
158   if((a_size + len) >= a_maxSize) extend(len);
159
160   char* w = a_buffer + a_size;
161
162   switch(len) {
163   case 0: break;
164   case 1: *w = *data; a_size ++; break;
165   case 2: *w = *data; *(w + 1) = *(data + 1); a_size += 2; break;
166   case 3: *w = *data; *(w + 1) = *(data + 1); *(w + 2) = *(data + 2); a_size += 3; break;
167   case 4: *w = *data; *(w + 1) = *(data + 1); *(w + 2) = *(data + 2); *(w + 3) = *(data + 3); a_size += 4; break;
168   default: anna_memcpy(w, data, len); a_size += len; break;
169   }
170 }
171
172 void DataBlock::remove(const int pos, const int nbytes)
173 throw(RuntimeException) {
174   if(a_deepCopy == false)
175     throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION);
176
177   if(pos >= a_size || pos < 0)
178     throw RuntimeException("Position to remove is out of range", ANNA_FILE_LOCATION);
179
180   const int nbytesToMove = a_size - (pos + nbytes);
181
182   if(nbytesToMove < 0)
183     throw RuntimeException("nbytes to remove are out of range", ANNA_FILE_LOCATION);
184
185   if(nbytesToMove > 0)
186     anna_memmove(a_buffer + pos, a_buffer + pos + nbytes, nbytesToMove);
187
188   a_size -= nbytes;
189 }
190
191 void DataBlock::remove(const int nbytes)
192 throw(RuntimeException) {
193   if(a_deepCopy == false)
194     throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION);
195
196   if(nbytes == 0)
197     return;
198
199   const int nbytesToMove = a_size - nbytes;
200
201   if(nbytesToMove < 0)
202     throw RuntimeException("nbytes to remove are out of range", ANNA_FILE_LOCATION);
203
204   if(nbytesToMove > 0)
205     anna_memmove(a_buffer, a_buffer + nbytes, nbytesToMove);
206
207   a_size -= nbytes;
208 }
209
210 void DataBlock::extend(const int nbytes)
211 throw(RuntimeException) {
212   if(a_deepCopy == false)
213     throw RuntimeException("Deep copy not activated", ANNA_FILE_LOCATION);
214
215   if((a_size + nbytes) < a_maxSize)
216     return;
217
218   int newSize = ((a_size + nbytes)  << 1) - ((a_size + nbytes)  >> 1);
219   char* newBuffer = new char [newSize];
220
221   if(newBuffer == NULL)
222     throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION);
223
224   if(a_size > 0)
225     anna_memcpy(newBuffer, a_buffer, a_size);
226
227   delete [] a_buffer;
228   a_buffer = newBuffer;
229   a_maxSize = newSize;
230 }
231
232 std::string DataBlock::asString(const int characterByLine) const
233 throw() {
234   char aux [8];
235   std::string numbers;
236   std::string characters;
237   unsigned char c;
238   int i;
239   std::string result;
240
241   if(a_size == 0) {
242     result = "<null>";
243     return result;
244   }
245
246   result += " (";
247   result += functions::asHexString(anna_ptrnumber_cast(a_buffer));
248   result += "):";
249
250   for(i = 0; i < a_size; i ++) {
251     if((i % characterByLine) == 0) {
252       if(i > 0) {
253         result += '\n';
254         result += numbers;
255         result += "  ";
256         result += characters;
257         characters.clear();
258       }
259
260       sprintf(aux, "%4d: ", i);
261       numbers = aux;
262     }
263
264     c = (unsigned char) a_buffer [i];
265     sprintf(aux, "%02x ", c);
266     numbers += aux;
267     characters += (isprint(c) ? (char) c : '.');
268   }
269
270   result += '\n';
271   result += numbers;
272
273   while((i % characterByLine) != 0) {
274     result += "   ";
275     i ++;
276   }
277
278   result += "  ";
279   return result += characters;
280 }