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: Exposed DocFile implementation
9 //
10 // Notes:
11 // The CExposedDocFile class is the implementation
12 // of IStorage. It implements IPropertySetStorage
13 // by inheriting from CPropertySetStorage. CPropertySetStorage
14 // implements all the functionality of IPropertySetStorage.
15 //
16 // Note that this interface is solely UNICODE, the ASCII layer
17 // support which is present if _UNICODE is not defined, provides
18 // the overloaded functions that handles the ASCII to Unicode
19 // conversion.
20 //
21 //---------------------------------------------------------------------------
22
23 // Initialize all the GUID's in ref.hxx
24 #ifdef INITGUID
25 #error "Something is Wrong: INIT_GUID should not be defined yet"
26 #else
27 #define INITGUID
28 #include "h/ref.hxx"
29 #endif
30
31 // enable memory leak detection if neccessary
32 #include "h/dbg.hxx"
33
34 #include "exphead.cxx"
35
36 #include "expdf.hxx"
37 #include "expst.hxx"
38 #include "expiter.hxx"
39 #include "logfile.hxx"
40 #include "h/rexpdf.hxx"
41 #include "h/docfilep.hxx"
42
43 // Check for proper single-instance flags
44 #define NOT_SINGLE(md) (((md) & STGM_DENY) != STGM_SHARE_EXCLUSIVE)
45
46 #define EnforceSingle(mode) (NOT_SINGLE(mode) ? STG_E_INVALIDFUNCTION : S_OK)
47
48 //+--------------------------------------------------------------
49 //
50 // Member: CExposedDocFile::CExposedDocFile, public
51 //
52 // Synopsis: Constructor
53 //
54 // Arguments: [pdf] - Public DocFile
55 // [pdfb] - DocFile basis
56 // [ppc] - Context
57 // [fOwnContext] - Whether this object owns the context
58 //
59 //---------------------------------------------------------------
60
61
CExposedDocFile(CExposedDocFile * pdfParent,CDocFile * pdf,DFLAGS const df,DFLUID luid,ILockBytes * pilbBase,CDfName const * pdfn,CMStream * pmsBase,CDFBasis * pdfb)62 CExposedDocFile::CExposedDocFile(CExposedDocFile *pdfParent,
63 CDocFile *pdf,
64 DFLAGS const df,
65 DFLUID luid,
66 ILockBytes *pilbBase,
67 CDfName const *pdfn,
68 CMStream* pmsBase,
69 CDFBasis *pdfb)
70 #ifdef NEWPROPS
71 #ifdef _MSC_VER
72 #pragma warning(disable: 4355)
73 #endif // _MSC_VER
74 : CPropertySetStorage(this)
75 #ifdef _MSC_VER
76 #pragma warning(default: 4355)
77 #endif // _MSC_VER
78 #endif // NEWPROPS
79 {
80 olDebugOut((DEB_ITRACE, "In CExposedDocFile::CExposedDocFile(%p)\n",
81 pdf));
82 _pdfb = pdfb;
83 _pdfb->AddRef();
84 _pdf = pdf;
85 _df = df;
86 _luid = luid;
87 _pdfParent = pdfParent;
88 // note: we don't addref here 'cos it is only done in the root
89 _pilbBase = pilbBase;
90 _pmsBase = pmsBase;
91 if (pdfn) _dfn.Set(pdfn->GetLength(), pdfn->GetBuffer());
92 else _dfn.Set((WORD)0, (BYTE*)NULL);
93 if (!IsRoot())
94 _pdfParent->AddChild(this);
95 _fDirty = FALSE;
96 _cReferences = 1;
97 _ulAccessLockBase = 0;
98 _sig = CEXPOSEDDOCFILE_SIG;
99 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::CExposedDocFile\n"));
100
101 }
102
103 //+--------------------------------------------------------------
104 //
105 // Member: CExposedDocFile::~CExposedDocFile, public
106 //
107 // Synopsis: Destructor
108 //
109 //---------------------------------------------------------------
110
~CExposedDocFile(void)111 CExposedDocFile::~CExposedDocFile(void)
112 {
113 olDebugOut((DEB_TRACE, "In CExposedDocFile::~CExposedDocFile\n"));
114 olAssert(_cReferences == 0);
115 if (_pdfb) _pdfb->Release();
116 _sig = CEXPOSEDDOCFILE_SIGDEL;
117 if (SUCCEEDED(CheckReverted()))
118 {
119 if (IsRoot()) {
120 olDebugOut((DEB_TRACE, "Destr called for root\n"));
121 olAssert(_pilbBase==NULL);
122 }
123 else {
124 _pdfParent->ReleaseChild(this);
125 }
126 _cilChildren.DeleteByName(NULL);
127 if (_pdf) _pdf->Release();
128 }
129 olDebugOut((DEB_TRACE, "Out CExposedDocFile::~CExposedDocFile\n"));
130 }
131
132 //+--------------------------------------------------------------
133 //
134 // Member: CExposedDocFile::Release, public
135 //
136 // Synopsis: Releases resources for a CExposedDocFile
137 //
138 // Returns: Appropriate status code
139 //
140 //---------------------------------------------------------------
141
STDMETHODIMP_(ULONG)142 STDMETHODIMP_(ULONG) CExposedDocFile::Release(void)
143 {
144 LONG lRet;
145
146 olLog(("%p::In CExposedDocFile::Release()\n", this));
147 olDebugOut((DEB_ITRACE, "In CExposedDocFile::Release()\n"));
148
149 if (FAILED(Validate())) return 0;
150 assert(_cReferences > 0);
151 lRet = AtomicDec(&_cReferences);
152 if (_pdf && !P_TRANSACTED(_df) && SUCCEEDED(CheckReverted()))
153 {
154 TIME_T tm;
155 olVerSucc(CoFileTimeNow(&tm));
156 olVerSucc(_pdf->SetTime(WT_ACCESS, tm));
157 #ifdef NEWPROPS
158 olVerSucc(FlushBufferedData());
159 #endif
160 if (IsDirty())
161 {
162 olVerSucc(CoFileTimeNow(&tm));
163 olVerSucc(_pdf->SetTime(WT_MODIFICATION, tm));
164 if (!IsRoot())
165 _pdfParent->SetDirty();
166 olAssert(P_WRITE(_df) &&
167 aMsg("Dirty & Direct but no write access"));
168 SetClean();
169 }
170 if (IsRoot() && P_WRITE(_df))
171 {
172 #if DBG == 1
173 SCODE sc =
174 #endif
175 _pmsBase->Flush(0);
176 #if DBG == 1
177 if (FAILED(sc))
178 {
179 olDebugOut((DEB_ERROR,
180 "ILockBytes::Flush() failed in release path "
181 "with error %lx\n", sc));
182 }
183 #endif
184 }
185 }
186 if (lRet == 0)
187 {
188 delete this;
189 }
190 else if (lRet < 0)
191 lRet = 0;
192
193 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::Release()\n"));
194 olLog(("%p::Out CExposedDocFile::Release(). ret == %lu\n", this, lRet));
195 FreeLogFile();
196 return (ULONG)lRet;
197 }
198
199 //+--------------------------------------------------------------
200 //
201 // Member: CExposedDocFile::CheckCopyTo, private
202 //
203 // Synopsis: Checks for CopyTo legality
204 //
205 // Returns: Appropriate status code
206 //
207 //---------------------------------------------------------------
208
CheckCopyTo(void)209 inline SCODE CExposedDocFile::CheckCopyTo(void)
210 {
211 // it is an error to copy a parent to child
212 return _pdfb->GetCopyBase() != NULL &&
213 IsAtOrAbove(_pdfb->GetCopyBase()) ? STG_E_ACCESSDENIED : S_OK;
214 }
215
216 //+--------------------------------------------------------------
217 //
218 // Member: CExposedDocFile::ConvertInternalStream, private
219 //
220 // Synopsis: Converts an internal stream to a storage
221 //
222 // Arguments: [pwcsName] - Name
223 // [pdfExp] - Destination docfile
224 //
225 // Returns: Appropriate status code
226 //
227 //---------------------------------------------------------------
228
229
230 static WCHAR const wcsIllegalName[] = {'\\','\0'};
231 extern WCHAR const wcsContents[9];
232
ConvertInternalStream(CExposedDocFile * pdfExp)233 SCODE CExposedDocFile::ConvertInternalStream(CExposedDocFile *pdfExp)
234 {
235 CExposedStream *pstFrom=NULL, *pstTo=NULL;
236 SCODE sc=S_OK;
237 CDfName const dfnIllegal(wcsIllegalName);
238 CDfName const dfnContents(wcsContents);
239
240 olDebugOut((DEB_ITRACE, "In CExposedDocFile::ConvertInternalStream(%p)\n",
241 pdfExp));
242
243 olChk(GetExposedStream(&dfnIllegal, DF_READWRITE | DF_DENYALL,
244 &pstFrom));
245 olChkTo(EH_pstFrom,
246 pdfExp->CreateExposedStream(&dfnContents, DF_WRITE | DF_DENYALL,
247 &pstTo));
248 olChkTo(EH_pstTo, CopyStreamToStream(pstFrom->GetDirectStream(),
249 pstTo->GetDirectStream()));
250 olChkTo(EH_pstTo, DestroyEntry(&dfnIllegal, FALSE));
251
252 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::ConvertInternalStream\n"));
253 // Fall through
254 EH_pstTo:
255 pstTo->Release();
256 EH_pstFrom:
257 pstFrom->Release();
258 EH_Err:
259 return sc;
260 }
261
262 //+---------------------------------------------------------------------------
263 //
264 // Member: CExposedDocFile::CreateEntry, private
265 //
266 // Synopsis: Creates elements, used in CreateStream, CreateStorage and
267 // for properties
268 //
269 // Arguments: [pwcsName] - Name
270 // [dwType] - Entry type
271 // [grfMode] - Access mode
272 // [ppv] - Object return
273 //
274 // Returns: Appropriate status code
275 //
276 // Modifies: [ppv]
277 //
278 //----------------------------------------------------------------------------
279
CreateEntry(WCHAR const * pwcsName,DWORD dwType,DWORD grfMode,void ** ppv)280 SCODE CExposedDocFile::CreateEntry(WCHAR const *pwcsName,
281 DWORD dwType,
282 DWORD grfMode,
283 void **ppv)
284 {
285 SCODE sc;
286 SEntryBuffer eb;
287 CDfName dfn;
288 BOOL fRenamed = FALSE;
289 CExposedStream *pstExp;
290 CExposedDocFile *pdfExp;
291
292 olDebugOut((DEB_ITRACE, "In CExposedDocFile::CreateEntry:%p("
293 "%ws, %lX, %lX, %p)\n",
294 this, pwcsName, dwType, grfMode, ppv));
295 olChk(EnforceSingle(grfMode));
296 olChk(CheckReverted());
297 dfn.Set(pwcsName);
298
299 if (grfMode & (STGM_CREATE | STGM_CONVERT))
300 {
301 if (FAILED(sc = _pdf->IsEntry(&dfn, &eb)))
302 {
303 if (sc != STG_E_FILENOTFOUND)
304 olErr(EH_Err, sc);
305 }
306 else if (eb.dwType == dwType && (grfMode & STGM_CREATE))
307 olChk(DestroyEntry(&dfn, FALSE));
308 else if (eb.dwType == STGTY_STREAM && (grfMode & STGM_CONVERT) &&
309 dwType == STGTY_STORAGE)
310 {
311 CDfName const dfnIllegal(wcsIllegalName);
312 olChk(RenameEntry(&dfn, &dfnIllegal));
313 fRenamed = TRUE;
314 }
315 else
316 olErr(EH_Err, STG_E_FILEALREADYEXISTS);
317 }
318
319 if (REAL_STGTY(dwType) == STGTY_STREAM)
320 {
321 olChk(CreateExposedStream(&dfn, ModeToDFlags(grfMode), &pstExp));
322 *ppv = pstExp;
323 }
324 else
325 {
326 olAssert(REAL_STGTY(dwType) == STGTY_STORAGE);
327 olChk(CreateExposedDocFile(&dfn, ModeToDFlags(grfMode), &pdfExp));
328 // If we've renamed the original stream for conversion, convert
329 if (fRenamed)
330 {
331 olChkTo(EH_pdfExpInit, ConvertInternalStream(pdfExp));
332 sc = STG_S_CONVERTED;
333 }
334 *ppv = pdfExp;
335 }
336 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::CreateEntry\n"));
337 return sc;
338
339 EH_pdfExpInit:
340 pdfExp->Release();
341 olVerSucc(DestroyEntry(&dfn, TRUE));
342 EH_Err:
343 return sc;
344 }
345
346 //+---------------------------------------------------------------------------
347 //
348 // Member: CExposedDocFile::OpenEntry, private
349 //
350 // Synopsis: Opens elements, used in OpenStream, OpenStorage and
351 // for properties
352 //
353 // Arguments: [pwcsName] - Name
354 // [dwType] - Entry type
355 // [grfMode] - Access mode
356 // [ppv] - Object return
357 //
358 // Returns: Appropriate status code
359 //
360 // Modifies: [ppv]
361 //
362 //----------------------------------------------------------------------------
363
364
OpenEntry(WCHAR const * pwcsName,DWORD dwType,DWORD grfMode,void ** ppv)365 SCODE CExposedDocFile::OpenEntry(WCHAR const *pwcsName,
366 DWORD dwType,
367 DWORD grfMode,
368 void **ppv)
369 {
370 CDfName dfn;
371 SCODE sc;
372 CExposedDocFile *pdfExp;
373 CExposedStream *pstExp;
374
375 olDebugOut((DEB_ITRACE, "In CExposedDocFile::OpenEntry:%p("
376 "%ws, %lX, %lX, %p)\n", this, pwcsName, dwType, grfMode, ppv));
377 olChk(EnforceSingle(grfMode));
378 dfn.Set(pwcsName);
379
380
381 if (REAL_STGTY(dwType) == STGTY_STREAM)
382 {
383 olChk(GetExposedStream(&dfn, ModeToDFlags(grfMode), &pstExp));
384 *ppv = pstExp;
385 }
386 else
387 {
388 olAssert(REAL_STGTY(dwType) == STGTY_STORAGE);
389 olChk(GetExposedDocFile(&dfn, ModeToDFlags(grfMode), &pdfExp));
390 *ppv = pdfExp;
391 }
392 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::OpenEntry\n"));
393 return S_OK;
394
395 EH_Err:
396 return sc;
397 }
398
399 //+--------------------------------------------------------------
400 //
401 // Member: CExposedDocFile::CreateStream, public
402 //
403 // Synopsis: Creates a stream
404 //
405 // Arguments: [pwcsName] - Name
406 // [grfMode] - Permissions
407 // [reserved1]
408 // [reserved2]
409 // [ppstm] - Stream return
410 //
411 // Returns: Appropriate status code
412 //
413 // Modifies: [ppstm]
414 //
415 //---------------------------------------------------------------
416
417
CreateStream(WCHAR const * pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2,IStream ** ppstm)418 TSTDMETHODIMP CExposedDocFile::CreateStream(WCHAR const *pwcsName,
419 DWORD grfMode,
420 DWORD reserved1,
421 DWORD reserved2,
422 IStream **ppstm)
423 {
424 SCODE sc;
425
426 olDebugOut((DEB_ITRACE, "In CExposedDocFile::CreateStream("
427 "%ws, %lX, %lu, %lu, %p)\n", pwcsName, grfMode, reserved1,
428 reserved2, ppstm));
429 olLog(("%p::In CExposedDocFile::CreateStream(%ws, %lX, %lu, %lu, %p)\n",
430 this, pwcsName, grfMode, reserved1, reserved2, ppstm));
431
432 olChk(ValidateOutPtrBuffer(ppstm));
433 *ppstm = NULL;
434 olChk(CheckWName(pwcsName));
435
436 if (reserved1 != 0 || reserved2 != 0)
437 olErr(EH_Err, STG_E_INVALIDPARAMETER);
438 olChk(VerifyPerms(grfMode));
439 if (grfMode & (STGM_CONVERT | STGM_TRANSACTED | STGM_PRIORITY |
440 STGM_DELETEONRELEASE))
441 olErr(EH_Err, STG_E_INVALIDFUNCTION);
442 olChk(Validate());
443 olChk(CheckCopyTo());
444 sc = CreateEntry(pwcsName, STGTY_STREAM, grfMode, (void **)ppstm);
445
446 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::CreateStream => %p\n",
447 *ppstm));
448 EH_Err:
449 olLog(("%p::Out CExposedDocFile::CreateStream(). "
450 "*ppstm == %p, ret == %lx\n", this, SAFE_DREF(ppstm), sc));
451 return sc;
452 }
453
454 //+--------------------------------------------------------------
455 //
456 // Member: CExposedDocFile::OpenStream, public
457 //
458 // Synopsis: Opens an existing stream
459 //
460 // Arguments: [pwcsName] - Name
461 // [reserved1]
462 // [grfMode] - Permissions
463 // [reserved2]
464 // [ppstm] - Stream return
465 //
466 // Returns: Appropriate status code
467 //
468 // Modifies: [ppstm]
469 //
470 //---------------------------------------------------------------
471
472
OpenStream(WCHAR const * pwcsName,void * reserved1,DWORD grfMode,DWORD reserved2,IStream ** ppstm)473 TSTDMETHODIMP CExposedDocFile::OpenStream(WCHAR const *pwcsName,
474 void *reserved1,
475 DWORD grfMode,
476 DWORD reserved2,
477 IStream **ppstm)
478 {
479 SCODE sc;
480
481 olDebugOut((DEB_ITRACE, "In CExposedDocFile::OpenStream("
482 "%ws, %p, %lX, %lu, %p)\n", pwcsName, reserved1,
483 grfMode, reserved2, ppstm));
484 olLog(("%p::In CExposedDocFile::OpenStream(%ws, %lu %lX, %lu, %p)\n",
485 this, pwcsName, reserved1, grfMode, reserved2, ppstm));
486
487 olChk(ValidateOutPtrBuffer(ppstm));
488 *ppstm = NULL;
489 olChk(CheckWName(pwcsName));
490
491 if (reserved1 != NULL || reserved2 != 0)
492 olErr(EH_Err, STG_E_INVALIDPARAMETER);
493 olChk(VerifyPerms(grfMode));
494 if (grfMode & (STGM_TRANSACTED | STGM_PRIORITY |
495 STGM_DELETEONRELEASE))
496 olErr(EH_Err, STG_E_INVALIDFUNCTION);
497 olChk(Validate());
498 sc = OpenEntry(pwcsName, STGTY_STREAM, grfMode, (void **)ppstm);
499
500 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::OpenStream => %p\n",
501 SAFE_DREF(ppstm)));
502 EH_Err:
503 olLog(("%p::Out CExposedDocFile::OpenStream(). "
504 "*ppstm == %p, ret == %lx\n", this, SAVE_DREF(ppstm), sc));
505 return sc;
506 }
507
508 //+--------------------------------------------------------------
509 //
510 // Member: CExposedDocFile::CreateStorage, public
511 //
512 // Synopsis: Creates an embedded DocFile
513 //
514 // Arguments: [pwcsName] - Name
515 // [grfMode] - Permissions
516 // [reserved1]
517 // [reserved2]
518 // [ppstg] - New DocFile return
519 //
520 // Returns: Appropriate status code
521 //
522 // Modifies: [ppstg]
523 //
524 //---------------------------------------------------------------
525
526
CreateStorage(WCHAR const * pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2,IStorage ** ppstg)527 TSTDMETHODIMP CExposedDocFile::CreateStorage(WCHAR const *pwcsName,
528 DWORD grfMode,
529 DWORD reserved1,
530 DWORD reserved2,
531 IStorage **ppstg)
532 {
533 SCODE sc;
534
535 olLog(("%p::In CExposedDocFile::CreateStorage(%ws, %lX, %lu, %lu, %p)\n",
536 this, pwcsName, grfMode, reserved1, reserved2, ppstg));
537 olDebugOut((DEB_ITRACE, "In CExposedDocFile::CreateStorage:%p("
538 "%ws, %lX, %lu, %lu, %p)\n", this, pwcsName, grfMode,
539 reserved1, reserved2, ppstg));
540
541 olChk(ValidateOutPtrBuffer(ppstg));
542 *ppstg = NULL;
543 olChk(CheckWName(pwcsName));
544
545 if (reserved1 != 0 || reserved2 != 0)
546 olErr(EH_Err, STG_E_INVALIDPARAMETER);
547 olChk(VerifyPerms(grfMode));
548 if (grfMode & (STGM_PRIORITY | STGM_DELETEONRELEASE))
549 olErr(EH_Err, STG_E_INVALIDFUNCTION);
550 olChk(Validate());
551 olChk(CheckCopyTo());
552 sc = CreateEntry(pwcsName, STGTY_STORAGE, grfMode, (void **)ppstg);
553
554 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::CreateStorage => %p\n",
555 *ppstg));
556 EH_Err:
557 olLog(("%p::Out CExposedDocFile::CreateStorage(). "
558 "*ppstg == %p, ret == %lX\n", this, *ppstg, sc));
559 return sc;
560 }
561
562 //+--------------------------------------------------------------
563 //
564 // Member: CExposedDocFile::OpenStorage, public
565 //
566 // Synopsis: Gets an existing embedded DocFile
567 //
568 // Arguments: [pwcsName] - Name
569 // [pstgPriority] - Priority reopens
570 // [grfMode] - Permissions
571 // [snbExclude] - Priority reopens
572 // [reserved]
573 // [ppstg] - DocFile return
574 //
575 // Returns: Appropriate status code
576 //
577 // Modifies: [ppstg]
578 //
579 //---------------------------------------------------------------
580
581
OpenStorage(WCHAR const * pwcsName,IStorage * pstgPriority,DWORD grfMode,SNBW snbExclude,DWORD reserved,IStorage ** ppstg)582 TSTDMETHODIMP CExposedDocFile::OpenStorage(WCHAR const *pwcsName,
583 IStorage *pstgPriority,
584 DWORD grfMode,
585 SNBW snbExclude,
586 DWORD reserved,
587 IStorage **ppstg)
588 {
589 SCODE sc;
590 CExposedDocFile *pdfExp;
591
592 olLog(("%p::In CExposedDocFile::OpenStorage(%ws, %p, %lX, %p, %lu, %p)\n",
593 this, pwcsName, pstgPriority, grfMode, snbExclude, reserved,
594 ppstg));
595 olDebugOut((DEB_ITRACE, "In CExposedDocFile::OpenStorage:%p("
596 "%ws, %p, %lX, %p, %lu, %p)\n", this, pwcsName, pstgPriority,
597 grfMode, snbExclude, reserved, ppstg));
598
599 #ifdef _UNICODE // for UNICODE API's we have to do validation,
600 // else it had been done in the ascii layer
601 olChk(CheckWName(pwcsName));
602 #endif
603 olChk(ValidateOutPtrBuffer(ppstg));
604 *ppstg = NULL;
605 if (reserved != 0)
606 olErr(EH_Err, STG_E_INVALIDPARAMETER);
607 olChk(VerifyPerms(grfMode));
608 if (pstgPriority != NULL ||
609 (grfMode & (STGM_PRIORITY | STGM_DELETEONRELEASE)))
610 olErr(EH_Err, STG_E_INVALIDFUNCTION);
611 olChk(Validate());
612 if (snbExclude != 0)
613 olErr(EH_Err, STG_E_INVALIDPARAMETER);
614 olChk(OpenEntry(pwcsName, STGTY_STORAGE, grfMode, (void **)&pdfExp));
615 *ppstg = pdfExp;
616
617 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::OpenStorage => %p\n",
618 *ppstg));
619 EH_Err:
620 olLog(("%p::Out CExposedDocFile::OpenStorage(). "
621 "*ppstg == %p, ret == %lX\n", this, SAFE_DREF(ppstg), sc));
622 return sc;
623
624 }
625
626 //+---------------------------------------------------------------------------
627 //
628 // Member: CExposedDocFile::MakeCopyFlags, public
629 //
630 // Synopsis: Translates IID array into bit fields
631 //
632 // Arguments: [ciidExclude] - Count of IIDs
633 // [rgiidExclude] - IIDs not to copy
634 //
635 // Returns: Appropriate status code
636 //
637 //----------------------------------------------------------------------------
638
639
MakeCopyFlags(DWORD ciidExclude,IID const * rgiidExclude)640 DWORD CExposedDocFile::MakeCopyFlags(DWORD ciidExclude,
641 IID const *rgiidExclude)
642 {
643 DWORD dwCopyFlags;
644
645 olDebugOut((DEB_ITRACE, "In CExposedDocFile::MakeCopyFlags(%lu, %p)\n",
646 ciidExclude, rgiidExclude));
647 // Copy everything by default
648 dwCopyFlags = COPY_ALL;
649 for (; ciidExclude > 0; ciidExclude--, rgiidExclude++)
650 if (IsEqualIID(*rgiidExclude, IID_IStorage))
651 dwCopyFlags &= ~COPY_STORAGES;
652 else if (IsEqualIID(*rgiidExclude, IID_IStream))
653 dwCopyFlags &= ~COPY_STREAMS;
654 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::MakeCopyFlags\n"));
655 return dwCopyFlags;
656 }
657
658 //+--------------------------------------------------------------
659 //
660 // Member: CExposedDocFile::CopyTo, public
661 //
662 // Synopsis: Makes a copy of a DocFile
663 //
664 // Arguments: [ciidExclude] - Length of rgiid array
665 // [rgiidExclude] - Array of IIDs to exclude
666 // [snbExclude] - Names to exclude
667 // [pstgDest] - Parent of copy
668 //
669 // Returns: Appropriate status code
670 //
671 //---------------------------------------------------------------
672
CopyTo(DWORD ciidExclude,IID const * rgiidExclude,SNBW snbExclude,IStorage * pstgDest)673 TSTDMETHODIMP CExposedDocFile::CopyTo(DWORD ciidExclude,
674 IID const *rgiidExclude,
675 SNBW snbExclude,
676 IStorage *pstgDest)
677 {
678 SCODE sc;
679 DWORD i;
680
681 olLog(("%p::In CExposedDocFile::CopyTo(%lu, %p, %p, %p)\n",
682 this, ciidExclude, rgiidExclude, snbExclude, pstgDest));
683 olDebugOut((DEB_ITRACE, "In CExposedDocFile::Copy(%lu, %p, %p, %p)\n",
684 ciidExclude, rgiidExclude, snbExclude, pstgDest));
685
686 if (snbExclude)
687 olChk(ValidateSNBW(snbExclude));
688
689 olChk(ValidateInterface(pstgDest, IID_IStorage));
690 if (rgiidExclude)
691 {
692 olAssert(sizeof(IID)*ciidExclude <= 0xffffUL);
693 olChk(ValidateBuffer(rgiidExclude,
694 (size_t)(sizeof(IID)*ciidExclude)));
695 for (i = 0; i<ciidExclude; i++)
696 olChk(ValidateIid(rgiidExclude[i]));
697 }
698 olChk(Validate());
699 olChk(CheckReverted());
700 olAssert(_pdfb->GetCopyBase() == NULL);
701 _pdfb->SetCopyBase(this);
702 #ifdef NEWPROPS
703 // Flush all descendant property set buffers so that their
704 // underlying Streams (which are about to be copied) are
705 // up to date.
706 olChk(FlushBufferedData());
707 #endif
708 olChk(CopyDocFileToIStorage(GetDF(), pstgDest, snbExclude,
709 MakeCopyFlags(ciidExclude, rgiidExclude)));
710
711 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::Copy\n"));
712
713 EH_Err:
714 _pdfb->SetCopyBase(NULL);
715
716 olLog(("%p::Out ExposedDocFile::CopyTo(). ret == %lX\n",this, sc));
717 return sc;
718 }
719
720 //+--------------------------------------------------------------
721 //
722 // Member: CExposedDocFile::Commit, public
723 //
724 // Synopsis: Commits transacted changes
725 //
726 // Arguments: [dwFlags] - DFC_*
727 //
728 // Returns: Appropriate status code
729 //
730 //---------------------------------------------------------------
731
732
Commit(DWORD dwFlags)733 STDMETHODIMP CExposedDocFile::Commit(DWORD dwFlags)
734 {
735 SCODE sc=S_OK;
736 TIME_T tm;
737
738 olLog(("%p::In CExposedDocFile::Commit(%lX)\n",this, dwFlags));
739 olDebugOut((DEB_ITRACE, "In CExposedDocFile::Commit(%lX)\n", dwFlags));
740
741 if (!VALID_COMMIT(dwFlags))
742 olErr(EH_Err, STG_E_INVALIDFLAG);
743 olChk(Validate());
744 olChk(CheckReverted());
745 if (!P_WRITE(_df)) olErr(EH_Err, STG_E_ACCESSDENIED);
746 if (IsDirty())
747 {
748 olChk(CoFileTimeNow(&tm));
749 olChk(_pdf->SetTime(WT_MODIFICATION, tm));
750 olChk(_pmsBase->Flush(FLUSH_CACHE(dwFlags)));
751 if (!IsRoot()) _pdfParent->SetDirty();
752 }
753 olChk(CoFileTimeNow(&tm));
754 olChk(_pdf->SetTime(WT_ACCESS, tm));
755 #ifdef NEWPROPS
756 olChk(FlushBufferedData());
757 #endif
758
759 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::Commit\n"));
760 EH_Err:
761 olLog(("%p::Out CExposedDocFile::Commit(). ret == %lx\n",this, sc));
762 return ResultFromScode(sc);
763 }
764
765 //+--------------------------------------------------------------
766 //
767 // Member: CExposedDocFile::Revert, public
768 //
769 // Synopsis: Reverts transacted changes
770 //
771 // Returns: S_OK - for direct mode files, this function
772 // has not effect
773 //
774 //---------------------------------------------------------------
775
Revert(void)776 STDMETHODIMP CExposedDocFile::Revert(void)
777 {
778 // we don't supported transacted files
779 // it is stated in the OLE documentation that for direct
780 // files, this method has no effect
781 return ResultFromScode(S_OK);
782 }
783
784 //+--------------------------------------------------------------
785 //
786 // Member: CExposedDocFile::EnumElements, public
787 //
788 // Synopsis: Starts an iterator
789 //
790 // Arguments: [reserved1]
791 // [reserved2]
792 // [reserved3]
793 // [ppenm] - Enumerator return
794 //
795 // Returns: Appropriate status code
796 //
797 // Modifies: [ppenm]
798 //
799 //---------------------------------------------------------------
800
801
EnumElements(DWORD reserved1,void * reserved2,DWORD reserved3,IEnumSTATSTG ** ppenm)802 STDMETHODIMP CExposedDocFile::EnumElements(DWORD reserved1,
803 void *reserved2,
804 DWORD reserved3,
805 IEnumSTATSTG **ppenm)
806 {
807 SCODE sc;
808 CExposedIterator *pdiExp;
809 CDfName dfnTemp;
810
811 olLog(("%p::In CExposedDocFile::EnumElements(%lu, %p, %lu, %p)\n",
812 this, reserved1, reserved2, reserved3, ppenm));
813 olDebugOut((DEB_ITRACE, "In CExposedDocFile::EnumElements(%p)\n",
814 ppenm));
815 olChk(ValidateOutPtrBuffer(ppenm));
816 *ppenm = NULL;
817 if (reserved1 != 0 || reserved2 != NULL || reserved3 != 0)
818 olErr(EH_Err, STG_E_INVALIDPARAMETER);
819 olChk(Validate());
820 olChk(CheckReverted());
821 if (!P_READ(_df))
822 olErr(EH_Err, STG_E_ACCESSDENIED);
823 olMem(pdiExp = new CExposedIterator(this, &dfnTemp));
824 *ppenm = pdiExp;
825
826 EH_Err:
827 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::EnumElements => %p\n",
828 SAFE_DREF(ppenm)));
829 olLog(("%p::Out CExposedDocFile::EnumElements(). ret == %lx\n",this, sc));
830 return ResultFromScode(sc);
831 }
832
833 //+--------------------------------------------------------------
834 //
835 // Member: CExposedDocFile::DestroyElement, public
836 //
837 // Synopsis: Permanently deletes an element of a DocFile
838 //
839 // Arguments: [pwcsName] - Name of element
840 //
841 // Returns: Appropriate status code
842 //
843 //---------------------------------------------------------------
844
845
DestroyElement(WCHAR const * pwcsName)846 TSTDMETHODIMP CExposedDocFile::DestroyElement(WCHAR const *pwcsName)
847 {
848 SCODE sc;
849 CDfName dfn;
850
851 olLog(("%p::In CExposedDocFile::DestroyElement(%ws)\n", this, pwcsName));
852 olDebugOut((DEB_ITRACE, "In CExposedDocFile::DestroyElement(%ws)\n",
853 pwcsName));
854 olChk(CheckWName(pwcsName));
855 olChk(Validate());
856 dfn.Set(pwcsName);
857 olChk(DestroyEntry(&dfn, FALSE));
858
859 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::DestroyElement\n"));
860 EH_Err:
861 olLog(("%p::Out CExposedDocFile::DestroyElement(). ret == %lx\n",
862 this, sc));
863 return sc;
864 }
865
866 //+--------------------------------------------------------------
867 //
868 // Member: CExposedDocFile::MoveElementTo, public
869 //
870 // Synopsis: Move an element of a DocFile to an IStorage
871 //
872 // Arguments: [pwcsName] - Current name
873 // [ptcsNewName] - New name
874 //
875 // Returns: Appropriate status code
876 //
877 // Algorithm: Open source as storage or stream (whatever works)
878 // Create appropriate destination
879 // Copy source to destination
880 // Set create time of destination equal to create time of source
881 // If appropriate, delete source
882 //
883 //---------------------------------------------------------------
884
MoveElementTo(WCHAR const * pwcsName,IStorage * pstgParent,TCHAR const * ptcsNewName,DWORD grfFlags)885 TSTDMETHODIMP CExposedDocFile::MoveElementTo(WCHAR const *pwcsName,
886 IStorage *pstgParent,
887 TCHAR const *ptcsNewName,
888 DWORD grfFlags)
889 {
890 IUnknown *punksrc = NULL;
891 SCODE sc;
892
893 olLog(("%p::In CExposedDocFile::MoveElementTo(%ws, %p, %s, %lu)\n",
894 this, pwcsName, pstgParent, ptcsNewName, grfFlags));
895 olDebugOut((DEB_ITRACE, "In CExposedDocFile::MoveElementTo("
896 "%ws, %p, %s, %lu)\n",
897 pwcsName, pstgParent, ptcsNewName, grfFlags));
898
899 IUnknown *punkdst;
900 IStorage *pstgsrc;
901 STATSTG statstg;
902
903 olChk(CheckWName(pwcsName));
904 olChk(Validate());
905 olChk(VerifyMoveFlags(grfFlags));
906
907 // determine source type (determine its type)
908
909 sc = OpenStorage(pwcsName, (IStorage*)NULL,
910 STGM_DIRECT| STGM_READ| STGM_SHARE_EXCLUSIVE,
911 0, 0, &pstgsrc);
912
913 if (SUCCEEDED(sc))
914 {
915 HRESULT hr;
916
917 // It's a storage
918 punksrc = pstgsrc;
919
920 IStorage *pstgdst;
921 olHChkTo(EH_UnkSrc, pstgsrc->Stat(&statstg, STATFLAG_NONAME));
922
923 hr = pstgParent->CreateStorage(ptcsNewName,
924 STGM_DIRECT |
925 STGM_WRITE |
926 STGM_SHARE_EXCLUSIVE
927 | STGM_FAILIFTHERE,
928 0, 0, &pstgdst);
929 if (DfGetScode(hr) == STG_E_FILEALREADYEXISTS &&
930 grfFlags == STGMOVE_COPY)
931 {
932 hr = pstgParent->OpenStorage(ptcsNewName,
933 NULL,
934 STGM_DIRECT |
935 STGM_WRITE |
936 STGM_SHARE_EXCLUSIVE,
937 NULL,
938 0, &pstgdst);
939 }
940 olHChkTo(EH_UnkSrc, hr);
941
942 punkdst = pstgdst;
943
944 sc = DfGetScode(pstgsrc->CopyTo(0, NULL, NULL, pstgdst));
945 }
946 else if (sc == STG_E_FILENOTFOUND)
947 {
948 // Try opening it as a stream
949
950 IStream *pstmsrc, *pstmdst;
951 olChk(OpenStream(pwcsName, (void *)NULL,
952 STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
953 0, &pstmsrc));
954
955 // It's a stream
956 punksrc = pstmsrc;
957
958 olHChkTo(EH_UnkSrc, pstmsrc->Stat(&statstg, STATFLAG_NONAME));
959
960 olHChkTo(EH_UnkSrc,
961 pstgParent->CreateStream(ptcsNewName,
962 STGM_DIRECT |
963 STGM_WRITE |
964 STGM_SHARE_EXCLUSIVE |
965 (grfFlags == STGMOVE_MOVE ?
966 STGM_FAILIFTHERE :
967 STGM_CREATE),
968 0, 0, &pstmdst));
969
970 punkdst = pstmdst;
971
972 ULARGE_INTEGER cb;
973 ULISetLow (cb, 0xffffffff);
974 ULISetHigh(cb, 0xffffffff);
975 sc = DfGetScode(pstmsrc->CopyTo(pstmdst, cb, NULL, NULL));
976 }
977 else
978 olChk(sc);
979
980 punkdst->Release();
981
982 if (SUCCEEDED(sc))
983 {
984 // Make destination create time match source create time
985 // Note that we don't really care if this call succeeded.
986
987 pstgParent->SetElementTimes(ptcsNewName, &statstg.ctime,
988 NULL, NULL);
989
990 if ((grfFlags & STGMOVE_COPY) == STGMOVE_MOVE)
991 sc = DestroyElement(pwcsName);
992 }
993
994 if (FAILED(sc))
995 {
996 // The copy/move failed, so get rid of the partial result.
997
998 pstgParent->DestroyElement(ptcsNewName);
999 }
1000
1001 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::MoveElementTo\n"));
1002 // Fall through
1003 EH_UnkSrc:
1004 if (punksrc)
1005 punksrc->Release();
1006 EH_Err:
1007 olLog(("%p::Out CExposedDocFile::MoveElementTo(). ret == %lx\n",
1008 this, sc));
1009 return sc;
1010 }
1011
1012 //+--------------------------------------------------------------
1013 //
1014 // Member: CExposedDocFile::RenameElement, public
1015 //
1016 // Synopsis: Renames an element of a DocFile
1017 //
1018 // Arguments: [pwcsName] - Current name
1019 // [pwcsNewName] - New name
1020 //
1021 // Returns: Appropriate status code
1022 //
1023 //---------------------------------------------------------------
1024
1025
RenameElement(WCHAR const * pwcsName,WCHAR const * pwcsNewName)1026 TSTDMETHODIMP CExposedDocFile::RenameElement(WCHAR const *pwcsName,
1027 WCHAR const *pwcsNewName)
1028 {
1029 SCODE sc;
1030 CDfName dfnOld, dfnNew;
1031
1032 olLog(("%p::In CExposedDocFile::RenameElement(%ws, %ws)\n",
1033 this, pwcsName, pwcsNewName));
1034 olDebugOut((DEB_ITRACE, "In CExposedDocFile::RenameElement(%ws, %ws)\n",
1035 pwcsName, pwcsNewName));
1036
1037 olChk(Validate());
1038 olChk(CheckWName(pwcsName));
1039 olChk(CheckWName(pwcsNewName));
1040 dfnOld.Set(pwcsName);
1041 dfnNew.Set(pwcsNewName);
1042 olChk(RenameEntry(&dfnOld, &dfnNew));
1043
1044 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::RenameElement\n"));
1045 EH_Err:
1046 olLog(("%p::Out CExposedDocFile::RenameElement(). ret == %lx\n",
1047 this, sc));
1048 return sc;
1049 }
1050
1051 //+--------------------------------------------------------------
1052 //
1053 // Member: CExposedDocFile::SetElementTimes, public
1054 //
1055 // Synopsis: Sets element time stamps
1056 //
1057 // Arguments: [pwcsName] - Name
1058 // [pctime] - create time
1059 // [patime] - access time
1060 // [pmtime] - modify time
1061 //
1062 // Returns: Appropriate status code
1063 //
1064 //---------------------------------------------------------------
1065
1066
SetElementTimes(WCHAR const * pwcsName,FILETIME const * pctime,FILETIME const * patime,FILETIME const * pmtime)1067 TSTDMETHODIMP CExposedDocFile::SetElementTimes(WCHAR const *pwcsName,
1068 FILETIME const *pctime,
1069 FILETIME const *patime,
1070 FILETIME const *pmtime)
1071 {
1072 SCODE sc;
1073 CDfName dfn;
1074 CDocFile *pdf;
1075
1076 olLog(("%p::In CExposedDocFile::SetElementTimes(%ws, %p, %p, %p)\n",
1077 this, pwcsName, pctime, patime, pmtime));
1078 olDebugOut((DEB_ITRACE, "In CExposedDocFile::SetElementTimes:%p("
1079 "%ws, %p, %p, %p)\n", this, pwcsName, pctime, patime, pmtime));
1080
1081 if (pwcsName)
1082 olChk(CheckWName(pwcsName));
1083 else // function is meant to work on root storage
1084 {
1085 olAssert(FALSE &&
1086 aMsg("SetTimes on root storage is not supported!\n"));
1087 // SetElementTimes on root storage is not portable
1088 // since it calls set filetimes.
1089 return ResultFromScode(STG_E_UNIMPLEMENTEDFUNCTION);
1090 }
1091 olChk(Validate());
1092
1093 if (pctime)
1094 olChk(ValidateBuffer(pctime, sizeof(FILETIME)));
1095 if (patime)
1096 olChk(ValidateBuffer(patime, sizeof(FILETIME)));
1097 if (pmtime)
1098 olChk(ValidateBuffer(pmtime, sizeof(FILETIME)));
1099 dfn.Set(pwcsName);
1100 olChk(CheckReverted());
1101 if (!P_WRITE(_df) || _cilChildren.FindByName(&dfn) != NULL)
1102 olErr(EH_Err, STG_E_ACCESSDENIED);
1103 olChk(_pdf->GetDocFile(&dfn, DF_WRITE, &pdf));
1104
1105 if (pctime)
1106 olChkTo(EH_pdf, pdf->SetTime(WT_CREATION, *pctime));
1107 if (pmtime)
1108 olChkTo(EH_pdf, pdf->SetTime(WT_MODIFICATION, *pmtime));
1109 if (patime)
1110 olChkTo(EH_pdf, pdf->SetTime(WT_ACCESS, *patime));
1111 SetDirty();
1112
1113 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::SetElementTimes\n"));
1114 // Fall thru
1115 EH_pdf:
1116 pdf->Release();
1117 EH_Err:
1118 olLog(("%p::Out CExposedDocFile::SetElementTimes(). ret == %lx\n",
1119 this, sc));
1120 return sc;
1121 }
1122
1123 //+--------------------------------------------------------------
1124 //
1125 // Member: CExposedDocFile::SetClass, public
1126 //
1127 // Synopsis: Sets storage class
1128 //
1129 // Arguments: [clsid] - class id
1130 //
1131 // Returns: Appropriate status code
1132 //
1133 //---------------------------------------------------------------
1134
SetClass(REFCLSID clsid)1135 STDMETHODIMP CExposedDocFile::SetClass(REFCLSID clsid)
1136 {
1137 SCODE sc;
1138
1139 olLog(("%p::In CExposedDocFile::SetClass(?)\n", this));
1140 olDebugOut((DEB_ITRACE, "In CExposedDocFile::SetClass:%p(?)\n", this));
1141
1142 olChk(Validate());
1143 olChk(ValidateBuffer(&clsid, sizeof(CLSID)));
1144 olChk(CheckReverted());
1145 if (!P_WRITE(_df))
1146 olErr(EH_Err, STG_E_ACCESSDENIED);
1147 olChk(_pdf->SetClass(clsid));
1148
1149 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::SetClass\n"));
1150 EH_Err:
1151 olLog(("%p::Out CExposedDocFile::SetClass(). ret == %lx\n",
1152 this, sc));
1153 return ResultFromScode(sc);
1154 }
1155
1156 //+--------------------------------------------------------------
1157 //
1158 // Member: CExposedDocFile::SetStateBits, public
1159 //
1160 // Synopsis: Sets state bits
1161 //
1162 // Arguments: [grfStateBits] - state bits
1163 // [grfMask] - state bits mask
1164 //
1165 // Returns: Appropriate status code
1166 //
1167 //---------------------------------------------------------------
1168
SetStateBits(DWORD grfStateBits,DWORD grfMask)1169 STDMETHODIMP CExposedDocFile::SetStateBits(DWORD grfStateBits, DWORD grfMask)
1170 {
1171 SCODE sc;
1172
1173 olLog(("%p::In CExposedDocFile::SetStateBits(%lu, %lu)\n", this,
1174 grfStateBits, grfMask));
1175 olDebugOut((DEB_ITRACE, "In CExposedDocFile::SetStateBits:%p("
1176 "%lu, %lu)\n", this, grfStateBits, grfMask));
1177
1178 olChk(Validate());
1179 olChk(CheckReverted());
1180 if (!P_WRITE(_df))
1181 olErr(EH_Err, STG_E_ACCESSDENIED);
1182 olChk(_pdf->SetStateBits(grfStateBits, grfMask));
1183 SetDirty();
1184
1185 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::SetStateBits\n"));
1186 // fall thru
1187 EH_Err:
1188 olLog(("%p::Out CExposedDocFile::SetStateBits(). ret == %lx\n",
1189 this, sc));
1190 return ResultFromScode(sc);
1191 }
1192
1193 //+--------------------------------------------------------------
1194 //
1195 // Member: CExposedDocFile::Stat, public virtual
1196 //
1197 // Synopsis: Fills in a buffer of information about this object
1198 //
1199 // Arguments: [pstatstg] - Buffer
1200 //
1201 // Returns: Appropriate status code
1202 //
1203 // Modifies: [pstatstg]
1204 //
1205 //---------------------------------------------------------------
1206
Stat(STATSTGW * pstatstg,DWORD grfStatFlag)1207 TSTDMETHODIMP CExposedDocFile::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
1208 {
1209 SCODE sc;
1210
1211 // root storage should be handled by virtual funcs in CRootExposedDocFile
1212 olAssert(!IsRoot());
1213 olLog(("%p::In CExposedDocFile::Stat(%p)\n", this, pstatstg));
1214 olDebugOut((DEB_ITRACE, "In CExposedDocFile::Stat(%p)\n", pstatstg));
1215
1216 olChkTo(EH_RetSc, ValidateOutBuffer(pstatstg, sizeof(STATSTGW)));
1217 olChk(VerifyStatFlag(grfStatFlag));
1218 olChk(CheckReverted());
1219 olChk(_pdf->GetTime(WT_CREATION, &pstatstg->ctime));
1220 olChk(_pdf->GetTime(WT_MODIFICATION, &pstatstg->mtime));
1221 pstatstg->atime.dwLowDateTime = pstatstg->atime.dwHighDateTime = 0;
1222 olChk(_pdf->GetClass(&pstatstg->clsid));
1223 olChk(_pdf->GetStateBits(&pstatstg->grfStateBits));
1224 pstatstg->pwcsName = NULL;
1225 if ((grfStatFlag & STATFLAG_NONAME) == 0)
1226 {
1227 olChk(DfAllocWCS((WCHAR *)_dfn.GetBuffer(), &pstatstg->pwcsName));
1228 wcscpy(pstatstg->pwcsName, (WCHAR *)_dfn.GetBuffer());
1229 }
1230 pstatstg->grfMode = DFlagsToMode(_df);
1231 pstatstg->type = STGTY_STORAGE;
1232 ULISet32(pstatstg->cbSize, 0); // irelevant for storage obj
1233 pstatstg->grfLocksSupported = 0;
1234 pstatstg->reserved = 0;
1235
1236 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::Stat\n"));
1237 EH_Err:
1238 if (FAILED(sc))
1239 memset(pstatstg, 0, sizeof(STATSTGW));
1240 EH_RetSc:
1241 olLog(("%p::Out CExposedDocFile::Stat(). *pstatstg == %p ret == %lx\n",
1242 this, *pstatstg, sc));
1243 return sc;
1244 }
1245
1246 //+--------------------------------------------------------------
1247 //
1248 // Member: CExposedDocFile::AddRef, public
1249 //
1250 // Synopsis: Increments the ref count
1251 //
1252 // Returns: Appropriate status code
1253 //
1254 //---------------------------------------------------------------
1255
1256
STDMETHODIMP_(ULONG)1257 STDMETHODIMP_(ULONG) CExposedDocFile::AddRef(void)
1258 {
1259 ULONG ulRet;
1260
1261 olLog(("%p::In CExposedDocFile::AddRef()\n", this));
1262 olDebugOut((DEB_ITRACE, "In CExposedDocFile::AddRef()\n"));
1263
1264 if (FAILED(Validate()))
1265 return 0;
1266 AtomicInc(&_cReferences);
1267 ulRet = _cReferences;
1268
1269 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::AddRef\n"));
1270 olLog(("%p::Out CExposedDocFile::AddRef(). ret == %lu\n", this, ulRet));
1271 return ulRet;
1272 }
1273
1274 //+--------------------------------------------------------------
1275 //
1276 // Member: CExposedDocFile::QueryInterface, public
1277 //
1278 // Synopsis: Returns an object for the requested interface
1279 //
1280 // Arguments: [iid] - Interface ID
1281 // [ppvObj] - Object return
1282 //
1283 // Returns: Appropriate status code
1284 //
1285 // Modifies: [ppvObj]
1286 //
1287 //---------------------------------------------------------------
1288
QueryInterface(REFIID iid,void ** ppvObj)1289 STDMETHODIMP CExposedDocFile::QueryInterface(REFIID iid, void **ppvObj)
1290 {
1291 SCODE sc;
1292
1293 olLog(("%p::In CExposedDocFile::QueryInterface(?, %p)\n",
1294 this, ppvObj));
1295 olDebugOut((DEB_ITRACE, "In CExposedDocFile::QueryInterface(?, %p)\n",
1296 ppvObj));
1297
1298 olChk(ValidateOutPtrBuffer(ppvObj));
1299 *ppvObj = NULL;
1300 olChk(ValidateIid(iid));
1301 olChk(Validate());
1302 olChk(CheckReverted());
1303 if ( IsEqualIID(iid, IID_IStorage) || IsEqualIID(iid, IID_IUnknown) )
1304 {
1305 olChk(CExposedDocFile::AddRef());
1306 *ppvObj = (IStorage*) this;
1307 }
1308 #ifdef NEWPROPS
1309 else if (IsEqualIID(iid, IID_IPropertySetStorage))
1310 {
1311 olChk(CExposedDocFile::AddRef());
1312 *ppvObj = (IPropertySetStorage *) this;
1313 }
1314 #endif
1315
1316 else
1317 olErr(EH_Err, E_NOINTERFACE);
1318 sc = S_OK;
1319
1320 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::QueryInterface => %p\n",
1321 ppvObj));
1322 EH_Err:
1323 olLog(("%p::Out CExposedDocFile::QueryInterface(). *ppvObj == %p ret == %lx\n",
1324 this, SAFE_DREF(ppvObj), sc));
1325 return ResultFromScode(sc);
1326 }
1327
1328 //+--------------------------------------------------------------
1329 //
1330 // Method: CExposedDocFile::CopyDStreamToIStream, private
1331 //
1332 // Synopsis: Copies a CDirectStream to an IStream
1333 //
1334 // Arguments: [pstFrom] - CDirectStream
1335 // [pstTo] - IStream
1336 //
1337 // Returns: Appropriate status code
1338 //
1339 //---------------------------------------------------------------
1340
1341
CopyDStreamToIStream(CDirectStream * pstFrom,IStream * pstTo)1342 SCODE CExposedDocFile::CopyDStreamToIStream(CDirectStream *pstFrom,
1343 IStream *pstTo)
1344 {
1345 BYTE *pbBuffer;
1346 SCODE sc;
1347 ULONG cbRead, cbWritten, cbPos, cbSizeLow;
1348 ULARGE_INTEGER cbSize;
1349
1350 // This is part of CopyTo and therefore we are allowed to
1351 // fail with out-of-memory
1352 olMem(pbBuffer = new BYTE[STREAMBUFFERSIZE]);
1353
1354 // Set destination size for contiguity
1355 pstFrom->GetSize(&cbSizeLow);
1356
1357 ULISet32(cbSize, cbSizeLow);
1358 // Don't need to SetAccess0 here because pstTo is an IStream
1359 olHChk(pstTo->SetSize(cbSize));
1360
1361 // Copy between streams
1362 cbPos = 0;
1363 for (;;)
1364 {
1365 olChk(pstFrom->ReadAt(cbPos, pbBuffer, STREAMBUFFERSIZE,
1366 (ULONG STACKBASED *)&cbRead));
1367 if (cbRead == 0) // EOF
1368 break;
1369
1370 // Don't need to SetAccess0 here because pstTo is an IStream
1371 olHChk(pstTo->Write(pbBuffer, cbRead, &cbWritten));
1372 if (cbRead != cbWritten)
1373 olErr(EH_Err, STG_E_WRITEFAULT);
1374 cbPos += cbWritten;
1375 }
1376 sc = S_OK;
1377
1378 EH_Err:
1379 delete [] pbBuffer;
1380 return sc;
1381 }
1382
1383 //+--------------------------------------------------------------
1384 //
1385 // Method: CExposedDocFile::CopyDocFileToIStorage, private
1386 //
1387 // Synopsis: Copies a docfile's contents to an IStorage
1388 //
1389 // Arguments: [pdfFrom] - From
1390 // [pstgTo] - To
1391 // [snbExclude] - Names to not copy
1392 // [dwCopyFlags] - Bitwise flags for types of objects to copy
1393 //
1394 // Returns: Appropriate status code
1395 //
1396 //---------------------------------------------------------------
1397
CopyDocFileToIStorage(CDocFile * pdfFrom,IStorage * pstgTo,SNBW snbExclude,DWORD dwCopyFlags)1398 SCODE CExposedDocFile::CopyDocFileToIStorage(CDocFile *pdfFrom,
1399 IStorage *pstgTo,
1400 SNBW snbExclude,
1401 DWORD dwCopyFlags)
1402 {
1403 PDocFileIterator *pdfi;
1404 SIterBuffer ib;
1405 CDirectStream *pstFrom;
1406 IStream *pstTo;
1407 CDocFile *pdfFromChild;
1408 IStorage *pstgToChild;
1409 SCODE sc;
1410 TCHAR atcName[CWCSTORAGENAME];
1411 CLSID clsid;
1412 DWORD grfStateBits;
1413
1414 olDebugOut((DEB_ITRACE, "In CopyDocFileToIStorage:%p(%p, %p, %p, %lX)\n",
1415 this, pdfFrom, pstgTo, snbExclude, dwCopyFlags));
1416
1417 olChk(pdfFrom->GetClass(&clsid));
1418
1419 olHChk(pstgTo->SetClass(clsid));
1420
1421 olChk(pdfFrom->GetStateBits(&grfStateBits));
1422
1423 olHChk(pstgTo->SetStateBits(grfStateBits, 0xffffffff));
1424
1425 olChk(pdfFrom->GetIterator(&pdfi));
1426
1427 for (;;)
1428 {
1429 sc = pdfi->BufferGetNext(&ib);
1430
1431 if (sc == STG_E_NOMOREFILES)
1432 break;
1433 else if (FAILED(sc))
1434 olErr(EH_pdfi, sc);
1435
1436 if (snbExclude && NameInSNB(&ib.dfnName, snbExclude) == S_OK)
1437 continue;
1438
1439 if ((ib.type == STGTY_STORAGE && (dwCopyFlags & COPY_STORAGES) == 0) ||
1440 (ib.type == STGTY_STREAM && (dwCopyFlags & COPY_STREAMS) == 0)
1441 )
1442 continue;
1443
1444 switch(ib.type)
1445 {
1446 case STGTY_STORAGE:
1447 // Embedded DocFile, create destination and recurse
1448
1449 sc = pdfFrom->GetDocFile(&ib.dfnName, DF_READ,
1450 ib.type, &pdfFromChild);
1451 olChkTo(EH_pdfi, sc);
1452
1453 WTOT(atcName, (WCHAR *)ib.dfnName.GetBuffer(), CWCSTORAGENAME);
1454
1455 // Don't need to SetAccess0 here because pstgTo is an IStorage.
1456
1457 sc = DfGetScode(pstgTo->CreateStorage(atcName, STGM_WRITE |
1458 STGM_SHARE_EXCLUSIVE |
1459 STGM_FAILIFTHERE,
1460 0, 0, &pstgToChild));
1461 if (sc == STG_E_FILEALREADYEXISTS)
1462 olHChkTo(EH_Get, pstgTo->OpenStorage(atcName, NULL,
1463 STGM_WRITE |
1464 STGM_SHARE_EXCLUSIVE,
1465 NULL, 0, &pstgToChild));
1466 else if (FAILED(sc))
1467 olErr(EH_Get, sc);
1468 olChkTo(EH_Create,
1469 CopyDocFileToIStorage(pdfFromChild, pstgToChild, NULL,
1470 dwCopyFlags));
1471 pdfFromChild->Release();
1472 pstgToChild->Release();
1473 break;
1474
1475 case STGTY_STREAM:
1476 sc = pdfFrom->GetStream(&ib.dfnName, DF_READ, ib.type, &pstFrom);
1477 olChkTo(EH_pdfi, sc);
1478 WTOT(atcName, (WCHAR *)ib.dfnName.GetBuffer(), CWCSTORAGENAME);
1479
1480 // Don't need to SetAccess0 here because pstgTo is an IStorage.
1481
1482 olHChkTo(EH_Get,
1483 pstgTo->CreateStream(atcName, STGM_WRITE |
1484 STGM_SHARE_EXCLUSIVE |
1485 STGM_CREATE,
1486 0, 0, &pstTo));
1487 olChkTo(EH_Create, CopyDStreamToIStream(pstFrom, pstTo));
1488 pstFrom->Release();
1489 pstTo->Release();
1490 break;
1491
1492
1493 default:
1494 olAssert(!aMsg("Unknown type in CopyDocFileToIStorage"));
1495 break;
1496 }
1497 }
1498 pdfi->Release();
1499 olDebugOut((DEB_ITRACE, "Out CopyDocFileToIStorage\n"));
1500 return S_OK;
1501
1502 EH_Create:
1503 if (ib.type == STGTY_STORAGE)
1504 pstgToChild->Release();
1505 else
1506 pstTo->Release();
1507 olVerSucc(pstgTo->DestroyElement(atcName));
1508 EH_Get:
1509 if (ib.type == STGTY_STORAGE)
1510 pdfFromChild->Release();
1511 else
1512 pstFrom->Release();
1513 EH_pdfi:
1514 pdfi->Release();
1515 EH_Err:
1516 return sc;
1517 }
1518
1519
1520 //+---------------------------------------------------------------------------
1521 //
1522 // Member: CExposedDocFile::SwitchToFile, public
1523 //
1524 // Synopsis: Switches the underlying file to another file
1525 //
1526 // Arguments: [ptcsFile] - New file name
1527 //
1528 // Returns: Appropriate status code
1529 //
1530 //----------------------------------------------------------------------------
1531
1532
SwitchToFile(TCHAR * ptcsFile)1533 STDMETHODIMP CExposedDocFile::SwitchToFile(TCHAR *ptcsFile)
1534 {
1535 UNREFERENCED_PARM(ptcsFile);
1536 olAssert(FALSE && aMsg("Unimplemented Function called!\n"));
1537 return ResultFromScode(STG_E_UNIMPLEMENTEDFUNCTION);
1538 }
1539
1540 //+---------------------------------------------------------------------------
1541 //
1542 // Member: CExposedDocFile::CreateExposedStream, private
1543 //
1544 // Synopsis: Creates an Exposed Stream
1545 // This is a private function that creates the exposed stream.
1546 // It is splitted out as a function so that the code can be
1547 // reused.
1548 //
1549 // Arguments: [pdfnName] name of entry
1550 // [df] doc file flags
1551 // [ppStream] returned ExposedStream
1552 //
1553 // Returns: Appropriate status code
1554 //
1555 //----------------------------------------------------------------------------
1556
1557
CreateExposedStream(CDfName const * pdfnName,DFLAGS const df,CExposedStream ** ppStream)1558 SCODE CExposedDocFile::CreateExposedStream( CDfName const *pdfnName,
1559 DFLAGS const df,
1560 CExposedStream **ppStream)
1561 {
1562 CExposedStream *pstExp = NULL;
1563 CDirectStream *pstDirect = NULL;
1564 SCODE sc = S_OK;
1565
1566 olChk(CheckReverted());
1567 if (!P_WRITE(_df)) olErr(EH_Err, STG_E_ACCESSDENIED);
1568
1569 olChk(_cilChildren.IsDenied(pdfnName, df, _df));
1570 olChk(_pdf->CreateStream(pdfnName, df, DF_NOLUID, &pstDirect));
1571
1572 // As soon as we have a base we dirty ourself (in case
1573 // we get an error later) so that we'll flush properly.
1574 SetDirty();
1575 olMemTo(EH_pst, pstExp = new CExposedStream());
1576 olChkTo(EH_pstExp, pstExp->Init(pstDirect, this,
1577 df, pdfnName, 0));
1578 *ppStream = pstExp;
1579 return S_OK;
1580
1581 EH_pstExp:
1582 delete pstExp;
1583 EH_pst:
1584 pstDirect->Release();
1585 olVerSucc(DestroyEntry(pdfnName, TRUE));
1586 EH_Err:
1587 return sc;
1588 }
1589
1590 //+---------------------------------------------------------------------------
1591 //
1592 // Member: CExposedDocFile::GetExposedStream, private
1593 //
1594 // Synopsis: Gets an existing exposed stream
1595 // This is a private function that gets the exposed stream.
1596 // It is splitted out as a function so that the code can be
1597 // reused.
1598 //
1599 // Arguments: [pdfnName] name of entry
1600 // [df] doc file flags
1601 // [ppStream] returned ExposedStream
1602 //
1603 // Returns: Appropriate status code
1604 //
1605 //----------------------------------------------------------------------------
1606
1607
GetExposedStream(CDfName const * pdfnName,DFLAGS const df,CExposedStream ** ppStream)1608 SCODE CExposedDocFile::GetExposedStream( CDfName const *pdfnName,
1609 DFLAGS const df,
1610 CExposedStream **ppStream)
1611 {
1612 CExposedStream *pstExp = NULL;
1613 CDirectStream *pstDirect = NULL;
1614 SCODE sc = S_OK;
1615
1616 olChk(CheckReverted());
1617 if (!P_READ(_df)) olErr(EH_Err, STG_E_ACCESSDENIED);
1618
1619 // Check permissions
1620 olChk(_cilChildren.IsDenied(pdfnName, df, _df));
1621
1622 olChk(_pdf->GetStream(pdfnName, df, DF_NOLUID, &pstDirect));
1623
1624 olMemTo(EH_pst, pstExp = new CExposedStream());
1625 olChkTo(EH_pstExp, pstExp->Init(pstDirect, this,
1626 df, pdfnName, 0));
1627 *ppStream = pstExp;
1628 return S_OK;
1629
1630 EH_pstExp:
1631 delete pstExp;
1632 EH_pst:
1633 pstDirect->Release();
1634 EH_Err:
1635 return sc;
1636 }
1637
1638 //+--------------------------------------------------------------
1639 //
1640 // Member: CExposedDocFile::DestroyEntry, private
1641 //
1642 // Synopsis: Destroys an entry and removes it from the children
1643 // list.
1644 //
1645 //---------------------------------------------------------------
DestroyEntry(CDfName const * pdfnName,BOOL fClean)1646 SCODE CExposedDocFile::DestroyEntry( CDfName const *pdfnName,
1647 BOOL fClean)
1648 {
1649 SCODE sc=S_OK;
1650 olChk(CheckReverted());
1651 if (!P_WRITE(_df)) olErr(EH_Err, STG_E_ACCESSDENIED);
1652
1653 olChk(_pdf->DestroyEntry(pdfnName, fClean));
1654 _cilChildren.DeleteByName(pdfnName);
1655 SetDirty();
1656
1657 // Fall through
1658 EH_Err:
1659 return sc;
1660 }
1661
1662 //+--------------------------------------------------------------
1663 //
1664 // Member: CExposedDocFile::CreateExposedDocFile, private
1665 //
1666 // Synopsis: Creates an embedded DocFile
1667 //
1668 // Arguments: [pdfnName] - Name
1669 // [df] - Permissions
1670 // [ppdfDocFile] - New DocFile return
1671 //
1672 // Returns: Appropriate status code
1673 //
1674 // Modifies: [ppdfDocFile]
1675 //
1676 //---------------------------------------------------------------
1677
CreateExposedDocFile(CDfName const * pdfnName,DFLAGS const df,CExposedDocFile ** ppdfDocFile)1678 SCODE CExposedDocFile::CreateExposedDocFile(CDfName const *pdfnName,
1679 DFLAGS const df,
1680 CExposedDocFile **ppdfDocFile)
1681 {
1682 SCODE sc;
1683 CDocFile *pdf=NULL;
1684 SEntryBuffer eb;
1685
1686 olChk(CheckReverted());
1687
1688 if (!P_WRITE(_df)) olErr(EH_Err, STG_E_ACCESSDENIED);
1689 olChk(_cilChildren.IsDenied(pdfnName, df, _df));
1690
1691 olChkTo(EH_Reserve, _pdf->CreateDocFile(pdfnName, df, DF_NOLUID,
1692 &pdf));
1693
1694 // As soon as we have a base we dirty ourself (in case
1695 // we get an error later) so that we'll flush properly.
1696 SetDirty();
1697 eb.luid = pdf->GetLuid();
1698 olAssert(eb.luid != DF_NOLUID && aMsg("DocFile id is DF_NOLUID!"));
1699 olMemTo(EH_pdf,
1700 *ppdfDocFile = new CExposedDocFile(this, pdf, df, eb.luid,
1701 _pilbBase, pdfnName, _pmsBase, _pdfb));
1702 return S_OK;
1703
1704 EH_pdf:
1705 pdf->Release();
1706 olVerSucc(_pdf->DestroyEntry(pdfnName, TRUE));
1707 return sc;
1708 EH_Reserve:
1709 EH_Err:
1710 return sc;
1711 }
1712
1713 //+--------------------------------------------------------------
1714 //
1715 // Member: CExposedDocFile::GetExposedDocFile, private
1716 //
1717 // Synopsis: Retrieves an embedded DocFile
1718 //
1719 // Arguments: [pdfnName] - Name
1720 // [df] - Permissions
1721 // [ppdfDocFile] - New DocFile return
1722 //
1723 // Returns: Appropriate status code
1724 //
1725 // Modifies: [ppdfDocFile]
1726 //
1727 //---------------------------------------------------------------
1728
GetExposedDocFile(CDfName const * pdfnName,DFLAGS const df,CExposedDocFile ** ppdfDocFile)1729 SCODE CExposedDocFile::GetExposedDocFile( CDfName const *pdfnName,
1730 DFLAGS const df,
1731 CExposedDocFile **ppdfDocFile)
1732 {
1733 CDocFile *pdf;
1734 SCODE sc;
1735 SEntryBuffer eb;
1736
1737 olChk(CheckReverted());
1738 if (!P_READ(_df)) olErr(EH_Err, STG_E_ACCESSDENIED);
1739
1740 // Check to see if an instance with DENY_* exists
1741 olChk(_cilChildren.IsDenied(pdfnName, df, _df));
1742
1743 olChk(_pdf->GetDocFile(pdfnName, df, &pdf));
1744 eb.luid = pdf->GetLuid();
1745 olAssert(eb.luid != DF_NOLUID && aMsg("DocFile id is DF_NOLUID!"));
1746 olMemTo(EH_pdf,
1747 *ppdfDocFile = new CExposedDocFile(this, pdf, df, eb.luid,
1748 _pilbBase, pdfnName, _pmsBase, _pdfb));
1749 return S_OK;
1750
1751 EH_pdf:
1752 pdf->Release();
1753 EH_Err:
1754 return sc;
1755 }
1756
1757 //+--------------------------------------------------------------
1758 //
1759 // Member: CExposedDocFile::RenameEntry, public
1760 //
1761 // Synopsis: Renames an element of a DocFile
1762 //
1763 // Arguments: [pdfnName] - Current name
1764 // [pdfnNewName] - New name
1765 //
1766 // Returns: Appropriate status code
1767 //
1768 //---------------------------------------------------------------
1769
RenameEntry(CDfName const * pdfnName,CDfName const * pdfnNewName)1770 SCODE CExposedDocFile::RenameEntry(CDfName const *pdfnName,
1771 CDfName const *pdfnNewName)
1772 {
1773 SCODE sc;
1774
1775 olChk(CheckReverted());
1776 if (!P_WRITE(_df))
1777 sc = STG_E_ACCESSDENIED;
1778 else
1779 {
1780 sc = _pdf->RenameEntry(pdfnName, pdfnNewName);
1781 if (SUCCEEDED(sc))
1782 {
1783 _cilChildren.RenameChild(pdfnName, pdfnNewName);
1784 SetDirty();
1785 }
1786 }
1787
1788 // Fall through
1789 EH_Err:
1790 return sc;
1791 }
1792
1793 //+--------------------------------------------------------------
1794 //
1795 // Member: CExposedDocFile::RevertFromAbove, public virtual from
1796 // PRevertable
1797 //
1798 // Synopsis: Parent has asked for reversion
1799 //
1800 //---------------------------------------------------------------
1801
RevertFromAbove(void)1802 void CExposedDocFile::RevertFromAbove(void)
1803 {
1804 olDebugOut((DEB_ITRACE, "In CExposedDocFile::RevertFromAbove:%p()\n", this));
1805 _df |= DF_REVERTED;
1806
1807 _cilChildren.DeleteByName(NULL);
1808
1809 _pdf->Release();
1810 #if DBG == 1
1811 _pdf = NULL;
1812 #endif
1813 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::RevertFromAbove\n"));
1814 }
1815
1816 //+--------------------------------------------------------------
1817 //
1818 // Member: CExposedDocFile::IsAtOrAbove, public
1819 //
1820 // Synopsis: Determines whether the given docfile is an ancestor
1821 // of this docfile
1822 //
1823 // Arguments: [pdf] - Docfile to check
1824 //
1825 // Returns: TRUE or FALSE
1826 //
1827 //---------------------------------------------------------------
1828
IsAtOrAbove(CExposedDocFile * pdf)1829 BOOL CExposedDocFile::IsAtOrAbove(CExposedDocFile *pdf)
1830 {
1831 CExposedDocFile *pdfPar = this;
1832
1833 olAssert(SUCCEEDED(CheckReverted()));
1834
1835 do
1836 {
1837 if (pdfPar == pdf)
1838 break;
1839 }
1840 while ((pdfPar = pdfPar->_pdfParent));
1841 return pdfPar == pdf;
1842 }
1843
1844 #ifdef NEWPROPS
1845 //+---------------------------------------------------------------------------
1846 //
1847 // Member: CExposedDocFile::GetStorage, public IPrivateStorage
1848 //
1849 // Synopsis: Returns the IStorage for this object.
1850 //
1851 // Notes: This member is called by CPropertyStorage.
1852 //
1853 //----------------------------------------------------------------------------
1854
STDMETHODIMP_(IStorage *)1855 STDMETHODIMP_(IStorage *)
1856 CExposedDocFile::GetStorage(VOID)
1857 {
1858 return this;
1859 }
1860
1861 //+--------------------------------------------------------------
1862 //
1863 // Member: CExposedDocFile::FlushBufferedData
1864 // : public, virtual : PRevertable
1865 //
1866 // Synopsis: Flush buffered data in any child streams.
1867 //
1868 //---------------------------------------------------------------
1869
FlushBufferedData(void)1870 SCODE CExposedDocFile::FlushBufferedData(void)
1871 {
1872 SCODE sc;
1873
1874 olDebugOut((DEB_ITRACE,
1875 "In CExposedDocFile::FlushBufferedData:%p()\n", this));
1876
1877 sc = _cilChildren.FlushBufferedData();
1878
1879 olDebugOut((DEB_ITRACE, "Out CExposedDocFile::FlushBufferedData\n"));
1880
1881 return sc;
1882 }
1883
1884 #endif // #ifdef NEWPROPS
1885