source: trunk/src/ole32/stg_stream.c@ 8266

Last change on this file since 8266 was 7926, checked in by sandervl, 24 years ago

Wine 20020215 resync

File size: 22.7 KB
Line 
1/*
2 * Compound Storage (32 bit version)
3 * Stream implementation
4 *
5 * This file contains the implementation of the stream interface
6 * for streams contained in a compound storage.
7 *
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Thuy Nguyen
10 */
11#ifdef __WIN32OS2__
12#include "ole32.h"
13#include "heapstring.h"
14#endif
15
16#include <assert.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20
21#include "winbase.h"
22#include "winerror.h"
23#include "ntddk.h"
24#include "debugtools.h"
25
26#include "storage32.h"
27
28DEFAULT_DEBUG_CHANNEL(storage);
29
30
31/*
32 * Virtual function table for the StgStreamImpl class.
33 */
34static ICOM_VTABLE(IStream) StgStreamImpl_Vtbl =
35{
36 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
37 StgStreamImpl_QueryInterface,
38 StgStreamImpl_AddRef,
39 StgStreamImpl_Release,
40 StgStreamImpl_Read,
41 StgStreamImpl_Write,
42 StgStreamImpl_Seek,
43 StgStreamImpl_SetSize,
44 StgStreamImpl_CopyTo,
45 StgStreamImpl_Commit,
46 StgStreamImpl_Revert,
47 StgStreamImpl_LockRegion,
48 StgStreamImpl_UnlockRegion,
49 StgStreamImpl_Stat,
50 StgStreamImpl_Clone
51};
52
53/******************************************************************************
54** StgStreamImpl implementation
55*/
56
57/***
58 * This is the constructor for the StgStreamImpl class.
59 *
60 * Params:
61 * parentStorage - Pointer to the storage that contains the stream to open
62 * ownerProperty - Index of the property that points to this stream.
63 */
64StgStreamImpl* StgStreamImpl_Construct(
65 StorageBaseImpl* parentStorage,
66 DWORD grfMode,
67 ULONG ownerProperty)
68{
69 StgStreamImpl* newStream;
70
71 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
72
73 if (newStream!=0)
74 {
75 /*
76 * Set-up the virtual function table and reference count.
77 */
78 ICOM_VTBL(newStream) = &StgStreamImpl_Vtbl;
79 newStream->ref = 0;
80
81 /*
82 * We want to nail-down the reference to the storage in case the
83 * stream out-lives the storage in the client application.
84 */
85 newStream->parentStorage = parentStorage;
86 IStorage_AddRef((IStorage*)newStream->parentStorage);
87
88 newStream->grfMode = grfMode;
89 newStream->ownerProperty = ownerProperty;
90
91 /*
92 * Start the stream at the beginning.
93 */
94 newStream->currentPosition.s.HighPart = 0;
95 newStream->currentPosition.s.LowPart = 0;
96
97 /*
98 * Initialize the rest of the data.
99 */
100 newStream->streamSize.s.HighPart = 0;
101 newStream->streamSize.s.LowPart = 0;
102 newStream->bigBlockChain = 0;
103 newStream->smallBlockChain = 0;
104
105 /*
106 * Read the size from the property and determine if the blocks forming
107 * this stream are large or small.
108 */
109 StgStreamImpl_OpenBlockChain(newStream);
110 }
111
112 return newStream;
113}
114
115/***
116 * This is the destructor of the StgStreamImpl class.
117 *
118 * This method will clean-up all the resources used-up by the given StgStreamImpl
119 * class. The pointer passed-in to this function will be freed and will not
120 * be valid anymore.
121 */
122void StgStreamImpl_Destroy(StgStreamImpl* This)
123{
124 TRACE("(%p)\n", This);
125
126 /*
127 * Release the reference we are holding on the parent storage.
128 */
129 IStorage_Release((IStorage*)This->parentStorage);
130 This->parentStorage = 0;
131
132 /*
133 * Make sure we clean-up the block chain stream objects that we were using.
134 */
135 if (This->bigBlockChain != 0)
136 {
137 BlockChainStream_Destroy(This->bigBlockChain);
138 This->bigBlockChain = 0;
139 }
140
141 if (This->smallBlockChain != 0)
142 {
143 SmallBlockChainStream_Destroy(This->smallBlockChain);
144 This->smallBlockChain = 0;
145 }
146
147 /*
148 * Finally, free the memory used-up by the class.
149 */
150 HeapFree(GetProcessHeap(), 0, This);
151}
152
153/***
154 * This implements the IUnknown method QueryInterface for this
155 * class
156 */
157HRESULT WINAPI StgStreamImpl_QueryInterface(
158 IStream* iface,
159 REFIID riid, /* [in] */
160 void** ppvObject) /* [iid_is][out] */
161{
162 StgStreamImpl* const This=(StgStreamImpl*)iface;
163
164 /*
165 * Perform a sanity check on the parameters.
166 */
167 if (ppvObject==0)
168 return E_INVALIDARG;
169
170 /*
171 * Initialize the return parameter.
172 */
173 *ppvObject = 0;
174
175 /*
176 * Compare the riid with the interface IDs implemented by this object.
177 */
178 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
179 {
180 *ppvObject = (IStream*)This;
181 }
182 else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
183 {
184 *ppvObject = (IStream*)This;
185 }
186
187 /*
188 * Check that we obtained an interface.
189 */
190 if ((*ppvObject)==0)
191 return E_NOINTERFACE;
192
193 /*
194 * Query Interface always increases the reference count by one when it is
195 * successful
196 */
197 StgStreamImpl_AddRef(iface);
198
199 return S_OK;;
200}
201
202/***
203 * This implements the IUnknown method AddRef for this
204 * class
205 */
206ULONG WINAPI StgStreamImpl_AddRef(
207 IStream* iface)
208{
209 StgStreamImpl* const This=(StgStreamImpl*)iface;
210
211 This->ref++;
212
213 return This->ref;
214}
215
216/***
217 * This implements the IUnknown method Release for this
218 * class
219 */
220ULONG WINAPI StgStreamImpl_Release(
221 IStream* iface)
222{
223 StgStreamImpl* const This=(StgStreamImpl*)iface;
224
225 ULONG newRef;
226
227 This->ref--;
228
229 newRef = This->ref;
230
231 /*
232 * If the reference count goes down to 0, perform suicide.
233 */
234 if (newRef==0)
235 {
236 StgStreamImpl_Destroy(This);
237 }
238
239 return newRef;
240}
241
242/***
243 * This method will open the block chain pointed by the property
244 * that describes the stream.
245 * If the stream's size is null, no chain is opened.
246 */
247void StgStreamImpl_OpenBlockChain(
248 StgStreamImpl* This)
249{
250 StgProperty curProperty;
251 BOOL readSucessful;
252
253 /*
254 * Make sure no old object is left over.
255 */
256 if (This->smallBlockChain != 0)
257 {
258 SmallBlockChainStream_Destroy(This->smallBlockChain);
259 This->smallBlockChain = 0;
260 }
261
262 if (This->bigBlockChain != 0)
263 {
264 BlockChainStream_Destroy(This->bigBlockChain);
265 This->bigBlockChain = 0;
266 }
267
268 /*
269 * Read the information from the property.
270 */
271 readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
272 This->ownerProperty,
273 &curProperty);
274
275 if (readSucessful)
276 {
277 This->streamSize = curProperty.size;
278
279 /*
280 * This code supports only streams that are <32 bits in size.
281 */
282 assert(This->streamSize.s.HighPart == 0);
283
284 if(curProperty.startingBlock == BLOCK_END_OF_CHAIN)
285 {
286 assert( (This->streamSize.s.HighPart == 0) && (This->streamSize.s.LowPart == 0) );
287 }
288 else
289 {
290 if ( (This->streamSize.s.HighPart == 0) &&
291 (This->streamSize.s.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
292 {
293 This->smallBlockChain = SmallBlockChainStream_Construct(
294 This->parentStorage->ancestorStorage,
295 This->ownerProperty);
296 }
297 else
298 {
299 This->bigBlockChain = BlockChainStream_Construct(
300 This->parentStorage->ancestorStorage,
301 NULL,
302 This->ownerProperty);
303 }
304 }
305 }
306}
307
308/***
309 * This method is part of the ISequentialStream interface.
310 *
311 * It reads a block of information from the stream at the current
312 * position. It then moves the current position at the end of the
313 * read block
314 *
315 * See the documentation of ISequentialStream for more info.
316 */
317HRESULT WINAPI StgStreamImpl_Read(
318 IStream* iface,
319 void* pv, /* [length_is][size_is][out] */
320 ULONG cb, /* [in] */
321 ULONG* pcbRead) /* [out] */
322{
323 StgStreamImpl* const This=(StgStreamImpl*)iface;
324
325 ULONG bytesReadBuffer;
326 ULONG bytesToReadFromBuffer;
327 HRESULT res = S_FALSE;
328
329 TRACE("(%p, %p, %ld, %p)\n",
330 iface, pv, cb, pcbRead);
331
332 /*
333 * If the caller is not interested in the number of bytes read,
334 * we use another buffer to avoid "if" statements in the code.
335 */
336 if (pcbRead==0)
337 pcbRead = &bytesReadBuffer;
338
339 /*
340 * Using the known size of the stream, calculate the number of bytes
341 * to read from the block chain
342 */
343 bytesToReadFromBuffer = min( This->streamSize.s.LowPart - This->currentPosition.s.LowPart, cb);
344
345 /*
346 * Depending on the type of chain that was opened when the stream was constructed,
347 * we delegate the work to the method that reads the block chains.
348 */
349 if (This->smallBlockChain!=0)
350 {
351 SmallBlockChainStream_ReadAt(This->smallBlockChain,
352 This->currentPosition,
353 bytesToReadFromBuffer,
354 pv,
355 pcbRead);
356
357 }
358 else if (This->bigBlockChain!=0)
359 {
360 BlockChainStream_ReadAt(This->bigBlockChain,
361 This->currentPosition,
362 bytesToReadFromBuffer,
363 pv,
364 pcbRead);
365 }
366 else
367 {
368 /*
369 * Small and big block chains are both NULL. This case will happen
370 * when a stream starts with BLOCK_END_OF_CHAIN and has size zero.
371 */
372
373 *pcbRead = 0;
374 res = S_OK;
375 goto end;
376 }
377
378 /*
379 * We should always be able to read the proper amount of data from the
380 * chain.
381 */
382 assert(bytesToReadFromBuffer == *pcbRead);
383
384 /*
385 * Advance the pointer for the number of positions read.
386 */
387 This->currentPosition.s.LowPart += *pcbRead;
388
389 if(*pcbRead != cb)
390 {
391 WARN("read %ld instead of the required %ld bytes !\n", *pcbRead, cb);
392 /*
393 * this used to return S_FALSE, however MSDN docu says that an app should
394 * be prepared to handle error in case of stream end reached, as *some*
395 * implementations *might* return an error (IOW: most do *not*).
396 * As some program fails on returning S_FALSE, I better use S_OK here.
397 */
398 res = S_OK;
399 }
400 else
401 res = S_OK;
402
403end:
404 TRACE("<-- %08lx\n", res);
405 return res;
406}
407
408/***
409 * This method is part of the ISequentialStream interface.
410 *
411 * It writes a block of information to the stream at the current
412 * position. It then moves the current position at the end of the
413 * written block. If the stream is too small to fit the block,
414 * the stream is grown to fit.
415 *
416 * See the documentation of ISequentialStream for more info.
417 */
418HRESULT WINAPI StgStreamImpl_Write(
419 IStream* iface,
420 const void* pv, /* [size_is][in] */
421 ULONG cb, /* [in] */
422 ULONG* pcbWritten) /* [out] */
423{
424 StgStreamImpl* const This=(StgStreamImpl*)iface;
425
426 ULARGE_INTEGER newSize;
427 ULONG bytesWritten = 0;
428
429 TRACE("(%p, %p, %ld, %p)\n",
430 iface, pv, cb, pcbWritten);
431
432 /*
433 * Do we have permission to write to this stream?
434 */
435 if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE))) {
436 return STG_E_ACCESSDENIED;
437 }
438
439 /*
440 * If the caller is not interested in the number of bytes written,
441 * we use another buffer to avoid "if" statements in the code.
442 */
443 if (pcbWritten == 0)
444 pcbWritten = &bytesWritten;
445
446 /*
447 * Initialize the out parameter
448 */
449 *pcbWritten = 0;
450
451 if (cb == 0)
452 {
453 return S_OK;
454 }
455 else
456 {
457 newSize.s.HighPart = 0;
458 newSize.s.LowPart = This->currentPosition.s.LowPart + cb;
459 }
460
461 /*
462 * Verify if we need to grow the stream
463 */
464 if (newSize.s.LowPart > This->streamSize.s.LowPart)
465 {
466 /* grow stream */
467 IStream_SetSize(iface, newSize);
468 }
469
470 /*
471 * Depending on the type of chain that was opened when the stream was constructed,
472 * we delegate the work to the method that readwrites to the block chains.
473 */
474 if (This->smallBlockChain!=0)
475 {
476 SmallBlockChainStream_WriteAt(This->smallBlockChain,
477 This->currentPosition,
478 cb,
479 pv,
480 pcbWritten);
481
482 }
483 else if (This->bigBlockChain!=0)
484 {
485 BlockChainStream_WriteAt(This->bigBlockChain,
486 This->currentPosition,
487 cb,
488 pv,
489 pcbWritten);
490 }
491 else
492 assert(FALSE);
493
494 /*
495 * Advance the position pointer for the number of positions written.
496 */
497 This->currentPosition.s.LowPart += *pcbWritten;
498
499 return S_OK;
500}
501
502/***
503 * This method is part of the IStream interface.
504 *
505 * It will move the current stream pointer according to the parameters
506 * given.
507 *
508 * See the documentation of IStream for more info.
509 */
510HRESULT WINAPI StgStreamImpl_Seek(
511 IStream* iface,
512 LARGE_INTEGER dlibMove, /* [in] */
513 DWORD dwOrigin, /* [in] */
514 ULARGE_INTEGER* plibNewPosition) /* [out] */
515{
516 StgStreamImpl* const This=(StgStreamImpl*)iface;
517
518 ULARGE_INTEGER newPosition;
519
520 TRACE("(%p, %ld, %ld, %p)\n",
521 iface, dlibMove.s.LowPart, dwOrigin, plibNewPosition);
522
523 /*
524 * The caller is allowed to pass in NULL as the new position return value.
525 * If it happens, we assign it to a dynamic variable to avoid special cases
526 * in the code below.
527 */
528 if (plibNewPosition == 0)
529 {
530 plibNewPosition = &newPosition;
531 }
532
533 /*
534 * The file pointer is moved depending on the given "function"
535 * parameter.
536 */
537 switch (dwOrigin)
538 {
539 case STREAM_SEEK_SET:
540 plibNewPosition->s.HighPart = 0;
541 plibNewPosition->s.LowPart = 0;
542 break;
543 case STREAM_SEEK_CUR:
544 *plibNewPosition = This->currentPosition;
545 break;
546 case STREAM_SEEK_END:
547 *plibNewPosition = This->streamSize;
548 break;
549 default:
550 return STG_E_INVALIDFUNCTION;
551 }
552
553#ifdef __WIN32OS2__
554 /*
555 * do some multiword arithmetic:
556 * treat HighPart as a signed value
557 * treat LowPart as unsigned
558 * NOTE: this stuff is two's complement specific!
559 */
560 if (dlibMove.s.HighPart < 0) { /* dlibMove is < 0 */
561 /* calculate the absolute value of dlibMove ... */
562 dlibMove.s.HighPart = -dlibMove.s.HighPart;
563 dlibMove.s.LowPart ^= -1;
564 /* ... and subtract with carry */
565 if (dlibMove.s.LowPart > plibNewPosition->s.LowPart) {
566 /* carry needed, This accounts for any underflows at [1]*/
567 plibNewPosition->s.HighPart -= 1;
568 }
569 plibNewPosition->s.LowPart -= dlibMove.s.LowPart; /* [1] */
570 plibNewPosition->s.HighPart -= dlibMove.s.HighPart;
571 } else {
572 /* add directly */
573 int initialLowPart = plibNewPosition->s.LowPart;
574 plibNewPosition->s.LowPart += dlibMove.s.LowPart;
575 if((plibNewPosition->s.LowPart < initialLowPart) ||
576 (plibNewPosition->s.LowPart < dlibMove.s.LowPart)) {
577 /* LowPart has rolled over => add the carry digit to HighPart */
578 plibNewPosition->s.HighPart++;
579 }
580 plibNewPosition->s.HighPart += dlibMove.s.HighPart;
581 }
582 /*
583 * Check if we end-up before the beginning of the file. That should
584 * trigger an error.
585 */
586 if (plibNewPosition->s.HighPart < 0) {
587 return STG_E_INVALIDPOINTER;
588 }
589
590 /*
591 * We currently don't support files with offsets of >32 bits.
592 * Note that we have checked for a negative offset already
593 */
594 assert(plibNewPosition->s.HighPart <= 0);
595
596#else
597 plibNewPosition->QuadPart = RtlLargeIntegerAdd( plibNewPosition->QuadPart, dlibMove.QuadPart );
598#endif
599
600 /*
601 * tell the caller what we calculated
602 */
603 This->currentPosition = *plibNewPosition;
604
605 return S_OK;
606}
607
608/***
609 * This method is part of the IStream interface.
610 *
611 * It will change the size of a stream.
612 *
613 * TODO: Switch from small blocks to big blocks and vice versa.
614 *
615 * See the documentation of IStream for more info.
616 */
617HRESULT WINAPI StgStreamImpl_SetSize(
618 IStream* iface,
619 ULARGE_INTEGER libNewSize) /* [in] */
620{
621 StgStreamImpl* const This=(StgStreamImpl*)iface;
622
623 StgProperty curProperty;
624 BOOL Success;
625
626 TRACE("(%p, %ld)\n", iface, libNewSize.s.LowPart);
627
628 /*
629 * As documented.
630 */
631 if (libNewSize.s.HighPart != 0)
632 return STG_E_INVALIDFUNCTION;
633
634 /*
635 * Do we have permission?
636 */
637 if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
638 return STG_E_ACCESSDENIED;
639
640 if (This->streamSize.s.LowPart == libNewSize.s.LowPart)
641 return S_OK;
642
643 /*
644 * This will happen if we're creating a stream
645 */
646 if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0))
647 {
648 if (libNewSize.s.LowPart < LIMIT_TO_USE_SMALL_BLOCK)
649 {
650 This->smallBlockChain = SmallBlockChainStream_Construct(
651 This->parentStorage->ancestorStorage,
652 This->ownerProperty);
653 }
654 else
655 {
656 This->bigBlockChain = BlockChainStream_Construct(
657 This->parentStorage->ancestorStorage,
658 NULL,
659 This->ownerProperty);
660 }
661 }
662
663 /*
664 * Read this stream's property to see if it's small blocks or big blocks
665 */
666 Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
667 This->ownerProperty,
668 &curProperty);
669 /*
670 * Determine if we have to switch from small to big blocks or vice versa
671 */
672 if ( (This->smallBlockChain!=0) &&
673 (curProperty.size.s.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
674 {
675 if (libNewSize.s.LowPart >= LIMIT_TO_USE_SMALL_BLOCK)
676 {
677 /*
678 * Transform the small block chain into a big block chain
679 */
680 This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks(
681 This->parentStorage->ancestorStorage,
682 &This->smallBlockChain);
683 }
684 }
685
686 if (This->smallBlockChain!=0)
687 {
688 Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize);
689 }
690 else
691 {
692 Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize);
693 }
694
695 /*
696 * Write the new information about this stream to the property
697 */
698 Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
699 This->ownerProperty,
700 &curProperty);
701
702 curProperty.size.s.HighPart = libNewSize.s.HighPart;
703 curProperty.size.s.LowPart = libNewSize.s.LowPart;
704
705 if (Success)
706 {
707 StorageImpl_WriteProperty(This->parentStorage->ancestorStorage,
708 This->ownerProperty,
709 &curProperty);
710 }
711
712 This->streamSize = libNewSize;
713
714 return S_OK;
715}
716
717/***
718 * This method is part of the IStream interface.
719 *
720 * It will copy the 'cb' Bytes to 'pstm' IStream.
721 *
722 * See the documentation of IStream for more info.
723 */
724HRESULT WINAPI StgStreamImpl_CopyTo(
725 IStream* iface,
726 IStream* pstm, /* [unique][in] */
727 ULARGE_INTEGER cb, /* [in] */
728 ULARGE_INTEGER* pcbRead, /* [out] */
729 ULARGE_INTEGER* pcbWritten) /* [out] */
730{
731 HRESULT hr = S_OK;
732 BYTE tmpBuffer[128];
733 ULONG bytesRead, bytesWritten, copySize;
734 ULARGE_INTEGER totalBytesRead;
735 ULARGE_INTEGER totalBytesWritten;
736
737 TRACE("(%p, %p, %ld, %p, %p)\n",
738 iface, pstm, cb.s.LowPart, pcbRead, pcbWritten);
739
740 /*
741 * Sanity check
742 */
743 if ( pstm == 0 )
744 return STG_E_INVALIDPOINTER;
745
746 totalBytesRead.s.LowPart = totalBytesRead.s.HighPart = 0;
747 totalBytesWritten.s.LowPart = totalBytesWritten.s.HighPart = 0;
748
749 /*
750 * use stack to store data temporarily
751 * there is surely a more performant way of doing it, for now this basic
752 * implementation will do the job
753 */
754 while ( cb.s.LowPart > 0 )
755 {
756 if ( cb.s.LowPart >= 128 )
757 copySize = 128;
758 else
759 copySize = cb.s.LowPart;
760
761 IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
762
763 totalBytesRead.s.LowPart += bytesRead;
764
765 IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
766
767 totalBytesWritten.s.LowPart += bytesWritten;
768
769 /*
770 * Check that read & write operations were successful
771 */
772 if (bytesRead != bytesWritten)
773 {
774 hr = STG_E_MEDIUMFULL;
775 break;
776 }
777
778 if (bytesRead!=copySize)
779 cb.s.LowPart = 0;
780 else
781 cb.s.LowPart -= bytesRead;
782 }
783
784 /*
785 * Update number of bytes read and written
786 */
787 if (pcbRead)
788 {
789 pcbRead->s.LowPart = totalBytesRead.s.LowPart;
790 pcbRead->s.HighPart = totalBytesRead.s.HighPart;
791 }
792
793 if (pcbWritten)
794 {
795 pcbWritten->s.LowPart = totalBytesWritten.s.LowPart;
796 pcbWritten->s.HighPart = totalBytesWritten.s.HighPart;
797 }
798 return hr;
799}
800
801/***
802 * This method is part of the IStream interface.
803 *
804 * For streams contained in structured storages, this method
805 * does nothing. This is what the documentation tells us.
806 *
807 * See the documentation of IStream for more info.
808 */
809HRESULT WINAPI StgStreamImpl_Commit(
810 IStream* iface,
811 DWORD grfCommitFlags) /* [in] */
812{
813 return S_OK;
814}
815
816/***
817 * This method is part of the IStream interface.
818 *
819 * For streams contained in structured storages, this method
820 * does nothing. This is what the documentation tells us.
821 *
822 * See the documentation of IStream for more info.
823 */
824HRESULT WINAPI StgStreamImpl_Revert(
825 IStream* iface)
826{
827 return S_OK;
828}
829
830HRESULT WINAPI StgStreamImpl_LockRegion(
831 IStream* iface,
832 ULARGE_INTEGER libOffset, /* [in] */
833 ULARGE_INTEGER cb, /* [in] */
834 DWORD dwLockType) /* [in] */
835{
836 FIXME("not implemented!\n");
837 return E_NOTIMPL;
838}
839
840HRESULT WINAPI StgStreamImpl_UnlockRegion(
841 IStream* iface,
842 ULARGE_INTEGER libOffset, /* [in] */
843 ULARGE_INTEGER cb, /* [in] */
844 DWORD dwLockType) /* [in] */
845{
846 FIXME("not implemented!\n");
847 return E_NOTIMPL;
848}
849
850/***
851 * This method is part of the IStream interface.
852 *
853 * This method returns information about the current
854 * stream.
855 *
856 * See the documentation of IStream for more info.
857 */
858HRESULT WINAPI StgStreamImpl_Stat(
859 IStream* iface,
860 STATSTG* pstatstg, /* [out] */
861 DWORD grfStatFlag) /* [in] */
862{
863 StgStreamImpl* const This=(StgStreamImpl*)iface;
864
865 StgProperty curProperty;
866 BOOL readSucessful;
867
868 /*
869 * Read the information from the property.
870 */
871 readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
872 This->ownerProperty,
873 &curProperty);
874
875 if (readSucessful)
876 {
877 StorageUtl_CopyPropertyToSTATSTG(pstatstg,
878 &curProperty,
879 grfStatFlag);
880
881 pstatstg->grfMode = This->grfMode;
882
883 return S_OK;
884 }
885
886 return E_FAIL;
887}
888
889/***
890 * This method is part of the IStream interface.
891 *
892 * This method returns a clone of the interface that allows for
893 * another seek pointer
894 *
895 * See the documentation of IStream for more info.
896 *
897 * I am not totally sure what I am doing here but I presume that this
898 * should be basically as simple as creating a new stream with the same
899 * parent etc and positioning its seek cursor.
900 */
901HRESULT WINAPI StgStreamImpl_Clone(
902 IStream* iface,
903 IStream** ppstm) /* [out] */
904{
905 StgStreamImpl* const This=(StgStreamImpl*)iface;
906 HRESULT hres;
907 StgStreamImpl* new_stream;
908 LARGE_INTEGER seek_pos;
909
910 /*
911 * Sanity check
912 */
913 if ( ppstm == 0 )
914 return STG_E_INVALIDPOINTER;
915
916 new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->ownerProperty);
917
918 if (!new_stream)
919 return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */
920
921 *ppstm = (IStream*) new_stream;
922 seek_pos.QuadPart = This->currentPosition.QuadPart;
923
924 hres=StgStreamImpl_Seek (*ppstm, seek_pos, STREAM_SEEK_SET, NULL);
925
926 assert (SUCCEEDED(hres));
927
928 return S_OK;
929}
Note: See TracBrowser for help on using the repository browser.