1 /******************************************************************************
5 * This is the implementation of a file that consists of blocks of
6 * a predetermined size.
7 * This class is used in the Compound File implementation of the
8 * IStorage and IStream interfaces. It provides the functionality
9 * to read and write any blocks in the file as well as setting and
10 * obtaining the size of the file.
11 * The blocks are indexed sequentially from the start of the file
15 * - Support for a transacted mode
17 * Copyright 1999 Thuy Nguyen
19 * This library is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU Lesser General Public
21 * License as published by the Free Software Foundation; either
22 * version 2.1 of the License, or (at your option) any later version.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
52 #include "storage32.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(storage
);
58 /***********************************************************
59 * Data structures used internally by the BigBlockFile
63 /* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */
64 #define PAGE_SIZE 131072
66 #define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE)
68 /* We keep a list of recently-discarded pages. This controls the
69 * size of that list. */
70 #define MAX_VICTIM_PAGES 16
72 /* This structure provides one bit for each block in a page.
73 * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */
76 unsigned int bits
[BLOCKS_PER_PAGE
/ (CHAR_BIT
* sizeof(unsigned int))];
80 * This structure identifies the paged that are mapped
81 * from the file and their position in memory. It is
82 * also used to hold a reference count to those pages.
84 * page_index identifies which PAGE_SIZE chunk from the
85 * file this mapping represents. (The mappings are always
98 BlockBits readable_blocks
;
99 BlockBits writable_blocks
;
102 /***********************************************************
103 * Prototypes for private methods
105 static void* BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This
,
107 static void BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This
,
109 static void BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This
);
110 static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This
);
111 static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This
);
112 static MappedPage
* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This
,
114 static DWORD
BIGBLOCKFILE_GetProtectMode(DWORD openFlags
);
115 static BOOL
BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This
, HANDLE hFile
);
116 static BOOL
BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This
, ILockBytes
* plkbyt
);
117 static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This
, MappedPage
*list
);
119 /* Note that this evaluates a and b multiple times, so don't
120 * pass expressions with side effects. */
121 #define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
123 /***********************************************************
124 * Blockbits functions.
126 static inline BOOL
BIGBLOCKFILE_TestBit(const BlockBits
*bb
,
129 unsigned int array_index
= index
/ (CHAR_BIT
* sizeof(unsigned int));
130 unsigned int bit_index
= index
% (CHAR_BIT
* sizeof(unsigned int));
132 return bb
->bits
[array_index
] & (1 << bit_index
);
135 static inline void BIGBLOCKFILE_SetBit(BlockBits
*bb
, unsigned int index
)
137 unsigned int array_index
= index
/ (CHAR_BIT
* sizeof(unsigned int));
138 unsigned int bit_index
= index
% (CHAR_BIT
* sizeof(unsigned int));
140 bb
->bits
[array_index
] |= (1 << bit_index
);
143 static inline void BIGBLOCKFILE_ClearBit(BlockBits
*bb
, unsigned int index
)
145 unsigned int array_index
= index
/ (CHAR_BIT
* sizeof(unsigned int));
146 unsigned int bit_index
= index
% (CHAR_BIT
* sizeof(unsigned int));
148 bb
->bits
[array_index
] &= ~(1 << bit_index
);
151 static inline void BIGBLOCKFILE_Zero(BlockBits
*bb
)
153 memset(bb
->bits
, 0, sizeof(bb
->bits
));
156 /******************************************************************************
157 * BIGBLOCKFILE_Construct
159 * Construct a big block file. Create the file mapping object.
160 * Create the read only mapped pages list, the writable mapped page list
161 * and the blocks in use list.
163 BigBlockFile
* BIGBLOCKFILE_Construct(
172 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BigBlockFile
));
177 This
->fileBased
= fileBased
;
179 This
->flProtect
= BIGBLOCKFILE_GetProtectMode(openFlags
);
181 This
->blocksize
= blocksize
;
183 This
->maplist
= NULL
;
184 This
->victimhead
= NULL
;
185 This
->victimtail
= NULL
;
186 This
->num_victim_pages
= 0;
190 if (!BIGBLOCKFILE_FileInit(This
, hFile
))
192 HeapFree(GetProcessHeap(), 0, This
);
198 if (!BIGBLOCKFILE_MemInit(This
, pLkByt
))
200 HeapFree(GetProcessHeap(), 0, This
);
208 /******************************************************************************
209 * BIGBLOCKFILE_FileInit
211 * Initialize a big block object supported by a file.
213 static BOOL
BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This
, HANDLE hFile
)
216 This
->hbytearray
= 0;
217 This
->pbytearray
= NULL
;
221 if (This
->hfile
== INVALID_HANDLE_VALUE
)
224 This
->filesize
.u
.LowPart
= GetFileSize(This
->hfile
,
225 &This
->filesize
.u
.HighPart
);
227 if( This
->filesize
.u
.LowPart
|| This
->filesize
.u
.HighPart
)
229 /* create the file mapping object
231 This
->hfilemap
= CreateFileMappingA(This
->hfile
,
239 CloseHandle(This
->hfile
);
244 This
->hfilemap
= NULL
;
246 This
->maplist
= NULL
;
248 TRACE("file len %u\n", This
->filesize
.u
.LowPart
);
253 /******************************************************************************
254 * BIGBLOCKFILE_MemInit
256 * Initialize a big block object supported by an ILockBytes on HGLOABL.
258 static BOOL
BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This
, ILockBytes
* plkbyt
)
264 * Retrieve the handle to the byte array from the LockByte object.
266 if (GetHGlobalFromILockBytes(plkbyt
, &(This
->hbytearray
)) != S_OK
)
268 FIXME("May not be an ILockBytes on HGLOBAL\n");
272 This
->pLkbyt
= plkbyt
;
275 * Increment the reference count of the ILockByte object since
276 * we're keeping a reference to it.
278 ILockBytes_AddRef(This
->pLkbyt
);
280 This
->filesize
.u
.LowPart
= GlobalSize(This
->hbytearray
);
281 This
->filesize
.u
.HighPart
= 0;
283 This
->pbytearray
= GlobalLock(This
->hbytearray
);
285 TRACE("mem on %p len %u\n", This
->pbytearray
, This
->filesize
.u
.LowPart
);
290 /******************************************************************************
291 * BIGBLOCKFILE_Destructor
293 * Destructor. Clean up, free memory.
295 void BIGBLOCKFILE_Destructor(
298 BIGBLOCKFILE_FreeAllMappedPages(This
);
302 CloseHandle(This
->hfilemap
);
303 CloseHandle(This
->hfile
);
307 GlobalUnlock(This
->hbytearray
);
308 ILockBytes_Release(This
->pLkbyt
);
313 HeapFree(GetProcessHeap(), 0, This
);
316 /******************************************************************************
317 * BIGBLOCKFILE_EnsureExists
319 * Grows the file if necessary to make sure the block is valid.
321 void BIGBLOCKFILE_EnsureExists(LPBIGBLOCKFILE This
, ULONG index
)
324 * block index starts at -1
325 * translate to zero based index
327 if (index
== 0xffffffff)
333 * make sure that the block physically exists
335 if ((This
->blocksize
* (index
+ 1)) > This
->filesize
.u
.LowPart
)
337 ULARGE_INTEGER newSize
;
339 newSize
.u
.HighPart
= 0;
340 newSize
.u
.LowPart
= This
->blocksize
* (index
+ 1);
342 BIGBLOCKFILE_SetSize(This
, newSize
);
346 /******************************************************************************
347 * BIGBLOCKFILE_SetSize
349 * Sets the size of the file.
352 void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This
, ULARGE_INTEGER newSize
)
354 if (This
->filesize
.u
.LowPart
== newSize
.u
.LowPart
)
357 TRACE("from %u to %u\n", This
->filesize
.u
.LowPart
, newSize
.u
.LowPart
);
359 * unmap all views, must be done before call to SetEndFile
361 * Just ditch the victim list because there is no guarentee we will need them
362 * and it is not worth the performance hit to unmap and remap them all.
364 BIGBLOCKFILE_DeleteList(This
, This
->victimhead
);
365 This
->victimhead
= NULL
;
366 This
->victimtail
= NULL
;
367 This
->num_victim_pages
= 0;
369 BIGBLOCKFILE_UnmapAllMappedPages(This
);
373 LARGE_INTEGER newpos
;
375 newpos
.QuadPart
= newSize
.QuadPart
;
376 if (SetFilePointerEx(This
->hfile
, newpos
, NULL
, FILE_BEGIN
))
378 if( This
->hfilemap
) CloseHandle(This
->hfilemap
);
380 SetEndOfFile(This
->hfile
);
383 * re-create the file mapping object
385 This
->hfilemap
= CreateFileMappingA(This
->hfile
,
394 GlobalUnlock(This
->hbytearray
);
397 * Resize the byte array object.
399 ILockBytes_SetSize(This
->pLkbyt
, newSize
);
402 * Re-acquire the handle, it may have changed.
404 GetHGlobalFromILockBytes(This
->pLkbyt
, &This
->hbytearray
);
405 This
->pbytearray
= GlobalLock(This
->hbytearray
);
408 This
->filesize
.u
.LowPart
= newSize
.u
.LowPart
;
409 This
->filesize
.u
.HighPart
= newSize
.u
.HighPart
;
411 BIGBLOCKFILE_RemapAllMappedPages(This
);
414 /******************************************************************************
415 * BIGBLOCKFILE_GetSize
417 * Returns the size of the file.
420 ULARGE_INTEGER
BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This
)
422 return This
->filesize
;
425 /******************************************************************************
426 * BIGBLOCKFILE_FindPageInList [PRIVATE]
429 static MappedPage
*BIGBLOCKFILE_FindPageInList(MappedPage
*head
,
432 for (; head
!= NULL
; head
= head
->next
)
434 if (head
->page_index
== page_index
)
436 InterlockedIncrement(&head
->refcnt
);
445 static void BIGBLOCKFILE_UnlinkPage(MappedPage
*page
)
447 if (page
->next
) page
->next
->prev
= page
->prev
;
448 if (page
->prev
) page
->prev
->next
= page
->next
;
451 static void BIGBLOCKFILE_LinkHeadPage(MappedPage
**head
, MappedPage
*page
)
453 if (*head
) (*head
)->prev
= page
;
459 /******************************************************************************
460 * BIGBLOCKFILE_GetMappedView [PRIVATE]
462 * Gets the page requested if it is already mapped.
463 * If it's not already mapped, this method will map it
465 static void * BIGBLOCKFILE_GetMappedView(
471 page
= BIGBLOCKFILE_FindPageInList(This
->maplist
, page_index
);
474 page
= BIGBLOCKFILE_FindPageInList(This
->victimhead
, page_index
);
477 This
->num_victim_pages
--;
479 BIGBLOCKFILE_Zero(&page
->readable_blocks
);
480 BIGBLOCKFILE_Zero(&page
->writable_blocks
);
486 /* If the page is not already at the head of the list, move
487 * it there. (Also moves pages from victim to main list.) */
488 if (This
->maplist
!= page
)
490 if (This
->victimhead
== page
) This
->victimhead
= page
->next
;
491 if (This
->victimtail
== page
) This
->victimtail
= page
->prev
;
493 BIGBLOCKFILE_UnlinkPage(page
);
495 BIGBLOCKFILE_LinkHeadPage(&This
->maplist
, page
);
501 page
= BIGBLOCKFILE_CreatePage(This
, page_index
);
502 if (!page
) return NULL
;
504 BIGBLOCKFILE_LinkHeadPage(&This
->maplist
, page
);
509 static BOOL
BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This
, MappedPage
*page
)
511 DWORD lowoffset
= PAGE_SIZE
* page
->page_index
;
516 DWORD desired_access
;
518 if( !This
->hfilemap
)
521 if (lowoffset
+ PAGE_SIZE
> This
->filesize
.u
.LowPart
)
522 numBytesToMap
= This
->filesize
.u
.LowPart
- lowoffset
;
524 numBytesToMap
= PAGE_SIZE
;
526 if (This
->flProtect
== PAGE_READONLY
)
527 desired_access
= FILE_MAP_READ
;
529 desired_access
= FILE_MAP_WRITE
;
531 page
->lpBytes
= MapViewOfFile(This
->hfilemap
, desired_access
, 0,
532 lowoffset
, numBytesToMap
);
533 page
->mapped_bytes
= numBytesToMap
;
537 page
->lpBytes
= (LPBYTE
)This
->pbytearray
+ lowoffset
;
538 page
->mapped_bytes
= PAGE_SIZE
;
541 TRACE("mapped page %u to %p\n", page
->page_index
, page
->lpBytes
);
543 return page
->lpBytes
!= NULL
;
546 static MappedPage
*BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This
,
551 page
= HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage
));
555 page
->page_index
= page_index
;
561 if (!BIGBLOCKFILE_MapPage(This
, page
))
563 HeapFree(GetProcessHeap(),0,page
);
567 BIGBLOCKFILE_Zero(&page
->readable_blocks
);
568 BIGBLOCKFILE_Zero(&page
->writable_blocks
);
573 static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This
, MappedPage
*page
)
575 TRACE("%d at %p\n", page
->page_index
, page
->lpBytes
);
576 if (page
->refcnt
> 0)
577 ERR("unmapping inuse page %p\n", page
->lpBytes
);
579 if (This
->fileBased
&& page
->lpBytes
)
580 UnmapViewOfFile(page
->lpBytes
);
582 page
->lpBytes
= NULL
;
585 static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This
, MappedPage
*page
)
587 BIGBLOCKFILE_UnmapPage(This
, page
);
589 HeapFree(GetProcessHeap(), 0, page
);
592 /******************************************************************************
593 * BIGBLOCKFILE_ReleaseMappedPage [PRIVATE]
595 * Decrements the reference count of the mapped page.
597 static void BIGBLOCKFILE_ReleaseMappedPage(
601 assert(This
!= NULL
);
602 assert(page
!= NULL
);
604 /* If the page is no longer refenced, move it to the victim list.
605 * If the victim list is too long, kick somebody off. */
606 if (!InterlockedDecrement(&page
->refcnt
))
608 if (This
->maplist
== page
) This
->maplist
= page
->next
;
610 BIGBLOCKFILE_UnlinkPage(page
);
612 if (MAX_VICTIM_PAGES
> 0)
614 if (This
->num_victim_pages
>= MAX_VICTIM_PAGES
)
616 MappedPage
*victim
= This
->victimtail
;
619 This
->victimtail
= victim
->prev
;
620 if (This
->victimhead
== victim
)
621 This
->victimhead
= victim
->next
;
623 BIGBLOCKFILE_UnlinkPage(victim
);
624 BIGBLOCKFILE_DeletePage(This
, victim
);
627 else This
->num_victim_pages
++;
629 BIGBLOCKFILE_LinkHeadPage(&This
->victimhead
, page
);
630 if (This
->victimtail
== NULL
) This
->victimtail
= page
;
633 BIGBLOCKFILE_DeletePage(This
, page
);
637 static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This
, MappedPage
*list
)
641 MappedPage
*next
= list
->next
;
643 BIGBLOCKFILE_DeletePage(This
, list
);
649 /******************************************************************************
650 * BIGBLOCKFILE_FreeAllMappedPages [PRIVATE]
652 * Unmap all currently mapped pages.
653 * Empty mapped pages list.
655 static void BIGBLOCKFILE_FreeAllMappedPages(
658 BIGBLOCKFILE_DeleteList(This
, This
->maplist
);
659 BIGBLOCKFILE_DeleteList(This
, This
->victimhead
);
661 This
->maplist
= NULL
;
662 This
->victimhead
= NULL
;
663 This
->victimtail
= NULL
;
664 This
->num_victim_pages
= 0;
667 static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This
, MappedPage
*list
)
669 for (; list
!= NULL
; list
= list
->next
)
671 BIGBLOCKFILE_UnmapPage(This
, list
);
675 static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This
)
677 BIGBLOCKFILE_UnmapList(This
, This
->maplist
);
678 BIGBLOCKFILE_UnmapList(This
, This
->victimhead
);
681 static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This
, MappedPage
*list
)
685 MappedPage
*next
= list
->next
;
687 if (list
->page_index
* PAGE_SIZE
> This
->filesize
.u
.LowPart
)
689 TRACE("discarding %u\n", list
->page_index
);
691 /* page is entirely outside of the file, delete it */
692 BIGBLOCKFILE_UnlinkPage(list
);
693 BIGBLOCKFILE_DeletePage(This
, list
);
697 /* otherwise, remap it */
698 BIGBLOCKFILE_MapPage(This
, list
);
705 static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This
)
707 BIGBLOCKFILE_RemapList(This
, This
->maplist
);
708 BIGBLOCKFILE_RemapList(This
, This
->victimhead
);
711 /****************************************************************************
712 * BIGBLOCKFILE_GetProtectMode
714 * This function will return a protection mode flag for a file-mapping object
715 * from the open flags of a file.
717 static DWORD
BIGBLOCKFILE_GetProtectMode(DWORD openFlags
)
719 switch(STGM_ACCESS_MODE(openFlags
))
723 return PAGE_READWRITE
;
725 return PAGE_READONLY
;
729 /* ILockByte Interfaces */
731 /******************************************************************************
732 * This method is part of the ILockBytes interface.
734 * It reads a block of information from the byte array at the specified
737 * See the documentation of ILockBytes for more info.
739 static HRESULT WINAPI
ImplBIGBLOCKFILE_ReadAt(
740 BigBlockFile
* const This
,
741 ULARGE_INTEGER ulOffset
, /* [in] */
742 void* pv
, /* [length_is][size_is][out] */
744 ULONG
* pcbRead
) /* [out] */
746 ULONG first_page
= ulOffset
.u
.LowPart
/ PAGE_SIZE
;
747 ULONG offset_in_page
= ulOffset
.u
.LowPart
% PAGE_SIZE
;
748 ULONG bytes_left
= cb
;
749 ULONG page_index
= first_page
;
750 ULONG bytes_from_page
;
751 LPVOID writePtr
= pv
;
755 TRACE("(%p)-> %i %p %i %p\n",This
, ulOffset
.u
.LowPart
, pv
, cb
, pcbRead
);
757 /* verify a sane environment */
758 if (!This
) return E_FAIL
;
760 if (offset_in_page
+ bytes_left
> PAGE_SIZE
)
761 bytes_from_page
= PAGE_SIZE
- offset_in_page
;
763 bytes_from_page
= bytes_left
;
772 MappedPage
*page
= BIGBLOCKFILE_GetMappedView(This
, page_index
);
774 if (!page
|| !page
->lpBytes
)
776 rc
= STG_E_READFAULT
;
780 TRACE("page %i, offset %u, bytes_from_page %u, bytes_left %u\n",
781 page
->page_index
, offset_in_page
, bytes_from_page
, bytes_left
);
783 if (page
->mapped_bytes
< bytes_from_page
)
786 bytes_from_page
= page
->mapped_bytes
;
789 readPtr
= (BYTE
*)page
->lpBytes
+ offset_in_page
;
790 memcpy(writePtr
,readPtr
,bytes_from_page
);
791 BIGBLOCKFILE_ReleaseMappedPage(This
, page
);
794 *pcbRead
+= bytes_from_page
;
795 bytes_left
-= bytes_from_page
;
797 if (bytes_left
&& !eof
)
799 writePtr
= (LPBYTE
)writePtr
+ bytes_from_page
;
802 if (bytes_left
> PAGE_SIZE
)
803 bytes_from_page
= PAGE_SIZE
;
805 bytes_from_page
= bytes_left
;
809 rc
= STG_E_READFAULT
;
818 /******************************************************************************
819 * This method is part of the ILockBytes interface.
821 * It writes the specified bytes at the specified offset.
822 * position. If the file is too small, it will be resized.
824 * See the documentation of ILockBytes for more info.
826 static HRESULT WINAPI
ImplBIGBLOCKFILE_WriteAt(
827 BigBlockFile
* const This
,
828 ULARGE_INTEGER ulOffset
, /* [in] */
829 const void* pv
, /* [size_is][in] */
831 ULONG
* pcbWritten
) /* [out] */
833 ULONG size_needed
= ulOffset
.u
.LowPart
+ cb
;
834 ULONG first_page
= ulOffset
.u
.LowPart
/ PAGE_SIZE
;
835 ULONG offset_in_page
= ulOffset
.u
.LowPart
% PAGE_SIZE
;
836 ULONG bytes_left
= cb
;
837 ULONG page_index
= first_page
;
839 LPCVOID readPtr
= pv
;
843 TRACE("(%p)-> %i %p %i %p\n",This
, ulOffset
.u
.LowPart
, pv
, cb
, pcbWritten
);
845 /* verify a sane environment */
846 if (!This
) return E_FAIL
;
848 if (This
->flProtect
!= PAGE_READWRITE
)
849 return STG_E_ACCESSDENIED
;
851 if (size_needed
> This
->filesize
.u
.LowPart
)
853 ULARGE_INTEGER newSize
;
854 newSize
.u
.HighPart
= 0;
855 newSize
.u
.LowPart
= size_needed
;
856 BIGBLOCKFILE_SetSize(This
, newSize
);
859 if (offset_in_page
+ bytes_left
> PAGE_SIZE
)
860 bytes_to_page
= PAGE_SIZE
- offset_in_page
;
862 bytes_to_page
= bytes_left
;
870 MappedPage
*page
= BIGBLOCKFILE_GetMappedView(This
, page_index
);
872 TRACE("page %i, offset %u, bytes_to_page %u, bytes_left %u\n",
873 page
? page
->page_index
: 0, offset_in_page
, bytes_to_page
, bytes_left
);
877 ERR("Unable to get a page to write. This should never happen\n");
882 if (page
->mapped_bytes
< bytes_to_page
)
884 ERR("Not enough bytes mapped to the page. This should never happen\n");
889 writePtr
= (BYTE
*)page
->lpBytes
+ offset_in_page
;
890 memcpy(writePtr
,readPtr
,bytes_to_page
);
891 BIGBLOCKFILE_ReleaseMappedPage(This
, page
);
894 *pcbWritten
+= bytes_to_page
;
895 bytes_left
-= bytes_to_page
;
899 readPtr
= (const BYTE
*)readPtr
+ bytes_to_page
;
902 if (bytes_left
> PAGE_SIZE
)
903 bytes_to_page
= PAGE_SIZE
;
905 bytes_to_page
= bytes_left
;
913 HRESULT
BIGBLOCKFILE_ReadAt(LPBIGBLOCKFILE This
, ULARGE_INTEGER offset
,
914 void* buffer
, ULONG size
, ULONG
* bytesRead
)
917 return ImplBIGBLOCKFILE_ReadAt(This
,offset
,buffer
,size
,bytesRead
);
919 return ILockBytes_ReadAt(This
->pLkbyt
,offset
,buffer
,size
,bytesRead
);
922 HRESULT
BIGBLOCKFILE_WriteAt(LPBIGBLOCKFILE This
, ULARGE_INTEGER offset
,
923 const void* buffer
, ULONG size
, ULONG
* bytesRead
)
926 return ImplBIGBLOCKFILE_WriteAt(This
,offset
,buffer
,size
,bytesRead
);
928 return ILockBytes_WriteAt(This
->pLkbyt
,offset
,buffer
,size
,bytesRead
);