1 //-------------------------------------------------------------------------
2 //
3 //  For conditions of distribution and use, see copyright notice
4 //  in Flashpix.h
5 //
6 //  Copyright (c) 1999 Digital Imaging Group, Inc.
7 //
8 //  Contents: Vector common code.
9 //
10 //  Classes:
11 //
12 //  Functions:
13 //
14 //--------------------------------------------------------------------------
15 
16 #include "msfhead.cxx"
17 
18 
19 #include "h/vect.hxx"
20 
21 
22 
23 //+-------------------------------------------------------------------------
24 //
25 //  Method:     CPagedVector::Init, public
26 //
27 //  Synopsis:   CPagedVector initialization function
28 //
29 //  Arguments:  [ulSize] -- size of vector
30 //
31 //  Algorithm:  Allocate an array of pointer of size ulSize
32 //              For each cell in the array, allocate a CFatSect
33 //
34 //  Notes:
35 //
36 //--------------------------------------------------------------------------
37 
Init(CMStream * pmsParent,ULONG ulSize)38 SCODE CPagedVector::Init(CMStream *pmsParent, ULONG ulSize)
39 {
40     msfDebugOut((DEB_ITRACE,"In CPagedVector::CPagedVector(%lu)\n",ulSize));
41     SCODE sc = S_OK;
42     _pmsParent = pmsParent;
43     _pmpt = _pmsParent->GetPageTable();
44 
45     msfAssert(_pmpt != NULL);
46 
47     USHORT i;
48 
49     //  We don't bother allocating more than necessary here
50     _ulAllocSize = _ulSize = ulSize;
51 
52     if (_ulSize > 0)
53     {
54 
55         msfMem(_amp = GetNewPageArray(ulSize));
56         for (i = 0; i < _ulSize; i++)
57         {
58             _amp[i] = NULL;
59         }
60         msfMem(_avb = GetNewVectBits(ulSize));
61     }
62 
63     msfDebugOut((DEB_ITRACE,"Out CPagedVector::CPagedVector()\n"));
64     return sc;
65 
66 Err:
67     //In the error case, discard whatever vectors we were able to allocate
68     //   and return S_OK.
69     delete [] _amp;
70     _amp = NULL;
71 
72     delete [] _avb;
73     _avb = NULL;
74 
75     return S_OK;
76 
77 }
78 
79 //+-------------------------------------------------------------------------
80 //
81 //  Method:     CPagedVector::~CPagedVector, public
82 //
83 //  Synopsis:   CPagedVector constructor
84 //
85 //  Algorithm:  Delete the pointer array.
86 //
87 //  Notes:
88 //
89 //--------------------------------------------------------------------------
90 
~CPagedVector()91 CPagedVector::~CPagedVector()
92 {
93     delete [] _amp;
94     delete [] _avb;
95 }
96 
97 
98 //+---------------------------------------------------------------------------
99 //
100 //  Member: CPagedVector::Empty, public
101 //
102 //  Synopsis: Discard the storage associated with this vector.
103 //
104 //  Arguments:  None.
105 //
106 //  Returns:  void.
107 //
108 //----------------------------------------------------------------------------
109 
Empty(void)110 void CPagedVector::Empty(void)
111 {
112     if (_pmpt != NULL)
113     {
114         _pmpt->FreePages(this);
115     }
116     delete [] _amp;
117     delete [] _avb;
118     _amp = NULL;
119     _avb = NULL;
120     _pmpt = NULL;
121     _ulAllocSize = _ulSize = 0;
122     _pmsParent = NULL;
123 }
124 
125 //+---------------------------------------------------------------------------
126 //
127 //  Member: CPagedVector::Flush, public
128 //
129 //  Synopsis: Flush the dirty pages for this vector
130 //
131 //  Arguments:  None.
132 //
133 //  Returns:  Appropriate status code
134 //
135 //----------------------------------------------------------------------------
136 
Flush(void)137 SCODE CPagedVector::Flush(void)
138 {
139     SCODE sc;
140     SCODE scRet = S_OK;
141 
142     if (_ulSize > 0)
143     {
144         if (_amp != NULL)
145         {
146             for (USHORT i = 0; i < _ulSize; i++)
147             {
148                 if ((_amp[i] != NULL) && (_amp[i]->IsDirty()))
149                 {
150                     sc = _pmpt->FlushPage(_amp[i]);
151                     if ((FAILED(sc)) && (SUCCEEDED(scRet)))
152                     {
153                         scRet = sc;
154                     }
155                 }
156             }
157         }
158         else
159         {
160             scRet = _pmpt->Flush();
161         }
162     }
163 
164     return scRet;
165 }
166 
167 
168 //+-------------------------------------------------------------------------
169 //
170 //  Method:     CPagedVector::GetTable, public
171 //
172 //  Synopsis:   Return a pointer to a page for the given index
173 //              into the vector.
174 //
175 //  Arguments:  [iTable] -- index into vector
176 //              [ppmp] -- Pointer to return location
177 //
178 //  Returns:    S_OK if call completed OK.
179 //
180 //  Notes:
181 //
182 //--------------------------------------------------------------------------
183 
GetTable(const FSINDEX iTable,DWORD dwFlags,void ** ppmp)184 SCODE CPagedVector::GetTable(
185         const FSINDEX iTable,
186         DWORD dwFlags,
187         void **ppmp)
188 {
189     SCODE sc = S_OK;
190     CMSFPage *pmp;
191 
192     msfAssert((_pmsParent->GetILB() != NULL) &&
193             aMsg("Null ILB found on GetTable - need SetAccess call?"));
194 
195     // docfile is corrupted with an invalid iTable size
196     if (iTable >= _ulSize)
197     {
198   msfErr(Err, STG_E_DOCFILECORRUPT);
199 
200     }
201 
202     if ((_amp == NULL) || (_amp[iTable] == NULL))
203     {
204         if (dwFlags & FB_NEW)
205         {
206             //We know that the page isn't in the page table,
207             //  so we can just get a free page an allocate it
208             //  ourselves.
209 
210             msfChk(_pmpt->GetFreePage(&pmp));
211 
212             pmp->SetVector(this);
213             pmp->SetSid(_sid);
214             pmp->SetOffset(iTable);
215             pmp->SetSect(ENDOFCHAIN);
216 
217             sc = STG_S_NEWPAGE;
218             dwFlags = (dwFlags & ~FB_NEW) | FB_DIRTY;
219         }
220         else
221         {
222             msfChk(_pmpt->GetPage(this, _sid, iTable, &pmp));
223             msfAssert((pmp->GetVector() == this) &&
224                     aMsg("GetPage returned wrong page."));
225         }
226 
227 
228         if (_amp != NULL)
229         {
230             _amp[iTable] = pmp;
231         }
232 
233     }
234     else
235     {
236         pmp = _amp[iTable];
237         msfAssert((pmp->GetVector() == this) &&
238                 aMsg("Cached page has wrong vector pointer"));
239     }
240 
241     pmp->AddRef();
242 
243     if (((dwFlags & FB_DIRTY) && !(pmp->IsDirty())) &&
244         (sc != STG_S_NEWPAGE))
245     {
246         //If we are not a newly created page, and we are being
247         //   dirtied for the first time, make sure that our
248         //   _sect field is correct.
249         //
250         //Newly created pages have to have their sect set manually
251         //  _before_ being released.  This is very important.
252 
253             pmp->SetSect(ENDOFCHAIN);
254 
255             SECT sect;
256             msfChkTo(Err_Rel, _pmsParent->GetESect(
257                     pmp->GetSid(),
258                     pmp->GetOffset(),
259                     &sect));
260 
261             pmp->SetSect(sect);
262     }
263 
264     pmp->SetFlags(pmp->GetFlags() | dwFlags | FB_TOUCHED);
265     msfAssert((pmp->GetVector() == this) &&
266             aMsg("GetTable returned wrong page."));
267     *ppmp = pmp->GetData();
268 
269 Err:
270     return sc;
271 
272 Err_Rel:
273     pmp->Release();
274     return sc;
275 }
276 
277 
278 //+---------------------------------------------------------------------------
279 //
280 //  Member: CPagedVector::SetDirty, public
281 //
282 //  Synopsis: Set the dirty bit on the specified page
283 //
284 //  Arguments:  [iTable] -- Table to set bit on
285 //
286 //  Notes:  This function is always called on a page with an
287 //              open reference.  Therefore, the page is
288 //              guaranteed to be in the page table, and that
289 //              FindPage call should never return an error.
290 //
291 //----------------------------------------------------------------------------
292 
SetDirty(ULONG iTable)293 SCODE CPagedVector::SetDirty(ULONG iTable)
294 {
295     SCODE sc = S_OK;
296     CMSFPage *pmp;
297 
298 
299     if (_amp == NULL)
300     {
301 
302         msfChk(_pmpt->FindPage(this, _sid, iTable, &pmp));
303         msfAssert(sc == STG_S_FOUND);
304         msfAssert(pmp->IsInUse() &&
305                 aMsg("Called SetDirty on page not in use."));
306     }
307     else
308     {
309         msfAssert(_amp != NULL);
310         msfAssert(_amp[iTable] != NULL);
311         pmp = _amp[iTable];
312     }
313 
314     if (!pmp->IsDirty())
315     {
316         //We are not a newly created page, and we are being
317         //   dirtied for the first time, make sure that our
318         //   _sect field is correct.
319         //
320 
321         pmp->AddRef();
322 
323             pmp->SetSect(ENDOFCHAIN);
324 
325             SECT sect;
326             msfChkTo(Err_Rel, _pmsParent->GetESect(
327                     pmp->GetSid(),
328                     pmp->GetOffset(),
329                     &sect));
330 
331             pmp->SetSect(sect);
332 
333         pmp->Release();
334     }
335 
336     pmp->SetDirty();
337 
338  Err:
339     return sc;
340 
341  Err_Rel:
342     pmp->Release();
343     return sc;
344 }
345 
346 
347 //+-------------------------------------------------------------------------
348 //
349 //  Method:     CPagedVector::Resize, public
350 //
351 //  Synopsis:   Resize a CPagedVector
352 //
353 //  Arguments:  [ulSize] -- Size of new vector
354 //
355 //  Algorithm:  Create new pointer array of size ulSize.
356 //              For each entry in old array, copy the pointer over.
357 //
358 //  Notes:
359 //
360 //--------------------------------------------------------------------------
361 
362 #define LARGETHRESHOLD  1024
363 #define VECTORBLOCK     1024    //  Must be power of 2
364 
Resize(FSINDEX ulSize)365 SCODE CPagedVector::Resize(FSINDEX ulSize)
366 {
367     msfDebugOut((DEB_ITRACE,"In CPagedVector::CPagedVector(%lu)\n",ulSize));
368 
369     msfAssert(ulSize >= _ulSize);
370     msfAssert(_ulSize <= _ulAllocSize);
371     msfAssert(((VECTORBLOCK & (VECTORBLOCK - 1)) == 0) &&
372               aMsg("VECTORBLOCK must be power of 2"));
373 
374     msfAssert(!((_amp == NULL) && (_avb != NULL)) &&
375             aMsg("Resize precondition failed."));
376 
377     if (ulSize > _ulAllocSize)
378     {
379         //  We don't have room in the existing vector;  grow it
380         ULONG ulNewAllocSize = ulSize;
381 
382         if (ulNewAllocSize > LARGETHRESHOLD)
383         {
384             //  We're dealing with a large vector;  grow it a VECTORBLOCK
385             //  at a time
386             ulNewAllocSize = (ulNewAllocSize + VECTORBLOCK - 1) &
387                              ~(VECTORBLOCK - 1);
388         }
389 
390         CMSFPage **amp = GetNewPageArray(ulNewAllocSize);
391         CVectBits *avb = GetNewVectBits(ulNewAllocSize);
392 
393         //  Can't fail after this point
394 
395         _ulAllocSize = ulNewAllocSize;
396 
397         //  Copy over the old entries
398 
399 
400         if ((amp != NULL) && (avb != NULL))
401         {
402             if ((_amp != NULL) && (_avb != NULL))
403             {
404                 //  Both allocations succeeded
405                 for (ULONG iamp = 0; iamp < _ulSize; iamp++)
406                 {
407                     amp[iamp] = _amp[iamp];
408                     avb[iamp] = _avb[iamp];
409                 }
410             }
411             else if (_amp != NULL)
412             {
413                 for (ULONG iamp = 0; iamp < _ulSize; iamp++)
414                 {
415                     amp[iamp] = _amp[iamp];
416                 }
417             }
418             else
419             {
420                 for (ULONG iamp = 0; iamp < _ulSize; iamp++)
421                 {
422                     amp[iamp] = NULL;
423                 }
424             }
425         }
426         else
427         {
428             //  At least one of the allocations failed
429             delete [] avb;
430             avb = NULL;
431 
432             delete [] amp;
433             amp = NULL;
434         }
435 
436         //  Delete the old vector and put in the new one (if any).
437         //  In the error case, throw away the vectors we are currently
438         //  holding (since they are of insufficient size) and return S_OK.
439 
440         delete [] _amp;
441         _amp = amp;
442 
443         delete [] _avb;
444         _avb = avb;
445     }
446 
447     if (_amp != NULL)
448     {
449         //  Initialize the new elements in the vector
450 
451         for (ULONG iamp = _ulSize; iamp < ulSize; iamp++)
452             _amp[iamp] = NULL;
453     }
454 
455     _ulSize = ulSize;
456 
457     msfDebugOut((DEB_ITRACE,"Out CPagedVector resize constructor\n"));
458     return S_OK;
459 }
460 
461 
462 
463