|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include "SqlUtil.h" |
|
17 #include "SqlBufFlat.h" |
|
18 |
|
19 /** |
|
20 Sets the flat buffer pointer to NULL |
|
21 */ |
|
22 RSqlBufFlat::RSqlBufFlat() : |
|
23 iBuf(NULL), |
|
24 iMaxSize(0), |
|
25 iBufPtr(NULL, 0) |
|
26 { |
|
27 } |
|
28 |
|
29 /** |
|
30 "Resource acquisiton" method. |
|
31 Sets the elements count of a new or already existing flat buffer. |
|
32 |
|
33 The occupied memory won't be freed (in case of buffer resizing). |
|
34 The buffer content is not preserved (in case of buffer resizing). |
|
35 |
|
36 All elements set to have: |
|
37 - invalid type; |
|
38 - zero length; |
|
39 - zero data position; |
|
40 |
|
41 @param aCount Desired flat buffer elements count |
|
42 |
|
43 @return KErrNone, The operation has completed successfully; |
|
44 KErrNoMemory, Out of memory condition has occured. |
|
45 */ |
|
46 TInt RSqlBufFlat::SetCount(TInt aCount) |
|
47 { |
|
48 __SQLASSERT(aCount >= 0, ESqlPanicBadArgument); |
|
49 TInt headerSize = sizeof(RSqlBufFlat::TCell) * aCount; |
|
50 TInt newSize = headerSize + sizeof(RSqlBufFlat::TBufFlat); |
|
51 if(DoReAlloc(newSize) != KErrNone) |
|
52 { |
|
53 return KErrNoMemory; |
|
54 } |
|
55 TBufFlat& buf = *iBuf; |
|
56 buf.iCount = aCount; |
|
57 buf.iHeaderSize = headerSize; |
|
58 buf.iSize = newSize; |
|
59 buf.iReserved = 0; |
|
60 DoInit(); |
|
61 SQLFLATBUF_INVARIANT(); |
|
62 return KErrNone; |
|
63 } |
|
64 |
|
65 /** |
|
66 Reallocates the amount of the occupied by the flat buffer memory. |
|
67 The operation preserves the content of the flat buffer. |
|
68 Note: if the new size is less or equal to the max size of the buffer, |
|
69 no memory will be allocated. |
|
70 |
|
71 @param aSize Desired flat buffer size in bytes |
|
72 |
|
73 @return KErrNone, The operation has completed successfully; |
|
74 KErrNoMemory, Out of memory condition has occured. |
|
75 */ |
|
76 TInt RSqlBufFlat::ReAlloc(TInt aSize) |
|
77 { |
|
78 SQLFLATBUF_INVARIANT(); |
|
79 TInt err = DoReAlloc(aSize); |
|
80 SQLFLATBUF_INVARIANT(); |
|
81 return err; |
|
82 } |
|
83 |
|
84 /** |
|
85 Cleans up the flat buffer content and |
|
86 frees the occupied memory if the memory is above KBufLimit. |
|
87 The count of elements is preserved. |
|
88 |
|
89 If the buffer size is bigger than KBufLimit, |
|
90 the buffer will be reallocated and the buffer content - not preserved. |
|
91 |
|
92 If the buffer size is less or equal to KBufLimit, |
|
93 no memory will be reallocated and the buffer preserves its content. |
|
94 |
|
95 It is guaranteed that the reallocated buffer will have the same address in the heap |
|
96 as the original one. |
|
97 */ |
|
98 void RSqlBufFlat::ResetAndMinimize() |
|
99 { |
|
100 SQLFLATBUF_INVARIANT(); |
|
101 Reset(); |
|
102 #ifdef _DEBUG |
|
103 const TInt KBufLimit = Max((TInt)RSqlBufFlat::EExpandSize, SysDataSize()); |
|
104 const TBufFlat* oldBuf = iBuf; |
|
105 #else |
|
106 const TInt KBufLimit = Max((8 * 1024), SysDataSize()); |
|
107 #endif |
|
108 if(iMaxSize > KBufLimit) |
|
109 { |
|
110 iMaxSize = KBufLimit - 1; //to force the reallocation |
|
111 (void)DoReAlloc(KBufLimit);//User::ReAlloc() does not fail if the new requested size is less than the current block size |
|
112 } |
|
113 __SQLASSERT(oldBuf == iBuf, ESqlPanicInternalError); |
|
114 SQLFLATBUF_INVARIANT(); |
|
115 } |
|
116 |
|
117 /** |
|
118 Cleans up the flat buffer content but does not free the occupied memory. |
|
119 The count of elements is preserved. |
|
120 |
|
121 All elements set to have: |
|
122 - invalid type; |
|
123 - zero length; |
|
124 - zero data position; |
|
125 |
|
126 The element count is preserved. |
|
127 */ |
|
128 void RSqlBufFlat::Reset() |
|
129 { |
|
130 SQLFLATBUF_INVARIANT(); |
|
131 iBuf->iSize = SysDataSize(); |
|
132 DoInit(); |
|
133 SQLFLATBUF_INVARIANT(); |
|
134 } |
|
135 |
|
136 /** |
|
137 Closes the flat bufer and frees the allocated memory. |
|
138 */ |
|
139 void RSqlBufFlat::Close() |
|
140 { |
|
141 User::Free(iBuf); |
|
142 iBuf = NULL; |
|
143 } |
|
144 |
|
145 /** |
|
146 Sets the content of a field. |
|
147 |
|
148 @param aIndex Field index |
|
149 @param aType Field type |
|
150 @param aData Field data, may be NULL |
|
151 @param aDataLength Field data length, may be 0 |
|
152 |
|
153 @return KErrNone, The operation has completed successfully; |
|
154 KErrNoMemory, Out of memory condition has occured. |
|
155 */ |
|
156 TInt RSqlBufFlat::SetField(TInt aIndex, TInt aType, const void* aData, TInt aDataLength) |
|
157 { |
|
158 SQLFLATBUF_INVARIANT(); |
|
159 __SQLASSERT((TUint)aIndex < iBuf->iCount, ESqlPanicBadArgument); |
|
160 __SQLASSERT((TUint)aType < RSqlBufFlat::EMaxType, ESqlPanicBadArgument); |
|
161 __SQLASSERT((TUint)aDataLength < RSqlBufFlat::EMaxLength, ESqlPanicBadArgument); |
|
162 if(aData) //field value "present" |
|
163 { |
|
164 __SQLASSERT(aDataLength >= 0, ESqlPanicBadArgument); |
|
165 if(aDataLength > 0) |
|
166 { |
|
167 if(Reserve(aDataLength) != KErrNone) |
|
168 { |
|
169 return KErrNoMemory; |
|
170 } |
|
171 } |
|
172 DoSet(aIndex, aType, aData, aDataLength); |
|
173 } |
|
174 else if(aDataLength == 0) //data is NULL, length is 0 - "null" field |
|
175 { |
|
176 DoSet(aIndex, aType, NULL, 0); |
|
177 } |
|
178 else //field value "not present" |
|
179 { |
|
180 RSqlBufFlat::TCell& cell = *(Header() + aIndex); |
|
181 cell.iBits = (TUint)(((TUint)aType << RSqlBufFlat::EWidthLen) | (TUint)aDataLength); |
|
182 cell.iPos = 0; |
|
183 } |
|
184 SQLFLATBUF_INVARIANT(); |
|
185 return KErrNone; |
|
186 } |
|
187 |
|
188 /** |
|
189 Initialzies the flat buffer header. |
|
190 All field set: |
|
191 - invalid type; |
|
192 - zero length; |
|
193 - "Not present"; |
|
194 */ |
|
195 void RSqlBufFlat::DoInit() |
|
196 { |
|
197 TBufFlat& buf = *iBuf; |
|
198 __SQLASSERT(buf.iCount >= 0, ESqlPanicInternalError); |
|
199 __SQLASSERT(buf.iSize <= iMaxSize, ESqlPanicInternalError); |
|
200 __SQLASSERT(buf.iHeaderSize == sizeof(RSqlBufFlat::TCell) * buf.iCount, ESqlPanicInternalError); |
|
201 if(buf.iHeaderSize > 0) |
|
202 { |
|
203 Mem::FillZ(Header(), buf.iHeaderSize); |
|
204 } |
|
205 } |
|
206 |
|
207 /** |
|
208 Reallocates the amount of the occupied by the flat buffer memory |
|
209 (only in case the requested size is bigger than the buffer size or the buffer does not exist). |
|
210 The operation preserves the content of the flat buffer. |
|
211 |
|
212 @param aSize Desired flat buffer size in bytes. |
|
213 |
|
214 @return KErrNone, The operation has completed successfully; |
|
215 KErrNoMemory, Out of memory condition has occured. |
|
216 */ |
|
217 TInt RSqlBufFlat::DoReAlloc(TInt aSize) |
|
218 { |
|
219 if(!iBuf || iMaxSize < aSize) |
|
220 { |
|
221 //Calculate buffer new size (sometimes allocates more, for example, if |
|
222 //aSize % RSqlBufFlat::EExpandSize == 0, then one more RSqlBufFlat::EExpandSize page is allocated). |
|
223 TInt newSize = (aSize / RSqlBufFlat::EExpandSize + 1) * RSqlBufFlat::EExpandSize; |
|
224 RSqlBufFlat::TBufFlat* newBuf = static_cast <RSqlBufFlat::TBufFlat*> (User::ReAlloc(iBuf, newSize)); |
|
225 if(!newBuf) |
|
226 { |
|
227 return KErrNoMemory; |
|
228 } |
|
229 iBuf = newBuf; |
|
230 iMaxSize = newSize; |
|
231 } |
|
232 return KErrNone; |
|
233 } |
|
234 |
|
235 /** |
|
236 Initialzes a flat buffer field. |
|
237 A memory for the field data has to be allocated before the call. |
|
238 |
|
239 @param aIndex Field index |
|
240 @param aType Field type |
|
241 @param aData Field data, may be NULL |
|
242 @param aDataLength Field data length, may be 0 |
|
243 */ |
|
244 void RSqlBufFlat::DoSet(TInt aIndex, TInt aType, const void* aData, TInt aDataLength) |
|
245 { |
|
246 TBufFlat& buf = *iBuf; |
|
247 __SQLASSERT((TUint)aDataLength < RSqlBufFlat::EMaxLength, ESqlPanicBadArgument); |
|
248 __SQLASSERT(aDataLength > 0 ? aData != NULL : ETrue, ESqlPanicBadArgument); |
|
249 __SQLASSERT(aDataLength <= (iMaxSize - buf.iSize), ESqlPanicInternalError); |
|
250 __SQLASSERT(::IsAligned8(buf.iSize), ESqlPanicInternalError); |
|
251 RSqlBufFlat::TCell& cell = *(Header() + aIndex); |
|
252 cell.iBits = (TUint)(((TUint)aType << RSqlBufFlat::EWidthLen) | (TUint)aDataLength); |
|
253 cell.iPos = 1; //not 0, because 0 means "not present" |
|
254 if(aDataLength > 0) //for fields with length > 0 set the data and reinitalize cell.iPos |
|
255 { |
|
256 #ifdef _DEBUG |
|
257 Mem::Copy(reinterpret_cast <TUint8*> (iBuf) + buf.iSize, &KSqlBufFlatMagicValue, sizeof(KSqlBufFlatMagicValue)); |
|
258 buf.iSize += sizeof(KSqlBufFlatMagicValue); |
|
259 #endif |
|
260 cell.iPos = buf.iSize - sizeof(RSqlBufFlat::TBufFlat); |
|
261 Mem::Copy(reinterpret_cast <TUint8*> (iBuf) + buf.iSize, reinterpret_cast <const TUint8*> (aData), aDataLength); |
|
262 buf.iSize += ::AlignedLen8(aDataLength); //align the next field start position |
|
263 //it is guaranteed that this "+" operation will not make iSize bigger than |
|
264 //iMaxSize, because the memory allocations are 8-byte aligned |
|
265 //(even RSqlBufFlat::EExpandSize aligned) |
|
266 } |
|
267 } |
|
268 |
|
269 /** |
|
270 Makes sure that the flat buffer has enough free space for a block of data with "aLength" length. |
|
271 The function may reallocated the buffer if there is not enough space. |
|
272 |
|
273 @param aLength The requested free memory length. |
|
274 |
|
275 @return KErrNone, The operation has completed successfully; |
|
276 KErrNoMemory, Out of memory condition has occured. |
|
277 */ |
|
278 TInt RSqlBufFlat::Reserve(TInt aLength) |
|
279 { |
|
280 #ifdef _DEBUG |
|
281 TInt diff = aLength + sizeof(KSqlBufFlatMagicValue) - Available(); |
|
282 #else |
|
283 TInt diff = aLength - Available(); |
|
284 #endif |
|
285 return diff > 0 ? DoReAlloc(iMaxSize + diff) : KErrNone; |
|
286 } |
|
287 |
|
288 #ifdef _DEBUG |
|
289 /** |
|
290 Panics in _DEBUG mode if the flat buffer content is inconsistent. |
|
291 */ |
|
292 void RSqlBufFlat::Invariant() const |
|
293 { |
|
294 __SQLASSERT(iBuf != NULL, ESqlPanicInternalError); |
|
295 const TBufFlat& buf = *iBuf; |
|
296 __SQLASSERT(buf.iCount >= 0, ESqlPanicInternalError); |
|
297 __SQLASSERT(buf.iHeaderSize == sizeof(RSqlBufFlat::TCell) * buf.iCount, ESqlPanicInternalError); |
|
298 __SQLASSERT(::IsAligned8(buf.iSize), ESqlPanicInternalError); |
|
299 __SQLASSERT(buf.iSize >= buf.iHeaderSize + sizeof(RSqlBufFlat::TBufFlat), ESqlPanicInternalError); |
|
300 __SQLASSERT(buf.iSize <= iMaxSize, ESqlPanicInternalError); |
|
301 __SQLASSERT(buf.iSize <= User::AllocLen(iBuf), ESqlPanicInternalError); |
|
302 for(TInt i=0;i<(TInt)buf.iCount;++i) |
|
303 { |
|
304 const RSqlBufFlat::TCell& cell = *((reinterpret_cast <const RSqlBufFlat::TCell*> (iBuf + 1)) + i); |
|
305 __SQLASSERT(cell.Type() < RSqlBufFlat::EMaxType, ESqlPanicInternalError); |
|
306 if(cell.Size() > 0 && cell.iPos >= buf.iHeaderSize) //only for present fields with length > 0 |
|
307 { |
|
308 __SQLASSERT((TUint)cell.Size() <= buf.iSize, ESqlPanicInternalError); |
|
309 __SQLASSERT(cell.iPos < (buf.iSize - sizeof(RSqlBufFlat::TBufFlat)), ESqlPanicInternalError); |
|
310 TUint64 val = *(TUint64*)(reinterpret_cast <TUint8*> (iBuf) + cell.iPos + sizeof(RSqlBufFlat::TBufFlat) - sizeof(KSqlBufFlatMagicValue)); |
|
311 __SQLASSERT(val == KSqlBufFlatMagicValue, ESqlPanicInternalError); |
|
312 } |
|
313 } |
|
314 } |
|
315 #endif//_DEBUG |