-rw-r--r-- | shared-code/Dynamide.h | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/shared-code/Dynamide.h b/shared-code/Dynamide.h new file mode 100644 index 0000000..32c93f7 --- a/dev/null +++ b/shared-code/Dynamide.h | |||
@@ -0,0 +1,443 @@ | |||
1 | #ifndef __DYNAMIDE_H | ||
2 | #define __DYNAMIDE_H | ||
3 | |||
4 | #include "LRUCache.h" | ||
5 | |||
6 | namespace Klever { | ||
7 | |||
8 | template<int fbSize,int bSize> | ||
9 | class CDynamide : public CObject { | ||
10 | structfirstBlock { | ||
11 | LONGfreeFile; | ||
12 | BYTEcrap[fbSize-sizeof(LONG)]; | ||
13 | }; | ||
14 | structtheBlock { | ||
15 | LONGnext; | ||
16 | BYTEdata[bSize-sizeof(LONG)]; | ||
17 | }; | ||
18 | public: | ||
19 | static firstBlock FirstBlock; | ||
20 | static theBlock TheBlock; | ||
21 | private: | ||
22 | classCDynaCache : public CLRUCache<DWORD,DWORD,theBlock> { | ||
23 | public: | ||
24 | CFile* m_File; | ||
25 | BOOL m_bAutodelete; | ||
26 | CDynaCache(CFile* file,BOOL bAutodelete=TRUE) : CLRUCache<DWORD,DWORD,theBlock>(64) { | ||
27 | m_File=file; | ||
28 | m_bAutodelete=bAutodelete; | ||
29 | } | ||
30 | virtual ~CDynaCache() { | ||
31 | Flush(); | ||
32 | if(m_bAutodelete){ | ||
33 | m_File->Close(); | ||
34 | delete m_File; | ||
35 | } | ||
36 | } | ||
37 | virtual BOOL _ReadIn(DWORD idx,theBlock* data) { | ||
38 | LONG p = sizeof(firstBlock)+idx*sizeof(theBlock); | ||
39 | LONG s = m_File->Seek(p,CFile::begin); | ||
40 | if(p==s){ | ||
41 | UINT rb = m_File->Read(data,sizeof(*data)); | ||
42 | if(rb==sizeof(*data)) | ||
43 | return TRUE; | ||
44 | if(rb) | ||
45 | return FALSE; | ||
46 | memset(data,0,sizeof(*data)); | ||
47 | data->next=-1; | ||
48 | try{ | ||
49 | m_File->Write(data,sizeof(*data)); | ||
50 | }catch(CException* e){ | ||
51 | e->Delete(); | ||
52 | return FALSE; | ||
53 | } | ||
54 | }else{ | ||
55 | LONG togo = p-s; | ||
56 | ASSERT(togo>0); | ||
57 | ASSERT(!(togo%sizeof(theBlock))); | ||
58 | memset(data,0,sizeof(*data)); | ||
59 | data->next=-1; | ||
60 | while(togo>=0){ | ||
61 | try{ | ||
62 | m_File->Write(data,sizeof(*data)); | ||
63 | }catch(CException* e){ | ||
64 | e->Delete(); | ||
65 | return FALSE; | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | return TRUE; | ||
70 | } | ||
71 | virtual BOOL _WriteOut(DWORD idx,theBlock* data) { | ||
72 | LONG p = sizeof(firstBlock)+idx*sizeof(theBlock); | ||
73 | LONG s = m_File->Seek(p,CFile::begin); | ||
74 | if(p!=s) | ||
75 | return FALSE; | ||
76 | try{ | ||
77 | m_File->Write(data,sizeof(*data)); | ||
78 | }catch(CException* e){ | ||
79 | e->Delete(); | ||
80 | return FALSE; | ||
81 | } | ||
82 | return TRUE; | ||
83 | } | ||
84 | DWORD AllocateNode() { | ||
85 | LONG l = m_File->GetLength(); | ||
86 | ASSERT(!((l-sizeof(firstBlock))%sizeof(theBlock))); | ||
87 | m_File->SetLength(l+sizeof(theBlock)); | ||
88 | return (l-sizeof(firstBlock))/sizeof(theBlock); | ||
89 | } | ||
90 | BOOL Read1stBlock(firstBlock* fb) { | ||
91 | m_File->SeekToBegin(); | ||
92 | UINT rb = m_File->Read(fb,sizeof(*fb)); | ||
93 | if(rb==sizeof(*fb)) | ||
94 | return TRUE; | ||
95 | if(rb) | ||
96 | return FALSE; | ||
97 | memset(fb,0,sizeof(*fb)); | ||
98 | fb->freeFile = -1; | ||
99 | try{ | ||
100 | m_File->Write(fb,sizeof(*fb)); | ||
101 | }catch(CException* e){ | ||
102 | e->Delete(); | ||
103 | return FALSE; | ||
104 | } | ||
105 | return TRUE; | ||
106 | } | ||
107 | BOOL Write1stBlock(firstBlock* fb) { | ||
108 | m_File->SeekToBegin(); | ||
109 | try{ | ||
110 | m_File->Write(fb,sizeof(*fb)); | ||
111 | }catch(CException* e){ | ||
112 | e->Delete(); | ||
113 | return FALSE; | ||
114 | } | ||
115 | return TRUE; | ||
116 | } | ||
117 | }; | ||
118 | public: | ||
119 | class CDynaFile : public CFile{ | ||
120 | public: | ||
121 | CDynamide<fbSize,bSize>* m_Daddy; | ||
122 | CArray<LONG,LONG> m_Blocks; | ||
123 | LONG m_Position; | ||
124 | |||
125 | CDynaFile(CDynamide<fbSize,bSize>* daddy) : m_Daddy(NULL) { AttachToDaddy(daddy); } | ||
126 | virtual ~CDynaFile() { Close(); DetachFromDaddy(); } | ||
127 | |||
128 | void AttachToDaddy(CDynamide<fbSize,bSize>* daddy) { | ||
129 | ASSERT(!m_Daddy); | ||
130 | ASSERT(daddy); | ||
131 | m_Daddy=daddy; | ||
132 | m_Daddy->AttachDynaFile(this); | ||
133 | } | ||
134 | void DetachFromDaddy() { | ||
135 | ASSERT(m_Daddy); | ||
136 | ASSERT(!IsOpened()); | ||
137 | m_Daddy->DetachDynaFile(this); | ||
138 | m_Daddy=NULL; | ||
139 | } | ||
140 | |||
141 | BOOL Create() { | ||
142 | if(IsOpened()) | ||
143 | return FALSE; | ||
144 | m_Blocks.SetAtGrow(0,m_Daddy->Allocate()); | ||
145 | ASSERT(m_Blocks[0]>=0); | ||
146 | m_Position=0; | ||
147 | return TRUE; | ||
148 | } | ||
149 | BOOL Open(LONG fb) { | ||
150 | if(IsOpened()) | ||
151 | return FALSE; | ||
152 | ASSERT(fb>=0); | ||
153 | theBlock* b; | ||
154 | do{ | ||
155 | m_Blocks.Add(fb); | ||
156 | b = m_Daddy->m_File->GetCached(fb); | ||
157 | ASSERT(b); | ||
158 | fb=b->next; | ||
159 | if(m_Blocks[m_Blocks.GetUpperBound()]==fb) | ||
160 | return FALSE; | ||
161 | }while(fb>=0); | ||
162 | m_Position=0; | ||
163 | return TRUE; | ||
164 | } | ||
165 | |||
166 | LONG GetFile() { | ||
167 | if(!IsOpened()) | ||
168 | return -1; | ||
169 | return m_Blocks[0]; | ||
170 | } | ||
171 | virtual DWORD GetPosition() const { | ||
172 | if(!IsOpened()) | ||
173 | return 0; | ||
174 | if(m_Position<0) | ||
175 | return 0; | ||
176 | if(m_Position>GetLength()) | ||
177 | return GetLength(); | ||
178 | return m_Position; | ||
179 | } | ||
180 | virtual CString GetFileName() { | ||
181 | CString rv; | ||
182 | if(IsOpened()) | ||
183 | rv.Format("0x%08lX",m_Blocks[0]); | ||
184 | else | ||
185 | rv.Format("None"); | ||
186 | return rv; | ||
187 | } | ||
188 | virtual CString GetFileTitle() { return GetFileName(); } | ||
189 | virtual CString GetFilePath() { return GetFileName(); } | ||
190 | virtual void SetFilePath(LPCTSTR lpszNewName) { ASSERT(FALSE); } | ||
191 | |||
192 | virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL) { ASSERT(FALSE); return FALSE; } | ||
193 | virtual CFile* Duplicate() { ASSERT(FALSE); return NULL; } | ||
194 | |||
195 | virtual LONG Seek(LONG lOff, UINT nFrom) { | ||
196 | if(!IsOpened()) | ||
197 | return -1; | ||
198 | switch(nFrom){ | ||
199 | case CFile::begin: | ||
200 | m_Position=lOff; | ||
201 | break; | ||
202 | case CFile::current: | ||
203 | m_Position+=lOff; | ||
204 | break; | ||
205 | case CFile::end: | ||
206 | m_Position=GetLength()+lOff; | ||
207 | break; | ||
208 | default: | ||
209 | ASSERT(FALSE); | ||
210 | return -1; | ||
211 | } | ||
212 | if(m_Position<0) | ||
213 | m_Position=0; | ||
214 | if(m_Position>GetLength()) | ||
215 | m_Position=GetLength(); | ||
216 | return m_Position; | ||
217 | } | ||
218 | virtual void SetLength(DWORD dwNewLen) { | ||
219 | if(!IsOpened()) | ||
220 | return; | ||
221 | if(dwNewLen<GetLength()){ | ||
222 | dwNewLen=dwNewLen+sizeof(TheBlock.data); | ||
223 | dwNewLen-=dwNewLen%sizeof(TheBlock.data); | ||
224 | while(dwNewLen<GetLength() && m_Blocks.GetSize()>1){ | ||
225 | LONG mb = m_Blocks[m_Blocks.GetUpperBound()]; | ||
226 | LONG mb1 = m_Blocks[m_Blocks.GetUpperBound()-1]; | ||
227 | theBlock* b = m_Daddy->m_File->GetCached(mb1); | ||
228 | ASSERT(b); | ||
229 | ASSERT(b->next==mb); | ||
230 | b->next=-1; | ||
231 | m_Daddy->m_File->MakeDirty(mb1); | ||
232 | m_Daddy->Deallocate(mb); | ||
233 | m_Blocks.SetSize(m_Blocks.GetSize()-1); | ||
234 | } | ||
235 | }else{ | ||
236 | while(dwNewLen>GetLength()){ | ||
237 | LONG mb = m_Blocks[m_Blocks.GetUpperBound()]; | ||
238 | LONG newBlock = m_Daddy->Allocate(); | ||
239 | ASSERT(newBlock>=0); | ||
240 | theBlock* b = m_Daddy->m_File->GetCached(mb); | ||
241 | ASSERT(b); | ||
242 | ASSERT(b->next<0); | ||
243 | b->next=newBlock; | ||
244 | m_Daddy->m_File->MakeDirty(mb); | ||
245 | m_Blocks.Add(newBlock); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | virtual DWORD GetLength() const { | ||
250 | return ((long)m_Blocks.GetSize())*((long)sizeof(TheBlock.data)); | ||
251 | } | ||
252 | |||
253 | virtual UINT Read(void* lpBuf, UINT nCount) { | ||
254 | UINT rv = 0; | ||
255 | ASSERT(m_Position>=0 && m_Position<=GetLength()); | ||
256 | LPBYTE data = (LPBYTE)lpBuf; | ||
257 | while(nCount && m_Position<GetLength()){ | ||
258 | UINT bn = m_Position/sizeof(TheBlock.data); | ||
259 | UINT bo = m_Position%sizeof(TheBlock.data); | ||
260 | theBlock* b = m_Daddy->m_File->GetCached(m_Blocks[bn]); | ||
261 | ASSERT(b); | ||
262 | UINT bc = min(nCount,sizeof(TheBlock.data)-bo); | ||
263 | memmove(data,&b->data[bo],bc); | ||
264 | nCount-=bc; | ||
265 | data=&data[bc]; | ||
266 | rv+=bc; | ||
267 | m_Position+=bc; | ||
268 | } | ||
269 | return rv; | ||
270 | } | ||
271 | virtual void Write(const void* lpBuf, UINT nCount) { | ||
272 | ASSERT(m_Position>=0 && m_Position<=GetLength()); | ||
273 | LPBYTE data = (LPBYTE)lpBuf; | ||
274 | while(nCount){ | ||
275 | UINT bn = m_Position/sizeof(TheBlock.data); | ||
276 | UINT bo = m_Position%sizeof(TheBlock.data); | ||
277 | while(bn>=m_Blocks.GetSize()){ | ||
278 | LONG mb = m_Blocks[m_Blocks.GetUpperBound()]; | ||
279 | LONG newBlock = m_Daddy->Allocate(); | ||
280 | ASSERT(newBlock>=0); | ||
281 | theBlock* b = m_Daddy->m_File->GetCached(mb); | ||
282 | ASSERT(b); | ||
283 | ASSERT(b->next<0); | ||
284 | b->next=newBlock; | ||
285 | m_Daddy->m_File->MakeDirty(mb); | ||
286 | m_Blocks.Add(newBlock); | ||
287 | } | ||
288 | theBlock* b = m_Daddy->m_File->GetCached(m_Blocks[bn]); | ||
289 | ASSERT(b); | ||
290 | UINT bc = min(nCount,sizeof(TheBlock.data)-bo); | ||
291 | memmove(&b->data[bo],data,bc); | ||
292 | m_Daddy->m_File->MakeDirty(m_Blocks[bn]); | ||
293 | nCount-=bc; | ||
294 | data=&data[bc]; | ||
295 | m_Position+=bc; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | virtual void LockRange(DWORD dwPos, DWORD dwCount) { ASSERT(FALSE); } | ||
300 | virtual void UnlockRange(DWORD dwPos, DWORD dwCount) { ASSERT(FALSE); } | ||
301 | |||
302 | virtual void Abort() { ASSERT(FALSE); } | ||
303 | virtual void Flush() { | ||
304 | m_Daddy->m_File->Flush(); | ||
305 | } | ||
306 | virtual void Close() { | ||
307 | m_Blocks.RemoveAll(); | ||
308 | } | ||
309 | |||
310 | BOOL IsOpened() const { return m_Blocks.GetSize()!=0; } | ||
311 | }; | ||
312 | |||
313 | CDynaCache* m_File; | ||
314 | firstBlock m_FB; | ||
315 | |||
316 | CDynamide() : m_File(NULL) {} | ||
317 | ~CDynamide() { Close(); } | ||
318 | |||
319 | BOOL AttachDynaFile(CDynaFile* f) { | ||
320 | //ASSERT(!m_Files.Find(f)); | ||
321 | //m_Files.AddHead(f); | ||
322 | return TRUE; | ||
323 | } | ||
324 | BOOL DetachDynaFile(CDynaFile* f) { | ||
325 | //POSITION p = m_Files.Find(f); | ||
326 | //ASSERT(p); | ||
327 | //m_Files.RemoveAt(p); | ||
328 | return TRUE; | ||
329 | } | ||
330 | |||
331 | BOOL Open(LPCTSTR file,BOOL bRO=FALSE) { | ||
332 | Close(); | ||
333 | try{ | ||
334 | CFile* f = new CFile(file,CFile::typeBinary|(bRO?CFile::modeRead|CFile::shareDenyWrite:CFile::modeReadWrite|CFile::shareDenyRead)); | ||
335 | return Attach(f,TRUE); | ||
336 | }catch(CException* e){ | ||
337 | e->Delete(); | ||
338 | return FALSE; | ||
339 | } | ||
340 | } | ||
341 | BOOL Create(LPCTSTR file) { | ||
342 | Close(); | ||
343 | try{ | ||
344 | CFile* f = new CFile(file,CFile::typeBinary|CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyRead); | ||
345 | return Attach(f,TRUE); | ||
346 | }catch(CException* e){ | ||
347 | e->Delete(); | ||
348 | return FALSE; | ||
349 | } | ||
350 | } | ||
351 | BOOL Attach(CFile* file,BOOL bAutodelete=TRUE) { | ||
352 | if(IsOpened()) | ||
353 | return FALSE; | ||
354 | m_File = new CDynaCache(file,bAutodelete); | ||
355 | if(!m_File->Read1stBlock(&m_FB)){ | ||
356 | memset(&m_FB,0,sizeof(m_FB)); | ||
357 | m_FB.freeFile=-1; | ||
358 | VERIFY(m_File->Write1stBlock(&m_FB)); | ||
359 | } | ||
360 | return IsOpened(); | ||
361 | } | ||
362 | // CFile* Detach(); | ||
363 | BOOL Close() { | ||
364 | if(!IsOpened()) | ||
365 | return FALSE; | ||
366 | m_File->Write1stBlock(&m_FB); | ||
367 | delete m_File; | ||
368 | m_File=NULL; | ||
369 | return TRUE; | ||
370 | } | ||
371 | BOOL IsOpened() { | ||
372 | return m_File != NULL; | ||
373 | } | ||
374 | BOOL Write1stBlock(void) { | ||
375 | if(!IsOpened()) | ||
376 | return FALSE; | ||
377 | VERIFY(m_File->Write1stBlock(&m_FB)); | ||
378 | return TRUE; | ||
379 | } | ||
380 | |||
381 | CDynaFile* CreateFile() { | ||
382 | CDynaFile* rv = new CDynaFile(this); | ||
383 | if(rv->Create()) | ||
384 | return rv; | ||
385 | delete rv; | ||
386 | return NULL; | ||
387 | } | ||
388 | CDynaFile* OpenFile(LONG fb) { | ||
389 | CDynaFile* rv = new CDynaFile(this); | ||
390 | if(rv->Open(fb)) | ||
391 | return rv; | ||
392 | delete rv; | ||
393 | return NULL; | ||
394 | } | ||
395 | BOOL DeleteFile(LONG fb) { | ||
396 | while(fb>=0){ | ||
397 | theBlock* b = m_File->GetCached(fb); | ||
398 | LONG nb = b->next; | ||
399 | Deallocate(fb); | ||
400 | fb=nb; | ||
401 | } | ||
402 | return TRUE; | ||
403 | } | ||
404 | |||
405 | LONG Allocate() { | ||
406 | if(!IsOpened()) | ||
407 | return -1; | ||
408 | if(m_FB.freeFile<0){ | ||
409 | LONG rv = m_File->AllocateNode(); | ||
410 | theBlock *b = m_File->GetCached(rv); | ||
411 | b->next=-1; | ||
412 | m_File->MakeDirty(rv); | ||
413 | return rv; | ||
414 | } | ||
415 | LONG rv = m_FB.freeFile; | ||
416 | theBlock *b = m_File->GetCached(rv); | ||
417 | m_FB.freeFile=b->next; | ||
418 | b->next=-1; | ||
419 | m_File->MakeDirty(rv); | ||
420 | m_File->Write1stBlock(&m_FB); | ||
421 | return rv; | ||
422 | } | ||
423 | BOOL Deallocate(LONG bk) { | ||
424 | if(!IsOpened()) | ||
425 | return FALSE; | ||
426 | theBlock* b = m_File->GetCached(bk); | ||
427 | ASSERT(b); | ||
428 | if(m_FB.freeFile<0){ | ||
429 | b->next=-1; | ||
430 | m_FB.freeFile=bk; | ||
431 | }else{ | ||
432 | b->next=m_FB.freeFile; | ||
433 | m_FB.freeFile=bk; | ||
434 | } | ||
435 | m_File->MakeDirty(bk); | ||
436 | m_File->Write1stBlock(&m_FB); | ||
437 | return TRUE; | ||
438 | } | ||
439 | }; | ||
440 | |||
441 | }; | ||
442 | |||
443 | #endif // __DYNAMIDE_H | ||