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                     &sect));
217         }
218         else if (start == _stmc.GetOffset())
219         {
220             sect = _stmc.GetSect();
221         }
222         else
223         {
224             msfChk(pms->GetDir()->GetStart(sid, &sectSidStart));
225             msfChk(pfat->GetSect(sectSidStart, start, &sect));
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, &sectstart));
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, &sectstart));
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, &sectstart));
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                     &sectLast));
599         }
600         else
601         {
602             msfChk(pfatNew->GetSect(sectstart, csectNew - 1, &sectLast));
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