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 §));
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 §));
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