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: Stream operations for Mstream project
9 //
10 // Classes: None. (defined in sstream.hxx)
11 //
12 //--------------------------------------------------------------------
13
14 #include "msfhead.cxx"
15
16 #include "h/dirfunc.hxx"
17 #include "h/sstream.hxx"
18 #include <time.h>
19 #include "mread.hxx"
20
21 #define DEB_STREAM (DEB_ITRACE | 0x00020000)
22
23
24 //+--------------------------------------------------------------
25 //
26 // Member: CDirectStream::CDirectStream, public
27 //
28 // Synopsis: Empty object constructor
29 //
30 // Arguments: [dl] - LUID
31 //
32 //---------------------------------------------------------------
33
CDirectStream(DFLUID dl)34 CDirectStream::CDirectStream(DFLUID dl)
35 : PEntry(dl)
36 {
37 _cReferences = 0;
38 }
39
40
41 //+--------------------------------------------------------------
42 //
43 // Member: CDirectStream::InitSystem, public
44 //
45 // Synopsis: Initializes special system streams like the ministream
46 //
47 // Arguments: [pms] - Multistream
48 // [sid] - SID
49 // [cbSize] - size
50 //
51 //---------------------------------------------------------------
52
InitSystem(CMStream * pms,SID sid,ULONG cbSize)53 void CDirectStream::InitSystem(CMStream *pms,
54 SID sid,
55 ULONG cbSize)
56 {
57 _stmh.Init(pms, sid);
58 _ulSize = _ulOldSize = cbSize;
59 AddRef();
60 }
61
62
63 //+-------------------------------------------------------------------------
64 //
65 // Method: CDirectStream::Init, public
66 //
67 // Synopsis: CDirectStream constructor
68 //
69 // Arguments: [pstgh] - Parent
70 // [pdfn] - Name of entry
71 // [fCreate] - Create or get
72 //
73 // Returns: Appropriate status code
74 //
75 //--------------------------------------------------------------------------
76
Init(CStgHandle * pstgh,CDfName const * pdfn,BOOL const fCreate)77 SCODE CDirectStream::Init(
78 CStgHandle *pstgh,
79 CDfName const *pdfn,
80 BOOL const fCreate)
81 {
82 SCODE sc;
83
84 if (fCreate)
85 sc = pstgh->CreateEntry(pdfn, STGTY_STREAM, &_stmh);
86 else
87 sc = pstgh->GetEntry(pdfn, STGTY_STREAM, &_stmh);
88 if (SUCCEEDED(sc))
89 {
90 sc = _stmh.GetSize(&_ulSize);
91 _ulOldSize = _ulSize;
92 if (SUCCEEDED(sc))
93 AddRef();
94 }
95 return sc;
96 }
97
98
99 //+-------------------------------------------------------------------------
100 //
101 // Method: CDirectStream::~CDirectStream, public
102 //
103 // Synopsis: CDirectStream destructor
104 //
105 // Notes:
106 //
107 //--------------------------------------------------------------------------
108
~CDirectStream()109 CDirectStream::~CDirectStream()
110 {
111 msfAssert(_cReferences == 0);
112 }
113
114 //+-------------------------------------------------------------------------
115 //
116 // Member: CDirectStream::ReadAt, public
117 //
118 // Synposis: Reads binary data from a linear single stream
119 //
120 // Arguments: [ulOffset] -- Position to be read from
121 //
122 // [pBuffer] -- Pointer to the area into which the data
123 // will be read.
124 // [ulCount] -- Indicates the number of bytes to be read
125 // [pulRetval] -- Area into which return value will be stored
126 //
127 // Returns: Error Code of parent MStream call
128 //
129 // Algorithm: Calculate start and end sectors and offsets, then
130 // pass call up to parent MStream.
131 //
132 // Notes:
133 //
134 //---------------------------------------------------------------------------
135
136
ReadAt(ULONG ulOffset,VOID HUGEP * pBuffer,ULONG ulCount,ULONG STACKBASED * pulRetval)137 SCODE CDirectStream::ReadAt(
138 ULONG ulOffset,
139 VOID HUGEP *pBuffer,
140 ULONG ulCount,
141 ULONG STACKBASED *pulRetval)
142 {
143 msfDebugOut((DEB_TRACE,"In CDirectStream::ReadAt(%lu,%p,%lu)\n",
144 ulOffset,pBuffer,ulCount));
145
146 SCODE sc = S_OK;
147
148 CMStream *pms = _stmh.GetMS();
149
150
151 // Check for offset beyond stream size and zero count
152
153 if ((ulOffset >= _ulSize) || (0 == ulCount))
154 {
155 *pulRetval = 0;
156 return S_OK;
157 }
158
159 if (ulOffset + ulCount > _ulSize)
160 {
161 msfDebugOut((DEB_ITRACE,"Truncating Read: ulOffset = %lu, ulCount = %lu, _ulSize = %lu\n",
162 ulOffset,ulCount,_ulSize));
163 ulCount = _ulSize - ulOffset;
164 }
165
166
167 // Stream is stored in ministream if size < MINISTREAMSIZE
168 // and this is not a scratch stream.
169
170
171 SID sid = _stmh.GetSid();
172 CFat *pfat = pms->GetFat();
173 USHORT cbSector = pms->GetSectorSize();
174 USHORT uShift = pms->GetSectorShift();
175 USHORT uMask = pms->GetSectorMask();
176
177
178
179 if ((_ulSize < MINISTREAMSIZE) &&
180 (sid != SIDMINISTREAM))
181 {
182 msfAssert(sid <= MAXREGSID);
183
184 // This stream is stored in the ministream
185
186 cbSector = MINISECTORSIZE;
187 uShift = MINISECTORSHIFT;
188 uMask = (USHORT) (cbSector - 1);
189 pfat = pms->GetMiniFat();
190 }
191
192 SECT start = (SECT)(ulOffset >> uShift);
193 OFFSET oStart = (OFFSET)(ulOffset & uMask);
194
195 SECT end = (SECT)((ulOffset + ulCount - 1) >> uShift);
196 OFFSET oEnd = (OFFSET)((ulOffset + ulCount - 1) & uMask);
197
198 ULONG total = 0;
199
200 ULONG cSect = end - start + 1;
201
202 SECT sectSidStart;
203
204 USHORT offset;
205 offset = oStart;
206
207 while (TRUE)
208 {
209 SECT sect;
210
211 if (start > _stmc.GetOffset())
212 {
213 msfChk(pfat->GetSect(
214 _stmc.GetSect(),
215 start - _stmc.GetOffset(),
216 §));
217 }
218 else if (start == _stmc.GetOffset())
219 {
220 sect = _stmc.GetSect();
221 }
222 else
223 {
224 msfChk(pms->GetDir()->GetStart(sid, §SidStart));
225 msfChk(pfat->GetSect(sectSidStart, start, §));
226 }
227
228 SSegment segtab[CSEG + 1];
229
230 msfChk(pfat->Contig(
231 (SSegment STACKBASED *) segtab,
232 sect,
233 cSect));
234
235 USHORT oend = (USHORT) (cbSector - 1);
236 for (USHORT iseg = 0; iseg < CSEG;)
237 {
238 msfDebugOut((DEB_ITRACE,"Segment: (%lu,%lu)\n",segtab[iseg].sectStart,segtab[iseg].cSect));
239 SECT sectStart = segtab[iseg].sectStart;
240 ULONG i = segtab[iseg].cSect;
241 cSect -= i;
242 start += i;
243
244 iseg++;
245 if (segtab[iseg].sectStart == ENDOFCHAIN)
246 oend = oEnd;
247
248 ULONG ulSize = ((i - 1) << uShift) - offset + oend + 1;
249
250 ULONG bytecount;
251 SCODE sc;
252
253 if (pms->GetMiniFat() == pfat)
254 {
255 sc = pms->GetMiniStream()->CDirectStream::ReadAt(
256 (sectStart << uShift) + offset,
257 pBuffer, ulSize,
258 (ULONG STACKBASED *)&bytecount);
259 }
260 else
261 {
262 ULARGE_INTEGER ulOffset;
263 ULISet32(ulOffset, ConvertSectOffset(sectStart,offset,uShift));
264 sc = DfGetScode(pms->GetILB()->ReadAt(ulOffset,
265 (BYTE *)pBuffer, ulSize,
266 &bytecount));
267 }
268
269 total += bytecount;
270 if ((0 == cSect) || (FAILED(sc)))
271 {
272 _stmc.SetCache(start - 1, sectStart + i - 1);
273 *pulRetval = total;
274 msfDebugOut((DEB_TRACE,
275 "Leaving CDirectStream::ReadAt()=>%lu, ret is %lu\n",
276 sc,*pulRetval));
277 return sc;
278 }
279
280 pBuffer = (BYTE HUGEP *)pBuffer + bytecount;
281 offset = 0;
282 }
283 }
284
285 msfDebugOut((DEB_ERROR,"In CDirectStream::ReadAt - reached end of function\n"));
286 Err:
287 return sc;
288 }
289
290 //+-------------------------------------------------------------------------
291 //
292 // Member: CDirectStream::Write, public
293 //
294 // Synposis: Writes binary data from a linear single stream
295 //
296 // Effects: Modifies _ulSeekPos. May cause modification in parent
297 // MStream.
298 //
299 // Arguments: [pBuffer] -- Pointer to the area from which the data
300 // will be written.
301 // [ulCount] -- Indicates the number of bytes to be written
302 // [pulRetval] -- Pointer to area in which number of bytes
303 // will be returned
304 //
305 // Returns: Error code of MStream call.
306 //
307 // Algorithm: Calculate sector and offset for beginning and end of
308 // write, then pass call up to MStream.
309 //
310 //
311 // Notes:
312 //
313 //---------------------------------------------------------------------------
314
315
WriteAt(ULONG ulOffset,VOID const HUGEP * pBuffer,ULONG ulCount,ULONG STACKBASED * pulRetval)316 SCODE CDirectStream::WriteAt(
317 ULONG ulOffset,
318 VOID const HUGEP *pBuffer,
319 ULONG ulCount,
320 ULONG STACKBASED *pulRetval)
321 {
322 msfDebugOut((DEB_TRACE,"In CDirectStream::WriteAt(%lu,%p,%lu)\n",ulOffset,pBuffer,ulCount));
323
324 *pulRetval = 0;
325
326 if (0 == ulCount)
327 return S_OK;
328
329 SCODE sc;
330
331 if (ulOffset + ulCount > _ulSize)
332 {
333 if (_ulSize > MINISTREAMSIZE)
334 {
335 }
336 else
337 {
338 msfChk(SetSize(ulOffset + ulCount));
339 }
340 }
341
342 CMStream *pms;
343 pms = _stmh.GetMS();
344 msfAssert(pms != NULL);
345
346 // This should be an inline call to MWrite
347
348 msfChk(pms->MWrite(
349 _stmh.GetSid(),
350 (_ulSize < MINISTREAMSIZE),
351 ulOffset,
352 pBuffer,
353 ulCount,
354 &_stmc,
355 pulRetval));
356
357 msfAssert(*pulRetval == ulCount);
358
359 msfDebugOut((DEB_TRACE,"Leaving CDirectStream::WriteAt()==>%lu, ret is %lu\n",sc,*pulRetval));
360
361 Err:
362 if (ulOffset + *pulRetval > _ulSize)
363 {
364 SCODE scSet;
365
366 _ulSize = ulOffset + *pulRetval;
367 scSet = pms->GetDir()->SetSize(_stmh.GetSid(), _ulSize);
368 if (SUCCEEDED(sc) && FAILED(scSet))
369 {
370 sc = scSet;
371 }
372 }
373
374 return sc;
375 }
376
377
378 //+-------------------------------------------------------------------------
379 //
380 // Member: CDirectStream::SetSize, public
381 //
382 // Synposis: Set the size of a linear stream
383 //
384 // Effects: Modifies _ulSize. May cause change in parent MStream.
385 //
386 // Arguments: [ulNewSize] -- New size for stream
387 //
388 // Returns: Error code returned by MStream call.
389 //
390 // Algorithm: Pass call up to parent.
391 //
392 // Notes: When changing the size of a stream, we need to be concerned
393 // with the cases where each stream is either zero length,
394 // stored in the ministream, or stored in a regular stream. The following
395 // grid shows the actions that we must perform in each case:
396 //
397 // New Sector Count (Cn)
398 //
399 // 0 S L
400 // O ------------------------------------------------
401 // l | same size | allocate Cn | allocate Cn
402 // d 0 | (fast out) | small sectors | large sectors
403 // ------------------------------------------------
404 // S | small | Co > Cn: | cbCopy = cbOld
405 // e S | setchain(Cn) | small | large allocate Cn
406 // c | | setchain(Cn)| copy bytes
407 // t | | Cn > Co: | small setchain(0)
408 // o | | extend small | copy data
409 // r ------------------------------------------------
410 // L | large | cbCopy = cbNew| Co > Cn:
411 // C | setchain(Cn) | small | large setchain(Cn)
412 // o | | allocate Cn | Cn > Co:
413 // u | | copy bytes | extend large
414 // n | | large |
415 // t | | setchain(0) |
416 // | | copy data |
417 // (Co) ------------------------------------------------
418 //
419 // where S indicates small sectors, L indicates large sectors, and Cx
420 // represents count of sectors. For example, the middle box represents
421 // doing a setsize on a stream which is currently stored in a small
422 // stream in Co small sectors and which will end up in a large stream
423 // with Cn sectors.
424 //
425 //---------------------------------------------------------------------------
426
427
SetSize(ULONG cbNewSize)428 SCODE CDirectStream::SetSize(ULONG cbNewSize)
429 {
430 msfDebugOut((DEB_TRACE,"In CDirectStream::SetSize(%lu)\n",cbNewSize));
431
432 SCODE sc = S_OK;
433 BYTE *pBuf = NULL;
434 SID sid = _stmh.GetSid();
435 CMStream *pms = _stmh.GetMS();
436 msfAssert(sid <= MAXREGSID);
437 CDirectory *pdir = pms->GetDir();
438 SECT sectOldStart;
439
440 if (_ulSize == cbNewSize)
441 {
442 return S_OK;
443 }
444
445 USHORT cbpsOld = pms->GetSectorSize();
446 // Count of Bytes Per Sector
447 USHORT cbpsNew = cbpsOld;
448 CFat *pfatOld = pms->GetFat();
449 CFat *pfatNew = pfatOld;
450
451 if (SIDMINISTREAM != sid)
452 {
453
454 if (cbNewSize < MINISTREAMSIZE)
455 {
456 cbpsNew = MINISECTORSIZE;
457 pfatNew = pms->GetMiniFat();
458 }
459
460 if (_ulSize < MINISTREAMSIZE)
461 {
462 cbpsOld = MINISECTORSIZE;
463 pfatOld = pms->GetMiniFat();
464 }
465 }
466
467 ULONG csectOld = (ULONG)(_ulSize + cbpsOld - 1) / (ULONG) cbpsOld;
468 ULONG csectNew = (ULONG)(cbNewSize + cbpsNew - 1) / (ULONG) cbpsNew;
469
470 msfAssert(sid <= MAXREGSID);
471 SECT sectstart;
472 msfChk(pdir->GetStart(sid, §start));
473
474 msfDebugOut((DEB_ITRACE,"pdbOld size is %lu\n\tSid is %lu\n\tStart is %lu\n",
475 _ulSize,sid,sectstart));
476 msfDebugOut((DEB_ITRACE,"CMStream::SetSize() needs %lu %u byte sectors\n",
477 csectNew, cbpsNew));
478 msfDebugOut((DEB_ITRACE,"SetSize() currently has %lu %u byte sectors\n",
479 csectOld, cbpsOld));
480
481 USHORT cbCopy;
482 cbCopy = 0;
483 if (cbpsOld != cbpsNew)
484 {
485 // Sector sizes are different, so we'll copy the data
486 msfAssert((cbNewSize > _ulSize ? _ulSize : cbNewSize) < 0x10000);
487 cbCopy =(USHORT)(cbNewSize > _ulSize ? _ulSize : cbNewSize);
488 }
489
490
491 if (cbCopy > 0)
492 {
493 msfDebugOut((DEB_ITRACE,"Copying between fat and minifat\n"));
494 GetSafeBuffer(cbCopy, cbCopy, &pBuf, &cbCopy);
495 msfAssert((pBuf != NULL) && aMsg("Couldn't get scratch buffer"));
496
497 ULONG ulRetVal;
498 sc = ReadAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal);
499 if ((FAILED(sc)) ||
500 ((ulRetVal != cbCopy) ? (sc = STG_E_UNKNOWN) : 0))
501 {
502 msfErr(Err, sc);
503 }
504
505 //The cache is no longer valid, so empty it.
506 _stmc.SetCache(MAX_ULONG, ENDOFCHAIN);
507
508 //Save start sector so we can free it later.
509 sectOldStart = sectstart;
510
511 msfChk(pfatNew->Allocate(csectNew, §start));
512 }
513 else
514 {
515 SECT dummy;
516
517 if ((csectOld > csectNew))
518 {
519 msfChk(pfatOld->SetChainLength(sectstart, csectNew));
520 if (0 == csectNew)
521 {
522 sectstart = ENDOFCHAIN;
523 }
524
525 //If this turns out to be a common case, we can
526 // sometimes keep the cache valid here.
527 _stmc.SetCache(MAX_ULONG, ENDOFCHAIN);
528 }
529 else if (0 == csectOld)
530 {
531 msfAssert(_stmc.GetOffset() == MAX_ULONG);
532 msfChk(pfatNew->Allocate(csectNew, §start));
533 }
534 else if (csectNew > csectOld)
535 {
536 ULONG start = csectNew - 1;
537
538 if (start > _stmc.GetOffset())
539 {
540 msfChk(pfatNew->GetESect(
541 _stmc.GetSect(),
542 start - _stmc.GetOffset(),
543 &dummy));
544 }
545 else if (start != _stmc.GetOffset())
546 {
547 msfChk(pfatNew->GetESect(sectstart, start, &dummy));
548 }
549 }
550 }
551
552
553 // Resize the ministream, if necessary
554 if (((MINISECTORSIZE == cbpsOld) && (csectOld > 0)) ||
555 ((MINISECTORSIZE == cbpsNew) && (csectNew > 0)))
556 {
557 msfChk(pms->SetMiniSize());
558 }
559
560 msfChk(pms->SetSize());
561
562 //If we fail on either of these operations and cbCopy != 0,
563 // we will have data loss. Ick.
564 msfChk(pdir->SetStart(sid, sectstart));
565
566 //If we fail here, we're screwed.
567 msfChk(pdir->SetSize(sid, cbNewSize));
568
569 _ulSize = cbNewSize;
570
571 if (cbCopy > 0)
572 {
573 // now copy the data
574 ULONG ulRetVal;
575
576 msfAssert(cbCopy <= _ulSize);
577 msfChk(WriteAt(0, pBuf, cbCopy, (ULONG STACKBASED *)&ulRetVal));
578
579 if (ulRetVal != cbCopy)
580 {
581 msfErr(Err, STG_E_UNKNOWN);
582 }
583
584 msfChk(pfatOld->SetChainLength(sectOldStart, 0));
585 msfChk(pms->SetMiniSize());
586 msfChk(pms->SetSize());
587 }
588
589 if (((csectNew > csectOld) || (cbCopy > 0)) &&
590 ((cbNewSize & (cbpsNew - 1)) != 0))
591 {
592 SECT sectLast;
593 if (csectNew - 1 > _stmc.GetOffset())
594 {
595 msfChk(pfatNew->GetSect(
596 _stmc.GetSect(),
597 (csectNew - 1) - _stmc.GetOffset(),
598 §Last));
599 }
600 else
601 {
602 msfChk(pfatNew->GetSect(sectstart, csectNew - 1, §Last));
603 }
604
605 msfVerify(SUCCEEDED(pms->SecureSect(
606 sectLast,
607 cbNewSize,
608 (cbNewSize < MINISTREAMSIZE) && (sid != SIDMINISTREAM))));
609 }
610 Err:
611 FreeBuffer(pBuf);
612 return sc;
613 }
614
615
616
617 //+---------------------------------------------------------------------------
618 //
619 // Member: CDirectStream::Release, public
620 //
621 // Synopsis: Decrements the ref count and frees if necessary
622 //
623 //----------------------------------------------------------------------------
624
625
Release()626 void CDirectStream::Release()
627 {
628 msfDebugOut((DEB_TRACE,"In CDirectStream::Release()\n"));
629 msfAssert(_cReferences > 0);
630
631 AtomicDec(&_cReferences);
632 if (_cReferences == 0)
633 delete this;
634 msfDebugOut((DEB_TRACE,"Out CDirectStream::Release()\n"));
635 }
636
637 //+--------------------------------------------------------------
638 //
639 // Member: CDirectStream::AddRef, public
640 //
641 // Synopsis: Increments the ref count
642 //
643 //---------------------------------------------------------------
644
645
AddRef(void)646 void CDirectStream::AddRef(void)
647 {
648 msfDebugOut((DEB_ITRACE, "In CDirectStream::AddRef()\n"));
649 AtomicInc(&_cReferences);
650 msfDebugOut((DEB_ITRACE, "Out CDirectStream::AddRef, %lu\n",
651 _cReferences));
652 }
653
654 //+---------------------------------------------------------------------------
655 //
656 // Member: CDirectStream::GetSize, public
657 //
658 // Synopsis: Gets the size of the stream
659 //
660 // Arguments: [pulSize] - Size return
661 //
662 // Modifies: [pulSize]
663 //
664 //----------------------------------------------------------------------------
665
GetSize(ULONG * pulSize)666 void CDirectStream::GetSize(ULONG *pulSize)
667 {
668 *pulSize = _ulSize;
669 }
670
671 //+--------------------------------------------------------------
672 //
673 // Member: CDirectStream::GetTime, public
674 //
675 // Synopsis: Gets a time
676 //
677 // Arguments: [wt] - Which time
678 // [ptm] - Time return
679 //
680 // Returns: Appropriate status code
681 //
682 // Modifies: [ptm]
683 //
684 //---------------------------------------------------------------
685
GetTime(WHICHTIME wt,TIME_T * ptm)686 SCODE CDirectStream::GetTime(WHICHTIME wt, TIME_T *ptm)
687 {
688 return _stmh.GetTime(wt, ptm);
689 }
690
691 //+--------------------------------------------------------------
692 //
693 // Member: CDirectStream::SetTime, public
694 //
695 // Synopsis: Sets a time
696 //
697 // Arguments: [wt] - Which time
698 // [tm] - New time
699 //
700 // Returns: Appropriate status code
701 //
702 //---------------------------------------------------------------
703
SetTime(WHICHTIME wt,TIME_T tm)704 SCODE CDirectStream::SetTime(WHICHTIME wt, TIME_T tm)
705 {
706 return _stmh.SetTime(wt, tm);
707 }
708
709
710