| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_store.hxx" |
| |
| #include "lockbyte.hxx" |
| |
| #include "sal/types.h" |
| #include "osl/diagnose.h" |
| #include "osl/file.h" |
| #include "osl/process.h" |
| #include "rtl/alloc.h" |
| #include "rtl/ustring.hxx" |
| |
| #include "object.hxx" |
| #include "storbase.hxx" |
| |
| #ifndef INCLUDED_STRING_H |
| #include <string.h> |
| #define INCLUDED_STRING_H |
| #endif |
| |
| using namespace store; |
| |
| /*======================================================================== |
| * |
| * ILockBytes (non-virtual interface) implementation. |
| * |
| *======================================================================*/ |
| |
| storeError ILockBytes::initialize (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) |
| { |
| OSL_PRECOND((STORE_MINIMUM_PAGESIZE <= nPageSize) && (nPageSize <= STORE_MAXIMUM_PAGESIZE), "invalid PageSize"); |
| return initialize_Impl (rxAllocator, nPageSize); |
| } |
| |
| storeError ILockBytes::readPageAt (PageHolder & rPage, sal_uInt32 nOffset) |
| { |
| OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readPageAt(): invalid Offset"); |
| if (nOffset == STORE_PAGE_NULL) |
| return store_E_CantSeek; |
| |
| return readPageAt_Impl (rPage, nOffset); |
| } |
| |
| storeError ILockBytes::writePageAt (PageHolder const & rPage, sal_uInt32 nOffset) |
| { |
| // [SECURITY:ValInput] |
| PageData const * pagedata = rPage.get(); |
| OSL_PRECOND(!(pagedata == 0), "store::ILockBytes::writePageAt(): invalid Page"); |
| if (pagedata == 0) |
| return store_E_InvalidParameter; |
| |
| sal_uInt32 const offset = pagedata->location(); |
| OSL_PRECOND(!(nOffset != offset), "store::ILockBytes::writePageAt(): inconsistent Offset"); |
| if (nOffset != offset) |
| return store_E_InvalidParameter; |
| |
| OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writePageAt(): invalid Offset"); |
| if (nOffset == STORE_PAGE_NULL) |
| return store_E_CantSeek; |
| |
| return writePageAt_Impl (rPage, nOffset); |
| } |
| |
| storeError ILockBytes::readAt (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) |
| { |
| // [SECURITY:ValInput] |
| sal_uInt8 * dst_lo = static_cast<sal_uInt8*>(pBuffer); |
| if (!(dst_lo != 0)) |
| return store_E_InvalidParameter; |
| |
| sal_uInt8 * dst_hi = dst_lo + nBytes; |
| if (!(dst_lo < dst_hi)) |
| return (dst_lo > dst_hi) ? store_E_InvalidParameter : store_E_None; |
| |
| OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readAt(): invalid Offset"); |
| if (nOffset == STORE_PAGE_NULL) |
| return store_E_CantSeek; |
| |
| sal_uInt64 const src_size = nOffset + nBytes; |
| if (src_size > SAL_MAX_UINT32) |
| return store_E_CantSeek; |
| |
| return readAt_Impl (nOffset, dst_lo, (dst_hi - dst_lo)); |
| } |
| |
| storeError ILockBytes::writeAt (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) |
| { |
| // [SECURITY:ValInput] |
| sal_uInt8 const * src_lo = static_cast<sal_uInt8 const*>(pBuffer); |
| if (!(src_lo != 0)) |
| return store_E_InvalidParameter; |
| |
| sal_uInt8 const * src_hi = src_lo + nBytes; |
| if (!(src_lo < src_hi)) |
| return (src_lo > src_hi) ? store_E_InvalidParameter : store_E_None; |
| |
| OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writeAt(): invalid Offset"); |
| if (nOffset == STORE_PAGE_NULL) |
| return store_E_CantSeek; |
| |
| sal_uInt64 const dst_size = nOffset + nBytes; |
| if (dst_size > SAL_MAX_UINT32) |
| return store_E_CantSeek; |
| |
| return writeAt_Impl (nOffset, src_lo, (src_hi - src_lo)); |
| } |
| |
| storeError ILockBytes::getSize (sal_uInt32 & rnSize) |
| { |
| rnSize = 0; |
| return getSize_Impl (rnSize); |
| } |
| |
| storeError ILockBytes::setSize (sal_uInt32 nSize) |
| { |
| return setSize_Impl (nSize); |
| } |
| |
| storeError ILockBytes::flush() |
| { |
| return flush_Impl(); |
| } |
| |
| /*======================================================================== |
| * |
| * FileLockBytes implementation. |
| * |
| *======================================================================*/ |
| namespace store |
| { |
| |
| struct FileHandle |
| { |
| oslFileHandle m_handle; |
| |
| FileHandle() : m_handle(0) {} |
| |
| bool operator != (FileHandle const & rhs) |
| { |
| return (m_handle != rhs.m_handle); |
| } |
| |
| static storeError errorFromNative (oslFileError eErrno) |
| { |
| switch (eErrno) |
| { |
| case osl_File_E_None: |
| return store_E_None; |
| |
| case osl_File_E_NOENT: |
| return store_E_NotExists; |
| |
| case osl_File_E_ACCES: |
| case osl_File_E_PERM: |
| return store_E_AccessViolation; |
| |
| case osl_File_E_AGAIN: |
| case osl_File_E_DEADLK: |
| return store_E_LockingViolation; |
| |
| case osl_File_E_BADF: |
| return store_E_InvalidHandle; |
| |
| case osl_File_E_INVAL: |
| return store_E_InvalidParameter; |
| |
| case osl_File_E_NOMEM: |
| return store_E_OutOfMemory; |
| |
| case osl_File_E_NOSPC: |
| return store_E_OutOfSpace; |
| |
| case osl_File_E_OVERFLOW: |
| return store_E_CantSeek; |
| |
| default: |
| return store_E_Unknown; |
| } |
| } |
| |
| static sal_uInt32 modeToNative (storeAccessMode eAccessMode) |
| { |
| sal_uInt32 nFlags = 0; |
| switch (eAccessMode) |
| { |
| case store_AccessCreate: |
| case store_AccessReadCreate: |
| nFlags |= osl_File_OpenFlag_Create; |
| // fall through |
| case store_AccessReadWrite: |
| nFlags |= osl_File_OpenFlag_Write; |
| // fall through |
| case store_AccessReadOnly: |
| nFlags |= osl_File_OpenFlag_Read; |
| break; |
| default: |
| OSL_PRECOND(0, "store::FileHandle: unknown storeAccessMode"); |
| } |
| return nFlags; |
| } |
| |
| storeError initialize (rtl_uString * pFilename, storeAccessMode eAccessMode) |
| { |
| // Verify arguments. |
| sal_uInt32 nFlags = modeToNative (eAccessMode); |
| if (!pFilename || !nFlags) |
| return store_E_InvalidParameter; |
| |
| // Convert into FileUrl. |
| rtl::OUString aFileUrl; |
| if (osl_getFileURLFromSystemPath (pFilename, &(aFileUrl.pData)) != osl_File_E_None) |
| { |
| // Not system path. Assume file url. |
| rtl_uString_assign (&(aFileUrl.pData), pFilename); |
| } |
| if (aFileUrl.compareToAscii("file://", 7) != 0) |
| { |
| // Not file url. Assume relative path. |
| rtl::OUString aCwdUrl; |
| (void) osl_getProcessWorkingDir (&(aCwdUrl.pData)); |
| |
| // Absolute file url. |
| (void) osl_getAbsoluteFileURL (aCwdUrl.pData, aFileUrl.pData, &(aFileUrl.pData)); |
| } |
| |
| // Acquire handle. |
| oslFileError result = osl_openFile (aFileUrl.pData, &m_handle, nFlags); |
| if (result == osl_File_E_EXIST) |
| { |
| // Already existing (O_CREAT | O_EXCL). |
| result = osl_openFile (aFileUrl.pData, &m_handle, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); |
| if ((result == osl_File_E_None) && (eAccessMode == store_AccessCreate)) |
| { |
| // Truncate existing file. |
| result = osl_setFileSize (m_handle, 0); |
| } |
| } |
| if (result != osl_File_E_None) |
| return errorFromNative(result); |
| return store_E_None; |
| } |
| |
| /** @see FileLockBytes destructor |
| */ |
| static void closeFile (oslFileHandle hFile) |
| { |
| (void) osl_closeFile (hFile); |
| } |
| |
| /** @see ResourceHolder<T>::destructor_type |
| */ |
| struct CloseFile |
| { |
| void operator()(FileHandle & rFile) const |
| { |
| // Release handle. |
| closeFile (rFile.m_handle); |
| rFile.m_handle = 0; |
| } |
| }; |
| typedef CloseFile destructor_type; |
| }; |
| |
| class FileLockBytes : |
| public store::OStoreObject, |
| public store::ILockBytes |
| { |
| /** Representation. |
| */ |
| oslFileHandle m_hFile; |
| sal_uInt32 m_nSize; |
| rtl::Reference< PageData::Allocator > m_xAllocator; |
| |
| storeError initSize_Impl (sal_uInt32 & rnSize); |
| |
| /** ILockBytes implementation. |
| */ |
| virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); |
| |
| virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); |
| virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); |
| |
| virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); |
| virtual storeError writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); |
| |
| virtual storeError getSize_Impl (sal_uInt32 & rnSize); |
| virtual storeError setSize_Impl (sal_uInt32 nSize); |
| |
| virtual storeError flush_Impl(); |
| |
| /** Not implemented. |
| */ |
| FileLockBytes (FileLockBytes const &); |
| FileLockBytes & operator= (FileLockBytes const &); |
| |
| public: |
| /** Construction. |
| */ |
| explicit FileLockBytes (FileHandle & rFile); |
| |
| /** Delegate multiple inherited IReference. |
| */ |
| virtual oslInterlockedCount SAL_CALL acquire(); |
| virtual oslInterlockedCount SAL_CALL release(); |
| |
| protected: |
| /** Destruction. |
| */ |
| virtual ~FileLockBytes(); |
| }; |
| |
| } // namespace store |
| |
| FileLockBytes::FileLockBytes (FileHandle & rFile) |
| : m_hFile (rFile.m_handle), m_nSize (SAL_MAX_UINT32), m_xAllocator() |
| { |
| } |
| |
| FileLockBytes::~FileLockBytes() |
| { |
| FileHandle::closeFile (m_hFile); |
| } |
| |
| oslInterlockedCount SAL_CALL FileLockBytes::acquire() |
| { |
| return OStoreObject::acquire(); |
| } |
| |
| oslInterlockedCount SAL_CALL FileLockBytes::release() |
| { |
| return OStoreObject::release(); |
| } |
| |
| storeError FileLockBytes::initSize_Impl (sal_uInt32 & rnSize) |
| { |
| /* osl_getFileSize() uses slow 'fstat(h, &size)', |
| * instead of fast 'size = lseek(h, 0, SEEK_END)'. |
| * so, init size here, and track changes. |
| */ |
| sal_uInt64 uSize = 0; |
| oslFileError result = osl_getFileSize (m_hFile, &uSize); |
| if (result != osl_File_E_None) |
| return FileHandle::errorFromNative(result); |
| if (uSize > SAL_MAX_UINT32) |
| return store_E_CantSeek; |
| |
| rnSize = sal::static_int_cast<sal_uInt32>(uSize); |
| return store_E_None; |
| } |
| |
| storeError FileLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) |
| { |
| storeError result = initSize_Impl (m_nSize); |
| if (result != store_E_None) |
| return (result); |
| |
| result = PageData::Allocator::createInstance (rxAllocator, nPageSize); |
| if (result != store_E_None) |
| return (result); |
| |
| // @see readPageAt_Impl(). |
| m_xAllocator = rxAllocator; |
| return store_E_None; |
| } |
| |
| storeError FileLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) |
| { |
| if (m_xAllocator.is()) |
| { |
| PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator); |
| page.swap (rPage); |
| } |
| |
| if (!m_xAllocator.is()) |
| return store_E_InvalidAccess; |
| if (!rPage.get()) |
| return store_E_OutOfMemory; |
| |
| PageData * pagedata = rPage.get(); |
| return readAt_Impl (nOffset, pagedata, pagedata->size()); |
| } |
| |
| storeError FileLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) |
| { |
| PageData const * pagedata = rPage.get(); |
| OSL_PRECOND(pagedata != 0, "contract violation"); |
| return writeAt_Impl (nOffset, pagedata, pagedata->size()); |
| } |
| |
| storeError FileLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) |
| { |
| sal_uInt64 nDone = 0; |
| oslFileError result = osl_readFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); |
| if (result != osl_File_E_None) |
| return FileHandle::errorFromNative(result); |
| if (nDone != nBytes) |
| return (nDone != 0) ? store_E_CantRead : store_E_NotExists; |
| return store_E_None; |
| } |
| |
| storeError FileLockBytes::writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) |
| { |
| sal_uInt64 nDone = 0; |
| oslFileError result = osl_writeFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone); |
| if (result != osl_File_E_None) |
| return FileHandle::errorFromNative(result); |
| if (nDone != nBytes) |
| return store_E_CantWrite; |
| |
| sal_uInt64 const uSize = nOffset + nBytes; |
| OSL_PRECOND(uSize < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation"); |
| if (uSize > m_nSize) |
| m_nSize = sal::static_int_cast<sal_uInt32>(uSize); |
| return store_E_None; |
| } |
| |
| storeError FileLockBytes::getSize_Impl (sal_uInt32 & rnSize) |
| { |
| rnSize = m_nSize; |
| return store_E_None; |
| } |
| |
| storeError FileLockBytes::setSize_Impl (sal_uInt32 nSize) |
| { |
| oslFileError result = osl_setFileSize (m_hFile, nSize); |
| if (result != osl_File_E_None) |
| return FileHandle::errorFromNative(result); |
| |
| m_nSize = nSize; |
| return store_E_None; |
| } |
| |
| storeError FileLockBytes::flush_Impl() |
| { |
| oslFileError result = osl_syncFile (m_hFile); |
| if (result != osl_File_E_None) |
| return FileHandle::errorFromNative(result); |
| return store_E_None; |
| } |
| |
| /*======================================================================== |
| * |
| * MappedLockBytes implementation. |
| * |
| *======================================================================*/ |
| namespace store |
| { |
| |
| struct FileMapping |
| { |
| sal_uInt8 * m_pAddr; |
| sal_uInt32 m_nSize; |
| |
| FileMapping() : m_pAddr(0), m_nSize(0) {} |
| |
| bool operator != (FileMapping const & rhs) const |
| { |
| return ((m_pAddr != rhs.m_pAddr) || (m_nSize != rhs.m_nSize)); |
| } |
| |
| oslFileError initialize (oslFileHandle hFile) |
| { |
| // Determine mapping size. |
| sal_uInt64 uSize = 0; |
| oslFileError result = osl_getFileSize (hFile, &uSize); |
| if (result != osl_File_E_None) |
| return result; |
| |
| // [SECURITY:IntOver] |
| if (uSize > SAL_MAX_UINT32) |
| return osl_File_E_OVERFLOW; |
| m_nSize = sal::static_int_cast<sal_uInt32>(uSize); |
| |
| // Acquire mapping. |
| return osl_mapFile (hFile, reinterpret_cast<void**>(&m_pAddr), m_nSize, 0, osl_File_MapFlag_RandomAccess); |
| } |
| |
| /** @see MappedLockBytes::destructor. |
| */ |
| static void unmapFile (sal_uInt8 * pAddr, sal_uInt32 nSize) |
| { |
| (void) osl_unmapFile (pAddr, nSize); |
| } |
| |
| /** @see ResourceHolder<T>::destructor_type |
| */ |
| struct UnmapFile |
| { |
| void operator ()(FileMapping & rMapping) const |
| { |
| // Release mapping. |
| unmapFile (rMapping.m_pAddr, rMapping.m_nSize); |
| rMapping.m_pAddr = 0, rMapping.m_nSize = 0; |
| } |
| }; |
| typedef UnmapFile destructor_type; |
| }; |
| |
| class MappedLockBytes : |
| public store::OStoreObject, |
| public store::PageData::Allocator, |
| public store::ILockBytes |
| { |
| /** Representation. |
| */ |
| sal_uInt8 * m_pData; |
| sal_uInt32 m_nSize; |
| sal_uInt16 m_nPageSize; |
| |
| /** PageData::Allocator implementation. |
| */ |
| virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize); |
| virtual void deallocate_Impl (void * pPage); |
| |
| /** ILockBytes implementation. |
| */ |
| virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); |
| |
| virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); |
| virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); |
| |
| virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); |
| virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes); |
| |
| virtual storeError getSize_Impl (sal_uInt32 & rnSize); |
| virtual storeError setSize_Impl (sal_uInt32 nSize); |
| |
| virtual storeError flush_Impl(); |
| |
| /** Not implemented. |
| */ |
| MappedLockBytes (MappedLockBytes const &); |
| MappedLockBytes & operator= (MappedLockBytes const &); |
| |
| public: |
| /** Construction. |
| */ |
| explicit MappedLockBytes (FileMapping & rMapping); |
| |
| /** Delegate multiple inherited IReference. |
| */ |
| virtual oslInterlockedCount SAL_CALL acquire(); |
| virtual oslInterlockedCount SAL_CALL release(); |
| |
| protected: |
| /* Destruction. |
| */ |
| virtual ~MappedLockBytes(); |
| }; |
| |
| } // namespace store |
| |
| MappedLockBytes::MappedLockBytes (FileMapping & rMapping) |
| : m_pData (rMapping.m_pAddr), m_nSize (rMapping.m_nSize), m_nPageSize(0) |
| { |
| } |
| |
| MappedLockBytes::~MappedLockBytes() |
| { |
| FileMapping::unmapFile (m_pData, m_nSize); |
| } |
| |
| oslInterlockedCount SAL_CALL MappedLockBytes::acquire() |
| { |
| return OStoreObject::acquire(); |
| } |
| |
| oslInterlockedCount SAL_CALL MappedLockBytes::release() |
| { |
| return OStoreObject::release(); |
| } |
| |
| void MappedLockBytes::allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) |
| { |
| OSL_PRECOND((ppPage != 0) && (pnSize != 0), "contract violation"); |
| if ((ppPage != 0) && (pnSize != 0)) |
| *ppPage = 0, *pnSize = m_nPageSize; |
| } |
| |
| void MappedLockBytes::deallocate_Impl (void * pPage) |
| { |
| OSL_PRECOND((m_pData <= pPage) && (pPage < m_pData + m_nSize), "contract violation"); |
| (void)pPage; // UNUSED |
| } |
| |
| storeError MappedLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) |
| { |
| rxAllocator = this; |
| m_nPageSize = nPageSize; |
| return store_E_None; |
| } |
| |
| storeError MappedLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) |
| { |
| sal_uInt8 * src_lo = m_pData + nOffset; |
| if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) |
| return store_E_NotExists; |
| |
| sal_uInt8 * src_hi = src_lo + m_nPageSize; |
| if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) |
| return store_E_CantRead; |
| |
| PageHolder page (reinterpret_cast< PageData* >(src_lo), static_cast< PageData::Allocator* >(this)); |
| page.swap (rPage); |
| |
| return store_E_None; |
| } |
| |
| storeError MappedLockBytes::writePageAt_Impl (PageHolder const & /*rPage*/, sal_uInt32 /*nOffset*/) |
| { |
| return store_E_AccessViolation; |
| } |
| |
| storeError MappedLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) |
| { |
| sal_uInt8 const * src_lo = m_pData + nOffset; |
| if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) |
| return store_E_NotExists; |
| |
| sal_uInt8 const * src_hi = src_lo + nBytes; |
| if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) |
| return store_E_CantRead; |
| |
| memcpy (pBuffer, src_lo, (src_hi - src_lo)); |
| return store_E_None; |
| } |
| |
| storeError MappedLockBytes::writeAt_Impl (sal_uInt32 /*nOffset*/, void const * /*pBuffer*/, sal_uInt32 /*nBytes*/) |
| { |
| return store_E_AccessViolation; |
| } |
| |
| storeError MappedLockBytes::getSize_Impl (sal_uInt32 & rnSize) |
| { |
| rnSize = m_nSize; |
| return store_E_None; |
| } |
| |
| storeError MappedLockBytes::setSize_Impl (sal_uInt32 /*nSize*/) |
| { |
| return store_E_AccessViolation; |
| } |
| |
| storeError MappedLockBytes::flush_Impl() |
| { |
| return store_E_None; |
| } |
| |
| /*======================================================================== |
| * |
| * MemoryLockBytes implementation. |
| * |
| *======================================================================*/ |
| namespace store |
| { |
| |
| class MemoryLockBytes : |
| public store::OStoreObject, |
| public store::ILockBytes |
| { |
| /** Representation. |
| */ |
| sal_uInt8 * m_pData; |
| sal_uInt32 m_nSize; |
| rtl::Reference< PageData::Allocator > m_xAllocator; |
| |
| /** ILockBytes implementation. |
| */ |
| virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize); |
| |
| virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); |
| virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); |
| |
| virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); |
| virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes); |
| |
| virtual storeError getSize_Impl (sal_uInt32 & rnSize); |
| virtual storeError setSize_Impl (sal_uInt32 nSize); |
| |
| virtual storeError flush_Impl(); |
| |
| /** Not implemented. |
| */ |
| MemoryLockBytes (MemoryLockBytes const &); |
| MemoryLockBytes& operator= (MemoryLockBytes const &); |
| |
| public: |
| /** Construction. |
| */ |
| MemoryLockBytes(); |
| |
| /** Delegate multiple inherited IReference. |
| */ |
| virtual oslInterlockedCount SAL_CALL acquire(); |
| virtual oslInterlockedCount SAL_CALL release(); |
| |
| protected: |
| /** Destruction. |
| */ |
| virtual ~MemoryLockBytes(); |
| }; |
| |
| } // namespace store |
| |
| MemoryLockBytes::MemoryLockBytes() |
| : m_pData (0), m_nSize (0), m_xAllocator() |
| {} |
| |
| MemoryLockBytes::~MemoryLockBytes() |
| { |
| rtl_freeMemory (m_pData); |
| } |
| |
| oslInterlockedCount SAL_CALL MemoryLockBytes::acquire (void) |
| { |
| return OStoreObject::acquire(); |
| } |
| |
| oslInterlockedCount SAL_CALL MemoryLockBytes::release (void) |
| { |
| return OStoreObject::release(); |
| } |
| |
| storeError MemoryLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) |
| { |
| storeError result = PageData::Allocator::createInstance (rxAllocator, nPageSize); |
| if (result == store_E_None) |
| { |
| // @see readPageAt_Impl(). |
| m_xAllocator = rxAllocator; |
| } |
| return result; |
| } |
| |
| storeError MemoryLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) |
| { |
| if (m_xAllocator.is()) |
| { |
| PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator); |
| page.swap (rPage); |
| } |
| |
| if (!m_xAllocator.is()) |
| return store_E_InvalidAccess; |
| if (!rPage.get()) |
| return store_E_OutOfMemory; |
| |
| PageData * pagedata = rPage.get(); |
| return readAt_Impl (nOffset, pagedata, pagedata->size()); |
| } |
| |
| storeError MemoryLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) |
| { |
| PageData const * pagedata = rPage.get(); |
| OSL_PRECOND(!(pagedata == 0), "contract violation"); |
| return writeAt_Impl (nOffset, pagedata, pagedata->size()); |
| } |
| |
| storeError MemoryLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) |
| { |
| sal_uInt8 const * src_lo = m_pData + nOffset; |
| if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize)) |
| return store_E_NotExists; |
| |
| sal_uInt8 const * src_hi = src_lo + nBytes; |
| if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize)) |
| return store_E_CantRead; |
| |
| memcpy (pBuffer, src_lo, (src_hi - src_lo)); |
| return store_E_None; |
| } |
| |
| storeError MemoryLockBytes::writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes) |
| { |
| sal_uInt64 const dst_size = nOffset + nBytes; |
| OSL_PRECOND(dst_size < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation"); |
| if (dst_size > m_nSize) |
| { |
| storeError eErrCode = setSize_Impl (sal::static_int_cast<sal_uInt32>(dst_size)); |
| if (eErrCode != store_E_None) |
| return eErrCode; |
| } |
| OSL_POSTCOND(dst_size <= m_nSize, "store::MemoryLockBytes::setSize_Impl() contract violation"); |
| |
| sal_uInt8 * dst_lo = m_pData + nOffset; |
| if (dst_lo >= m_pData + m_nSize) |
| return store_E_CantSeek; |
| |
| sal_uInt8 * dst_hi = dst_lo + nBytes; |
| if (dst_hi > m_pData + m_nSize) |
| return store_E_CantWrite; |
| |
| memcpy (dst_lo, pBuffer, (dst_hi - dst_lo)); |
| return store_E_None; |
| } |
| |
| storeError MemoryLockBytes::getSize_Impl (sal_uInt32 & rnSize) |
| { |
| rnSize = m_nSize; |
| return store_E_None; |
| } |
| |
| storeError MemoryLockBytes::setSize_Impl (sal_uInt32 nSize) |
| { |
| if (nSize != m_nSize) |
| { |
| sal_uInt8 * pData = reinterpret_cast<sal_uInt8*>(rtl_reallocateMemory (m_pData, nSize)); |
| if (pData != 0) |
| { |
| if (nSize > m_nSize) |
| memset (pData + m_nSize, 0, sal::static_int_cast<size_t>(nSize - m_nSize)); |
| } |
| else |
| { |
| if (nSize != 0) |
| return store_E_OutOfMemory; |
| } |
| m_pData = pData, m_nSize = nSize; |
| } |
| return store_E_None; |
| } |
| |
| storeError MemoryLockBytes::flush_Impl() |
| { |
| return store_E_None; |
| } |
| |
| /*======================================================================== |
| * |
| * ILockBytes factory implementations. |
| * |
| *======================================================================*/ |
| namespace store |
| { |
| |
| template< class T > struct ResourceHolder |
| { |
| typedef typename T::destructor_type destructor_type; |
| |
| T m_value; |
| |
| explicit ResourceHolder (T const & value = T()) : m_value (value) {} |
| ~ResourceHolder() { reset(); } |
| |
| T & get() { return m_value; } |
| T const & get() const { return m_value; } |
| |
| void set (T const & value) { m_value = value; } |
| void reset (T const & value = T()) |
| { |
| T tmp (m_value); |
| if (tmp != value) |
| destructor_type()(tmp); |
| set (value); |
| } |
| T release() |
| { |
| T tmp (m_value); |
| set (T()); |
| return tmp; |
| } |
| |
| ResourceHolder (ResourceHolder & rhs) |
| { |
| set (rhs.release()); |
| } |
| ResourceHolder & operator= (ResourceHolder & rhs) |
| { |
| reset (rhs.release()); |
| return *this; |
| } |
| }; |
| |
| storeError |
| FileLockBytes_createInstance ( |
| rtl::Reference< ILockBytes > & rxLockBytes, |
| rtl_uString * pFilename, |
| storeAccessMode eAccessMode |
| ) |
| { |
| // Acquire file handle. |
| ResourceHolder<FileHandle> xFile; |
| storeError result = xFile.get().initialize (pFilename, eAccessMode); |
| if (result != store_E_None) |
| return (result); |
| |
| if (eAccessMode == store_AccessReadOnly) |
| { |
| ResourceHolder<FileMapping> xMapping; |
| if (xMapping.get().initialize (xFile.get().m_handle) == osl_File_E_None) |
| { |
| rxLockBytes = new MappedLockBytes (xMapping.get()); |
| if (!rxLockBytes.is()) |
| return store_E_OutOfMemory; |
| (void) xMapping.release(); |
| } |
| } |
| if (!rxLockBytes.is()) |
| { |
| rxLockBytes = new FileLockBytes (xFile.get()); |
| if (!rxLockBytes.is()) |
| return store_E_OutOfMemory; |
| (void) xFile.release(); |
| } |
| |
| return store_E_None; |
| } |
| |
| storeError |
| MemoryLockBytes_createInstance ( |
| rtl::Reference< ILockBytes > & rxLockBytes |
| ) |
| { |
| rxLockBytes = new MemoryLockBytes(); |
| if (!rxLockBytes.is()) |
| return store_E_OutOfMemory; |
| |
| return store_E_None; |
| } |
| |
| } // namespace store |