xref: /aoo41x/main/store/source/lockbyte.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_store.hxx"
30 
31 #include "lockbyte.hxx"
32 
33 #include "sal/types.h"
34 #include "osl/diagnose.h"
35 #include "osl/file.h"
36 #include "osl/process.h"
37 #include "rtl/alloc.h"
38 #include "rtl/ustring.hxx"
39 
40 #include "object.hxx"
41 #include "storbase.hxx"
42 
43 #ifndef INCLUDED_STRING_H
44 #include <string.h>
45 #define INCLUDED_STRING_H
46 #endif
47 
48 using namespace store;
49 
50 /*========================================================================
51  *
52  * ILockBytes (non-virtual interface) implementation.
53  *
54  *======================================================================*/
55 
56 storeError ILockBytes::initialize (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
57 {
58     OSL_PRECOND((STORE_MINIMUM_PAGESIZE <= nPageSize) && (nPageSize <= STORE_MAXIMUM_PAGESIZE), "invalid PageSize");
59     return initialize_Impl (rxAllocator, nPageSize);
60 }
61 
62 storeError ILockBytes::readPageAt (PageHolder & rPage, sal_uInt32 nOffset)
63 {
64     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readPageAt(): invalid Offset");
65     if (nOffset == STORE_PAGE_NULL)
66         return store_E_CantSeek;
67 
68     return readPageAt_Impl (rPage, nOffset);
69 }
70 
71 storeError ILockBytes::writePageAt (PageHolder const & rPage, sal_uInt32 nOffset)
72 {
73     // [SECURITY:ValInput]
74     PageData const * pagedata = rPage.get();
75     OSL_PRECOND(!(pagedata == 0), "store::ILockBytes::writePageAt(): invalid Page");
76     if (pagedata == 0)
77         return store_E_InvalidParameter;
78 
79     sal_uInt32 const offset = pagedata->location();
80     OSL_PRECOND(!(nOffset != offset), "store::ILockBytes::writePageAt(): inconsistent Offset");
81     if (nOffset != offset)
82         return store_E_InvalidParameter;
83 
84     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writePageAt(): invalid Offset");
85     if (nOffset == STORE_PAGE_NULL)
86         return store_E_CantSeek;
87 
88     return writePageAt_Impl (rPage, nOffset);
89 }
90 
91 storeError ILockBytes::readAt (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
92 {
93     // [SECURITY:ValInput]
94     sal_uInt8 * dst_lo = static_cast<sal_uInt8*>(pBuffer);
95     if (!(dst_lo != 0))
96         return store_E_InvalidParameter;
97 
98     sal_uInt8 * dst_hi = dst_lo + nBytes;
99     if (!(dst_lo < dst_hi))
100         return (dst_lo > dst_hi) ? store_E_InvalidParameter : store_E_None;
101 
102     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readAt(): invalid Offset");
103     if (nOffset == STORE_PAGE_NULL)
104         return store_E_CantSeek;
105 
106     sal_uInt64 const src_size = nOffset + nBytes;
107     if (src_size > SAL_MAX_UINT32)
108         return store_E_CantSeek;
109 
110     return readAt_Impl (nOffset, dst_lo, (dst_hi - dst_lo));
111 }
112 
113 storeError ILockBytes::writeAt (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes)
114 {
115     // [SECURITY:ValInput]
116     sal_uInt8 const * src_lo = static_cast<sal_uInt8 const*>(pBuffer);
117     if (!(src_lo != 0))
118         return store_E_InvalidParameter;
119 
120     sal_uInt8 const * src_hi = src_lo + nBytes;
121     if (!(src_lo < src_hi))
122         return (src_lo > src_hi) ? store_E_InvalidParameter : store_E_None;
123 
124     OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writeAt(): invalid Offset");
125     if (nOffset == STORE_PAGE_NULL)
126         return store_E_CantSeek;
127 
128     sal_uInt64 const dst_size = nOffset + nBytes;
129     if (dst_size > SAL_MAX_UINT32)
130         return store_E_CantSeek;
131 
132     return writeAt_Impl (nOffset, src_lo, (src_hi - src_lo));
133 }
134 
135 storeError ILockBytes::getSize (sal_uInt32 & rnSize)
136 {
137     rnSize = 0;
138     return getSize_Impl (rnSize);
139 }
140 
141 storeError ILockBytes::setSize (sal_uInt32 nSize)
142 {
143     return setSize_Impl (nSize);
144 }
145 
146 storeError ILockBytes::flush()
147 {
148     return flush_Impl();
149 }
150 
151 /*========================================================================
152  *
153  * FileLockBytes implementation.
154  *
155  *======================================================================*/
156 namespace store
157 {
158 
159 struct FileHandle
160 {
161     oslFileHandle m_handle;
162 
163     FileHandle() : m_handle(0) {}
164 
165     bool operator != (FileHandle const & rhs)
166     {
167         return (m_handle != rhs.m_handle);
168     }
169 
170     static storeError errorFromNative (oslFileError eErrno)
171     {
172         switch (eErrno)
173         {
174         case osl_File_E_None:
175             return store_E_None;
176 
177         case osl_File_E_NOENT:
178             return store_E_NotExists;
179 
180         case osl_File_E_ACCES:
181         case osl_File_E_PERM:
182             return store_E_AccessViolation;
183 
184         case osl_File_E_AGAIN:
185         case osl_File_E_DEADLK:
186             return store_E_LockingViolation;
187 
188         case osl_File_E_BADF:
189             return store_E_InvalidHandle;
190 
191         case osl_File_E_INVAL:
192             return store_E_InvalidParameter;
193 
194         case osl_File_E_NOMEM:
195             return store_E_OutOfMemory;
196 
197         case osl_File_E_NOSPC:
198             return store_E_OutOfSpace;
199 
200         case osl_File_E_OVERFLOW:
201             return store_E_CantSeek;
202 
203         default:
204             return store_E_Unknown;
205         }
206     }
207 
208     static sal_uInt32 modeToNative (storeAccessMode eAccessMode)
209     {
210         sal_uInt32 nFlags = 0;
211         switch (eAccessMode)
212         {
213         case store_AccessCreate:
214         case store_AccessReadCreate:
215             nFlags |= osl_File_OpenFlag_Create;
216             // fall through
217         case store_AccessReadWrite:
218             nFlags |= osl_File_OpenFlag_Write;
219             // fall through
220         case store_AccessReadOnly:
221             nFlags |= osl_File_OpenFlag_Read;
222             break;
223         default:
224             OSL_PRECOND(0, "store::FileHandle: unknown storeAccessMode");
225         }
226         return nFlags;
227     }
228 
229     storeError initialize (rtl_uString * pFilename, storeAccessMode eAccessMode)
230     {
231         // Verify arguments.
232         sal_uInt32 nFlags = modeToNative (eAccessMode);
233         if (!pFilename || !nFlags)
234             return store_E_InvalidParameter;
235 
236         // Convert into FileUrl.
237         rtl::OUString aFileUrl;
238         if (osl_getFileURLFromSystemPath (pFilename, &(aFileUrl.pData)) != osl_File_E_None)
239         {
240             // Not system path. Assume file url.
241             rtl_uString_assign (&(aFileUrl.pData), pFilename);
242         }
243 		if (aFileUrl.compareToAscii("file://", 7) != 0)
244 		{
245 			// Not file url. Assume relative path.
246 			rtl::OUString aCwdUrl;
247 			(void) osl_getProcessWorkingDir (&(aCwdUrl.pData));
248 
249 			// Absolute file url.
250 			(void) osl_getAbsoluteFileURL (aCwdUrl.pData, aFileUrl.pData, &(aFileUrl.pData));
251 		}
252 
253         // Acquire handle.
254         oslFileError result = osl_openFile (aFileUrl.pData, &m_handle, nFlags);
255         if (result == osl_File_E_EXIST)
256         {
257             // Already existing (O_CREAT | O_EXCL).
258             result = osl_openFile (aFileUrl.pData, &m_handle, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write);
259             if ((result == osl_File_E_None) && (eAccessMode == store_AccessCreate))
260             {
261                 // Truncate existing file.
262                 result = osl_setFileSize (m_handle, 0);
263             }
264         }
265         if (result != osl_File_E_None)
266             return errorFromNative(result);
267         return store_E_None;
268     }
269 
270     /** @see FileLockBytes destructor
271      */
272     static void closeFile (oslFileHandle hFile)
273     {
274         (void) osl_closeFile (hFile);
275     }
276 
277     /** @see ResourceHolder<T>::destructor_type
278      */
279     struct CloseFile
280     {
281         void operator()(FileHandle & rFile) const
282         {
283             // Release handle.
284             closeFile (rFile.m_handle);
285             rFile.m_handle = 0;
286         }
287     };
288     typedef CloseFile destructor_type;
289 };
290 
291 class FileLockBytes :
292     public store::OStoreObject,
293     public store::ILockBytes
294 {
295     /** Representation.
296      */
297     oslFileHandle                         m_hFile;
298     sal_uInt32                            m_nSize;
299     rtl::Reference< PageData::Allocator > m_xAllocator;
300 
301     storeError initSize_Impl (sal_uInt32 & rnSize);
302 
303     /** ILockBytes implementation.
304      */
305     virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize);
306 
307     virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset);
308     virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset);
309 
310     virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes);
311     virtual storeError writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes);
312 
313     virtual storeError getSize_Impl (sal_uInt32 & rnSize);
314     virtual storeError setSize_Impl (sal_uInt32 nSize);
315 
316     virtual storeError flush_Impl();
317 
318     /** Not implemented.
319      */
320     FileLockBytes (FileLockBytes const &);
321     FileLockBytes & operator= (FileLockBytes const &);
322 
323 public:
324     /** Construction.
325      */
326     explicit FileLockBytes (FileHandle & rFile);
327 
328     /** Delegate multiple inherited IReference.
329      */
330     virtual oslInterlockedCount SAL_CALL acquire();
331     virtual oslInterlockedCount SAL_CALL release();
332 
333 protected:
334     /** Destruction.
335      */
336     virtual ~FileLockBytes();
337 };
338 
339 } // namespace store
340 
341 FileLockBytes::FileLockBytes (FileHandle & rFile)
342     : m_hFile (rFile.m_handle), m_nSize (SAL_MAX_UINT32), m_xAllocator()
343 {
344 }
345 
346 FileLockBytes::~FileLockBytes()
347 {
348     FileHandle::closeFile (m_hFile);
349 }
350 
351 oslInterlockedCount SAL_CALL FileLockBytes::acquire()
352 {
353     return OStoreObject::acquire();
354 }
355 
356 oslInterlockedCount SAL_CALL FileLockBytes::release()
357 {
358     return OStoreObject::release();
359 }
360 
361 storeError FileLockBytes::initSize_Impl (sal_uInt32 & rnSize)
362 {
363     /* osl_getFileSize() uses slow 'fstat(h, &size)',
364      * instead of fast 'size = lseek(h, 0, SEEK_END)'.
365      * so, init size here, and track changes.
366      */
367     sal_uInt64 uSize = 0;
368     oslFileError result = osl_getFileSize (m_hFile, &uSize);
369     if (result != osl_File_E_None)
370         return FileHandle::errorFromNative(result);
371     if (uSize > SAL_MAX_UINT32)
372         return store_E_CantSeek;
373 
374     rnSize = sal::static_int_cast<sal_uInt32>(uSize);
375     return store_E_None;
376 }
377 
378 storeError FileLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
379 {
380     storeError result = initSize_Impl (m_nSize);
381     if (result != store_E_None)
382         return (result);
383 
384     result = PageData::Allocator::createInstance (rxAllocator, nPageSize);
385     if (result != store_E_None)
386         return (result);
387 
388     // @see readPageAt_Impl().
389     m_xAllocator = rxAllocator;
390     return store_E_None;
391 }
392 
393 storeError FileLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset)
394 {
395     if (m_xAllocator.is())
396     {
397         PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator);
398         page.swap (rPage);
399     }
400 
401     if (!m_xAllocator.is())
402         return store_E_InvalidAccess;
403     if (!rPage.get())
404         return store_E_OutOfMemory;
405 
406     PageData * pagedata = rPage.get();
407     return readAt_Impl (nOffset, pagedata, pagedata->size());
408 }
409 
410 storeError FileLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset)
411 {
412     PageData const * pagedata = rPage.get();
413     OSL_PRECOND(pagedata != 0, "contract violation");
414     return writeAt_Impl (nOffset, pagedata, pagedata->size());
415 }
416 
417 storeError FileLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
418 {
419     sal_uInt64 nDone = 0;
420     oslFileError result = osl_readFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone);
421     if (result != osl_File_E_None)
422         return FileHandle::errorFromNative(result);
423     if (nDone != nBytes)
424         return (nDone != 0) ? store_E_CantRead : store_E_NotExists;
425     return store_E_None;
426 }
427 
428 storeError FileLockBytes::writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes)
429 {
430     sal_uInt64 nDone = 0;
431     oslFileError result = osl_writeFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone);
432     if (result != osl_File_E_None)
433         return FileHandle::errorFromNative(result);
434     if (nDone != nBytes)
435         return store_E_CantWrite;
436 
437     sal_uInt64 const uSize = nOffset + nBytes;
438     OSL_PRECOND(uSize < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation");
439     if (uSize > m_nSize)
440 		m_nSize = sal::static_int_cast<sal_uInt32>(uSize);
441     return store_E_None;
442 }
443 
444 storeError FileLockBytes::getSize_Impl (sal_uInt32 & rnSize)
445 {
446     rnSize = m_nSize;
447     return store_E_None;
448 }
449 
450 storeError FileLockBytes::setSize_Impl (sal_uInt32 nSize)
451 {
452     oslFileError result = osl_setFileSize (m_hFile, nSize);
453     if (result != osl_File_E_None)
454         return FileHandle::errorFromNative(result);
455 
456     m_nSize = nSize;
457     return store_E_None;
458 }
459 
460 storeError FileLockBytes::flush_Impl()
461 {
462     oslFileError result = osl_syncFile (m_hFile);
463     if (result != osl_File_E_None)
464         return FileHandle::errorFromNative(result);
465     return store_E_None;
466 }
467 
468 /*========================================================================
469  *
470  * MappedLockBytes implementation.
471  *
472  *======================================================================*/
473 namespace store
474 {
475 
476 struct FileMapping
477 {
478     sal_uInt8 * m_pAddr;
479     sal_uInt32  m_nSize;
480 
481     FileMapping() : m_pAddr(0), m_nSize(0) {}
482 
483     bool operator != (FileMapping const & rhs) const
484     {
485         return ((m_pAddr != rhs.m_pAddr) || (m_nSize != rhs.m_nSize));
486     }
487 
488     oslFileError initialize (oslFileHandle hFile)
489     {
490         // Determine mapping size.
491         sal_uInt64   uSize  = 0;
492         oslFileError result = osl_getFileSize (hFile, &uSize);
493         if (result != osl_File_E_None)
494             return result;
495 
496         // [SECURITY:IntOver]
497         if (uSize > SAL_MAX_UINT32)
498             return osl_File_E_OVERFLOW;
499         m_nSize = sal::static_int_cast<sal_uInt32>(uSize);
500 
501         // Acquire mapping.
502         return osl_mapFile (hFile, reinterpret_cast<void**>(&m_pAddr), m_nSize, 0, osl_File_MapFlag_RandomAccess);
503     }
504 
505     /** @see MappedLockBytes::destructor.
506      */
507     static void unmapFile (sal_uInt8 * pAddr, sal_uInt32 nSize)
508     {
509         (void) osl_unmapFile (pAddr, nSize);
510     }
511 
512     /** @see ResourceHolder<T>::destructor_type
513      */
514     struct UnmapFile
515     {
516         void operator ()(FileMapping & rMapping) const
517         {
518             // Release mapping.
519             unmapFile (rMapping.m_pAddr, rMapping.m_nSize);
520             rMapping.m_pAddr = 0, rMapping.m_nSize = 0;
521         }
522     };
523     typedef UnmapFile destructor_type;
524 };
525 
526 class MappedLockBytes :
527     public store::OStoreObject,
528     public store::PageData::Allocator,
529     public store::ILockBytes
530 {
531     /** Representation.
532      */
533     sal_uInt8 * m_pData;
534     sal_uInt32  m_nSize;
535     sal_uInt16  m_nPageSize;
536 
537     /** PageData::Allocator implementation.
538      */
539     virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize);
540     virtual void deallocate_Impl (void * pPage);
541 
542     /** ILockBytes implementation.
543      */
544     virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize);
545 
546     virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset);
547     virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset);
548 
549     virtual storeError readAt_Impl  (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes);
550     virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes);
551 
552     virtual storeError getSize_Impl (sal_uInt32 & rnSize);
553     virtual storeError setSize_Impl (sal_uInt32 nSize);
554 
555     virtual storeError flush_Impl();
556 
557     /** Not implemented.
558      */
559     MappedLockBytes (MappedLockBytes const &);
560     MappedLockBytes & operator= (MappedLockBytes const &);
561 
562 public:
563     /** Construction.
564      */
565     explicit MappedLockBytes (FileMapping & rMapping);
566 
567     /** Delegate multiple inherited IReference.
568      */
569     virtual oslInterlockedCount SAL_CALL acquire();
570     virtual oslInterlockedCount SAL_CALL release();
571 
572 protected:
573     /* Destruction.
574      */
575     virtual ~MappedLockBytes();
576 };
577 
578 } // namespace store
579 
580 MappedLockBytes::MappedLockBytes (FileMapping & rMapping)
581     : m_pData (rMapping.m_pAddr), m_nSize (rMapping.m_nSize), m_nPageSize(0)
582 {
583 }
584 
585 MappedLockBytes::~MappedLockBytes()
586 {
587     FileMapping::unmapFile (m_pData, m_nSize);
588 }
589 
590 oslInterlockedCount SAL_CALL MappedLockBytes::acquire()
591 {
592     return OStoreObject::acquire();
593 }
594 
595 oslInterlockedCount SAL_CALL MappedLockBytes::release()
596 {
597     return OStoreObject::release();
598 }
599 
600 void MappedLockBytes::allocate_Impl (void ** ppPage, sal_uInt16 * pnSize)
601 {
602     OSL_PRECOND((ppPage != 0) && (pnSize != 0), "contract violation");
603     if ((ppPage != 0) && (pnSize != 0))
604         *ppPage = 0, *pnSize = m_nPageSize;
605 }
606 
607 void MappedLockBytes::deallocate_Impl (void * pPage)
608 {
609     OSL_PRECOND((m_pData <= pPage) && (pPage < m_pData + m_nSize), "contract violation");
610     (void)pPage; // UNUSED
611 }
612 
613 storeError MappedLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
614 {
615     rxAllocator = this;
616     m_nPageSize = nPageSize;
617     return store_E_None;
618 }
619 
620 storeError MappedLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset)
621 {
622     sal_uInt8 * src_lo = m_pData + nOffset;
623     if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize))
624         return store_E_NotExists;
625 
626     sal_uInt8 * src_hi = src_lo + m_nPageSize;
627     if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize))
628         return store_E_CantRead;
629 
630     PageHolder page (reinterpret_cast< PageData* >(src_lo), static_cast< PageData::Allocator* >(this));
631     page.swap (rPage);
632 
633     return store_E_None;
634 }
635 
636 storeError MappedLockBytes::writePageAt_Impl (PageHolder const & /*rPage*/, sal_uInt32 /*nOffset*/)
637 {
638     return store_E_AccessViolation;
639 }
640 
641 storeError MappedLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
642 {
643     sal_uInt8 const * src_lo = m_pData + nOffset;
644     if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize))
645         return store_E_NotExists;
646 
647     sal_uInt8 const * src_hi = src_lo + nBytes;
648     if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize))
649         return store_E_CantRead;
650 
651     memcpy (pBuffer, src_lo, (src_hi - src_lo));
652     return store_E_None;
653 }
654 
655 storeError MappedLockBytes::writeAt_Impl (sal_uInt32 /*nOffset*/, void const * /*pBuffer*/, sal_uInt32 /*nBytes*/)
656 {
657     return store_E_AccessViolation;
658 }
659 
660 storeError MappedLockBytes::getSize_Impl (sal_uInt32 & rnSize)
661 {
662     rnSize = m_nSize;
663     return store_E_None;
664 }
665 
666 storeError MappedLockBytes::setSize_Impl (sal_uInt32 /*nSize*/)
667 {
668     return store_E_AccessViolation;
669 }
670 
671 storeError MappedLockBytes::flush_Impl()
672 {
673     return store_E_None;
674 }
675 
676 /*========================================================================
677  *
678  * MemoryLockBytes implementation.
679  *
680  *======================================================================*/
681 namespace store
682 {
683 
684 class MemoryLockBytes :
685     public store::OStoreObject,
686     public store::ILockBytes
687 {
688     /** Representation.
689      */
690     sal_uInt8 * m_pData;
691     sal_uInt32  m_nSize;
692     rtl::Reference< PageData::Allocator > m_xAllocator;
693 
694     /** ILockBytes implementation.
695      */
696     virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize);
697 
698     virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset);
699     virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset);
700 
701     virtual storeError readAt_Impl  (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes);
702     virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes);
703 
704     virtual storeError getSize_Impl (sal_uInt32 & rnSize);
705     virtual storeError setSize_Impl (sal_uInt32 nSize);
706 
707     virtual storeError flush_Impl();
708 
709     /** Not implemented.
710      */
711     MemoryLockBytes (MemoryLockBytes const &);
712     MemoryLockBytes& operator= (MemoryLockBytes const &);
713 
714 public:
715     /** Construction.
716      */
717     MemoryLockBytes();
718 
719     /** Delegate multiple inherited IReference.
720      */
721     virtual oslInterlockedCount SAL_CALL acquire();
722     virtual oslInterlockedCount SAL_CALL release();
723 
724 protected:
725     /** Destruction.
726      */
727     virtual ~MemoryLockBytes();
728 };
729 
730 } // namespace store
731 
732 MemoryLockBytes::MemoryLockBytes()
733     : m_pData (0), m_nSize (0), m_xAllocator()
734 {}
735 
736 MemoryLockBytes::~MemoryLockBytes()
737 {
738     rtl_freeMemory (m_pData);
739 }
740 
741 oslInterlockedCount SAL_CALL MemoryLockBytes::acquire (void)
742 {
743     return OStoreObject::acquire();
744 }
745 
746 oslInterlockedCount SAL_CALL MemoryLockBytes::release (void)
747 {
748     return OStoreObject::release();
749 }
750 
751 storeError MemoryLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
752 {
753     storeError result = PageData::Allocator::createInstance (rxAllocator, nPageSize);
754     if (result == store_E_None)
755     {
756         // @see readPageAt_Impl().
757         m_xAllocator = rxAllocator;
758     }
759     return result;
760 }
761 
762 storeError MemoryLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset)
763 {
764     if (m_xAllocator.is())
765     {
766         PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator);
767         page.swap (rPage);
768     }
769 
770     if (!m_xAllocator.is())
771         return store_E_InvalidAccess;
772     if (!rPage.get())
773         return store_E_OutOfMemory;
774 
775     PageData * pagedata = rPage.get();
776     return readAt_Impl (nOffset, pagedata, pagedata->size());
777 }
778 
779 storeError MemoryLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset)
780 {
781     PageData const * pagedata = rPage.get();
782     OSL_PRECOND(!(pagedata == 0), "contract violation");
783     return writeAt_Impl (nOffset, pagedata, pagedata->size());
784 }
785 
786 storeError MemoryLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
787 {
788     sal_uInt8 const * src_lo = m_pData + nOffset;
789     if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize))
790         return store_E_NotExists;
791 
792     sal_uInt8 const * src_hi = src_lo + nBytes;
793     if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize))
794         return store_E_CantRead;
795 
796     memcpy (pBuffer, src_lo, (src_hi - src_lo));
797     return store_E_None;
798 }
799 
800 storeError MemoryLockBytes::writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes)
801 {
802     sal_uInt64 const dst_size = nOffset + nBytes;
803     OSL_PRECOND(dst_size < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation");
804     if (dst_size > m_nSize)
805     {
806         storeError eErrCode = setSize_Impl (sal::static_int_cast<sal_uInt32>(dst_size));
807         if (eErrCode != store_E_None)
808             return eErrCode;
809     }
810     OSL_POSTCOND(dst_size <= m_nSize, "store::MemoryLockBytes::setSize_Impl() contract violation");
811 
812     sal_uInt8 * dst_lo = m_pData + nOffset;
813     if (dst_lo >= m_pData + m_nSize)
814         return store_E_CantSeek;
815 
816     sal_uInt8 * dst_hi = dst_lo + nBytes;
817     if (dst_hi > m_pData + m_nSize)
818         return store_E_CantWrite;
819 
820     memcpy (dst_lo, pBuffer, (dst_hi - dst_lo));
821     return store_E_None;
822 }
823 
824 storeError MemoryLockBytes::getSize_Impl (sal_uInt32 & rnSize)
825 {
826     rnSize = m_nSize;
827     return store_E_None;
828 }
829 
830 storeError MemoryLockBytes::setSize_Impl (sal_uInt32 nSize)
831 {
832     if (nSize != m_nSize)
833     {
834         sal_uInt8 * pData = reinterpret_cast<sal_uInt8*>(rtl_reallocateMemory (m_pData, nSize));
835         if (pData != 0)
836         {
837             if (nSize > m_nSize)
838                 memset (pData + m_nSize, 0, sal::static_int_cast<size_t>(nSize - m_nSize));
839         }
840         else
841         {
842             if (nSize != 0)
843                 return store_E_OutOfMemory;
844         }
845         m_pData = pData, m_nSize = nSize;
846     }
847     return store_E_None;
848 }
849 
850 storeError MemoryLockBytes::flush_Impl()
851 {
852     return store_E_None;
853 }
854 
855 /*========================================================================
856  *
857  * ILockBytes factory implementations.
858  *
859  *======================================================================*/
860 namespace store
861 {
862 
863 template< class T > struct ResourceHolder
864 {
865     typedef typename T::destructor_type destructor_type;
866 
867     T m_value;
868 
869     explicit ResourceHolder (T const & value = T()) : m_value (value) {}
870     ~ResourceHolder() { reset(); }
871 
872     T & get() { return m_value; }
873     T const & get() const { return m_value; }
874 
875     void set (T const & value) { m_value = value; }
876     void reset (T const & value = T())
877     {
878         T tmp (m_value);
879         if (tmp != value)
880             destructor_type()(tmp);
881         set (value);
882     }
883     T release()
884     {
885         T tmp (m_value);
886         set (T());
887         return tmp;
888     }
889 
890     ResourceHolder (ResourceHolder & rhs)
891     {
892         set (rhs.release());
893     }
894     ResourceHolder & operator= (ResourceHolder & rhs)
895     {
896         reset (rhs.release());
897         return *this;
898     }
899 };
900 
901 storeError
902 FileLockBytes_createInstance (
903     rtl::Reference< ILockBytes > & rxLockBytes,
904     rtl_uString *                  pFilename,
905     storeAccessMode                eAccessMode
906 )
907 {
908     // Acquire file handle.
909     ResourceHolder<FileHandle> xFile;
910     storeError result = xFile.get().initialize (pFilename, eAccessMode);
911     if (result != store_E_None)
912         return (result);
913 
914     if (eAccessMode == store_AccessReadOnly)
915     {
916         ResourceHolder<FileMapping> xMapping;
917         if (xMapping.get().initialize (xFile.get().m_handle) == osl_File_E_None)
918         {
919             rxLockBytes = new MappedLockBytes (xMapping.get());
920             if (!rxLockBytes.is())
921                 return store_E_OutOfMemory;
922             (void) xMapping.release();
923         }
924     }
925     if (!rxLockBytes.is())
926     {
927         rxLockBytes = new FileLockBytes (xFile.get());
928         if (!rxLockBytes.is())
929             return store_E_OutOfMemory;
930         (void) xFile.release();
931     }
932 
933     return store_E_None;
934 }
935 
936 storeError
937 MemoryLockBytes_createInstance (
938     rtl::Reference< ILockBytes > & rxLockBytes
939 )
940 {
941     rxLockBytes = new MemoryLockBytes();
942     if (!rxLockBytes.is())
943         return store_E_OutOfMemory;
944 
945     return store_E_None;
946 }
947 
948 } // namespace store
949