/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include "sal/config.h" #include "boost/static_assert.hpp" #include "osl/diagnose.h" #include "rtl/alloc.h" #include "rtl/ref.hxx" #include "storbase.hxx" #include "osl/file.h" #include "rtl/ustring.hxx" template< class T > void swap (T & lhs, T & rhs) { T tmp = rhs; rhs = lhs; lhs = tmp; } class SharedCount { long * m_pCount; class Allocator { rtl_cache_type * m_cache; public: static Allocator & get(); long * alloc() { return static_cast(rtl_cache_alloc (m_cache)); } void free (long * pCount) { rtl_cache_free (m_cache, pCount); } protected: Allocator(); ~Allocator(); }; public: SharedCount() : m_pCount(Allocator::get().alloc()) { if (m_pCount != 0) (*m_pCount) = 1; } ~SharedCount() { if (m_pCount != 0) { long new_count = --(*m_pCount); if (new_count == 0) Allocator::get().free(m_pCount); } } bool operator== (long count) const { return (m_pCount != 0) ? *m_pCount == count : false; } friend void swap<> (SharedCount & lhs, SharedCount & rhs); // nothrow SharedCount (SharedCount const & rhs); // nothrow SharedCount & operator= (SharedCount const & rhs); // nothrow }; template<> inline void swap (SharedCount & lhs, SharedCount & rhs) // nothrow { swap(lhs.m_pCount, rhs.m_pCount); } SharedCount::SharedCount (SharedCount const & rhs) // nothrow : m_pCount (rhs.m_pCount) { if (m_pCount != 0) ++(*m_pCount); } SharedCount & SharedCount::operator= (SharedCount const & rhs) // nothrow { SharedCount tmp(rhs); swap(tmp, *this); return *this; } SharedCount::Allocator & SharedCount::Allocator::get() { static Allocator g_aSharedCountAllocator; return g_aSharedCountAllocator; } SharedCount::Allocator::Allocator() { m_cache = rtl_cache_create ( "store_shared_count_cache", sizeof(long), 0, // objalign 0, // constructor 0, // destructor 0, // reclaim 0, // userarg 0, // default source 0 // flags ); } SharedCount::Allocator::~Allocator() { rtl_cache_destroy (m_cache), m_cache = 0; } /*======================================================================*/ #if defined(OSL_BIGENDIAN) #define STORE_DWORD(dword) OSL_SWAPDWORD((dword)) #else #define STORE_DWORD(dword) (dword) #endif struct PageData { typedef store::OStorePageGuard G; typedef store::OStorePageDescriptor D; typedef store::OStorePageLink L; /** Representation. */ G m_aGuard; D m_aDescr; L m_aMarked; L m_aUnused; /** theSize. */ static const size_t theSize = sizeof(G) + sizeof(D) + 2 * sizeof(L); static const sal_uInt16 thePageSize = theSize; BOOST_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize); /** type. */ sal_uInt32 type() const { return m_aGuard.m_nMagic; /* @@@ */ } /** offset. */ sal_uInt32 offset() const { return m_aDescr.m_nAddr; /* @@@ */ } void offset (sal_uInt32 nOffset) { m_aDescr.m_nAddr = nOffset; } /** size. */ sal_uInt16 size() const { return m_aDescr.m_nSize; /* @@@ */ } /** Allocation. */ class Allocator : public rtl::IReference { public: template< class T > T * construct() { void * page = 0; sal_uInt16 size = 0; if (allocate (&page, &size)) { return new(page) T(size); } return 0; } virtual bool allocate (void ** ppPage, sal_uInt16 * pnSize) = 0; virtual void deallocate (void * pPage) = 0; }; static void * operator new (size_t, void * p) { return p; } static void operator delete (void *, void *) {} /** Construction. */ explicit PageData (sal_uInt16 nPageSize = thePageSize) : m_aDescr (STORE_PAGE_NULL, nPageSize, thePageSize) {} /** ... */ void guard() {} storeError verify() const { return store_E_None; } }; class PageAllocator { rtl_cache_type * m_cache; SharedCount m_refcount; public: PageAllocator() : m_cache(0), m_refcount() {} ~PageAllocator() { // NYI if (m_refcount == 1) { } } friend void swap<>(PageAllocator & lhs, PageAllocator & rhs); PageAllocator (PageAllocator const & rhs); PageAllocator & operator= (PageAllocator const & rhs); }; template<> inline void swap (PageAllocator & lhs, PageAllocator & rhs) { swap(lhs.m_cache, rhs.m_cache); swap(lhs.m_refcount, rhs.m_refcount); } PageAllocator::PageAllocator (PageAllocator const & rhs) : m_cache (rhs.m_cache), m_refcount (rhs.m_refcount) { } PageAllocator & PageAllocator::operator= (PageAllocator const & rhs) { PageAllocator tmp (rhs); swap(tmp, *this); return *this; } /*======================================================================*/ class PageHolder { SharedCount m_refcount; PageData * m_pagedata; typedef rtl::Reference< PageData::Allocator > allocator_type; allocator_type m_allocator; public: explicit PageHolder (PageData * pagedata = 0, allocator_type const & allocator = allocator_type()) : m_refcount (), m_pagedata (pagedata), m_allocator(allocator) {} ~PageHolder() { if ((m_refcount == 1) && (m_pagedata != 0) && m_allocator.is()) { // free pagedata. m_allocator->deallocate (m_pagedata); } } PageData * get() { return m_pagedata; } PageData const * get() const { return m_pagedata; } PageData * operator->() { return m_pagedata; } PageData const * operator->() const { return m_pagedata; } friend void swap<> (PageHolder & lhs, PageHolder & rhs); // nothrow PageHolder (PageHolder const & rhs); // nothrow PageHolder & operator= (PageHolder const & rhs); // nothrow }; template<> inline void swap (PageHolder & lhs, PageHolder & rhs) // nothrow { swap(lhs.m_refcount, rhs.m_refcount); swap(lhs.m_pagedata, rhs.m_pagedata); swap(lhs.m_allocator, rhs.m_allocator); } PageHolder::PageHolder (PageHolder const & rhs) // nothrow : m_refcount (rhs.m_refcount), m_pagedata (rhs.m_pagedata), m_allocator(rhs.m_allocator) {} PageHolder & PageHolder::operator= (PageHolder const & rhs) // nothrow { PageHolder tmp (rhs); swap(tmp, *this); return *this; } /*======================================================================*/ template< class T > class PageHolderObject { protected: /** Representation. */ PageHolder m_xPage; /** Checked cast. */ template< class U > static bool isA (PageData const * p) { return ((p != 0) && (p->type() == U::theTypeId)); } template< class U > static U * dynamic_page_cast (PageData * p) { return isA(p) ? static_cast(p) : 0; } template< class U > static U const * dynamic_page_cast (PageData const * p) { return isA(p) ? static_cast(p) : 0; } public: static PageHolderObject construct (rtl::Reference< PageData::Allocator > const & rxAllocator) { PageHolderObject tmp; if (rxAllocator.is()) { PageHolder xPage (rxAllocator->construct(), rxAllocator); store::swap(tmp.m_xPage, xPage); } return tmp; } explicit PageHolderObject (PageHolder const & rxPage = PageHolder()) : m_xPage (rxPage) {} void swap (PageHolderObject & rhs) { store::swap(m_xPage, rhs.m_xPage); } PageHolderObject (PageHolderObject const & rhs) : m_xPage (rhs.m_xPage) { } PageHolderObject & operator= (PageHolderObject const & rhs) { PageHolderObject tmp (rhs); this->swap(tmp); return *this; } T * operator->() { T * pImpl = dynamic_page_cast(m_xPage.get()); OSL_PRECOND(pImpl != 0, "store::PageHolder::operator->(): Null pointer"); return pImpl; } T const * operator->() const { T const * pImpl = dynamic_page_cast(m_xPage.get()); OSL_PRECOND(pImpl != 0, "store::PageHolder::operator->(): Null pointer"); return pImpl; } T & operator*() { T * pImpl = dynamic_page_cast(m_xPage.get()); OSL_PRECOND(pImpl != 0, "store::PageHolder::operator*(): Null pointer"); return *pImpl; } T const & operator*() const { T const * pImpl = dynamic_page_cast(m_xPage.get()); OSL_PRECOND(pImpl != 0, "store::PageHolder::operator*(): Null pointer"); return *pImpl; } static storeError guard (PageHolder & rxPage) { T * pImpl = dynamic_page_cast(rxPage.get()); if (pImpl != 0) { pImpl->guard(); return store_E_None; } else if (rxPage.get() != 0) return store_E_WrongVersion; else return store_E_InvalidAccess; } static storeError verify (PageHolder const & rxPage) { T const * pImpl = dynamic_page_cast(rxPage.get()); if (pImpl != 0) return pImpl->verify(); else if (rxPage.get() != 0) return store_E_WrongVersion; else return store_E_InvalidAccess; } }; /*======================================================================*/ class PageObject { public: explicit PageObject (PageHolder const & rxPage = PageHolder()) : m_xPage (rxPage) {} virtual ~PageObject(); PageHolder & get() { return m_xPage; } PageHolder const & get() const { return m_xPage; } PageData * operator->() { PageData * pImpl = m_xPage.get(); OSL_PRECOND(pImpl != 0, "store::PageObject::operator->(): Null pointer"); return pImpl; } PageData & operator*() { PageData * pImpl = m_xPage.get(); OSL_PRECOND(pImpl != 0, "store::PageObject::operator*(): Null pointer"); return *pImpl; } virtual void guard(); virtual storeError verify() const; protected: PageHolder m_xPage; }; PageObject::~PageObject() {} void PageObject::guard() { PageData * p = m_xPage.get(); p->guard(); } storeError PageObject::verify() const { PageData const * p = m_xPage.get(); return p->verify(); } /*======================================================================*/ template< class T > T * dynamic_page_cast (PageData * pagedata) { if ((pagedata != 0) && (pagedata->type() == T::theTypeId)) return static_cast(pagedata); return 0; } template< class T > T * dynamic_page_cast (PageData const * pagedata) { if ((pagedata != 0) && (pagedata->type() == T::theTypeId)) return static_cast(pagedata); return 0; } /*======================================================================*/ class TestBIOS { public: storeError loadPageAt (PageHolder & rPage, storeError (*pfnVerify)(PageHolder const &)) { return (pfnVerify)(rPage); } storeError allocate (PageHolder & rxPage, ...) { // NYI: PageObject.save(nAddr, *this); (void)rxPage; // NYI return store_E_Unknown; // NYI } storeError loadAt (PageHolder & rPage, sal_uInt32 nOffset) { (void)rPage; // NYI (void)nOffset; // NYI return store_E_Unknown; // NYI } storeError saveAt (PageHolder const & rPage, sal_uInt32 nOffset) { (void)rPage; // NYI (void)nOffset; // NYI return store_E_Unknown; // NYI } template< class T > storeError save (PageHolder & rxPage, sal_uInt32 nOffset) { storeError result = PageHolderObject::guard (rxPage); if (result != store_E_None) return result; return saveAt (rxPage, nOffset); } storeError lookupAt (PageHolder & rPage, sal_uInt32 nOffset) { (void)rPage; // NYI (void)nOffset; // NYI return store_E_NotExists; } storeError replaceAt (PageHolder const & rPage, sal_uInt32 nOffset) { (void)rPage; // NYI (void)nOffset; // NYI return store_E_None; } }; struct TestDataV1 : public PageData { static const sal_uInt32 theTypeId = 6 * 9; }; struct TestData : public PageData { typedef PageData base; typedef TestData self; static const sal_uInt32 theTypeId = 42; void guard() { base::guard(); // self::m_aGuard = ...; } storeError verify() const { storeError result = base::verify(); if (result != store_E_None) return result; if (!(base::type() == self::theTypeId)) return store_E_WrongVersion; return store_E_None; } storeError dwim() const { return store_E_None; } }; class TestObject : public PageObject { typedef PageObject base; public: void dwim() { PageHolderObject< TestData > xPage (m_xPage); xPage->guard(); } virtual void guard() { TestData * pagedata = dynamic_page_cast< TestData >(m_xPage.get()); if (pagedata != 0) {} } virtual storeError verify() const { storeError result = base::verify(); if (result != store_E_None) return result; TestData const * pagedata = dynamic_page_cast< TestData const >(m_xPage.get()); if (!pagedata) return store_E_WrongVersion; return pagedata->verify(); } static storeError verify (PageHolder const & rPage) { return PageHolderObject< TestData >::verify (rPage); } storeError loadAt (sal_uInt32 nOffset, TestBIOS & rBIOS) { storeError result = rBIOS.lookupAt (m_xPage, nOffset); // cache lookup if (result == store_E_NotExists) { result = rBIOS.loadAt (m_xPage, nOffset); if (result != store_E_None) return result; result = PageHolderObject< TestData >::verify (m_xPage); if (result != store_E_None) return result; result = rBIOS.replaceAt (m_xPage, nOffset); // cache insert } return result; } storeError saveAt (sal_uInt32 nOffset, TestBIOS & rBIOS) { if (!m_xPage.get()) return store_E_InvalidAccess; m_xPage->m_aDescr.m_nAddr = store::htonl(nOffset); // m_xPage->location (nOffset); storeError result = PageHolderObject< TestData >::guard (m_xPage); if (result != store_E_None) return result; result = rBIOS.saveAt (m_xPage, nOffset); if (result != store_E_None) return result; return rBIOS.replaceAt (m_xPage, nOffset); // cache update } }; class TestObjectV2 : public PageHolderObject< TestData > { typedef PageHolderObject< TestData > base; public: storeError saveAt (sal_uInt32 nOffset, TestBIOS & rBIOS) { m_xPage->offset(nOffset); storeError result = PageHolderObject< TestData >::guard (m_xPage); if (result != store_E_None) return result; result = rBIOS.saveAt (m_xPage, nOffset); if (result != store_E_None) return result; return rBIOS.replaceAt (m_xPage, nOffset); } #if 1 storeError dwim() const { TestData const * pImpl1 = operator->(); PageHolderObject< TestData > xImpl (m_xPage); TestData const * pImpl2 = &*xImpl; OSL_ASSERT(pImpl1 == pImpl2); return xImpl->dwim(); } #endif }; class TestClient { public: void dwim(TestBIOS & rBIOS) { TestObject aObj; rBIOS.loadPageAt(aObj.get(), aObj.verify); rBIOS.loadPageAt(aObj.get(), TestObject::verify); rBIOS.loadPageAt(aObj.get(), PageHolderObject::verify); aObj.loadAt (1024, rBIOS); TestObjectV2 aObj2; aObj2.dwim(); aObj2->dwim(); } }; /*======================================================================*/ class IPageAccess { public: virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) = 0; public: storeError readPageAt (PageHolder & rPage, sal_uInt32 nOffset) { return readPageAt_Impl (rPage, nOffset); } storeError writePageAt (PageHolder const & rPage, sal_uInt32 nOffset) { // [SECURITY:ValInput] PageData const * pagedata = rPage.get(); OSL_PRECOND(!(pagedata == 0), "invalid Page"); if (pagedata == 0) return store_E_InvalidParameter; sal_uInt32 const offset = pagedata->offset(); OSL_PRECOND(!(nOffset != offset), "inconsistent Offset"); if (nOffset != offset) return store_E_InvalidParameter; OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::IPageAccess::writePageAt(): invalid Offset"); if (nOffset == STORE_PAGE_NULL) return store_E_CantSeek; return writePageAt_Impl (rPage, nOffset); } storeError peekAt (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) { // [SECURITY:ValInput] sal_uInt8 * dst_lo = static_cast(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; sal_uInt64 const dst_size = nOffset + nBytes; if (dst_size > SAL_MAX_UINT32) return store_E_CantSeek; return peekAt_Impl (nOffset, dst_lo, (dst_hi - dst_lo)); } storeError pokeAt (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) { // [SECURITY:ValInput] sal_uInt8 const * src_lo = static_cast(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; sal_uInt64 const dst_size = nOffset + nBytes; if (dst_size > SAL_MAX_UINT32) return store_E_CantSeek; return pokeAt_Impl (nOffset, src_lo, (src_hi - src_lo)); } storeError getSize (sal_uInt32 & rnSize) { rnSize = 0; return getSize_Impl (rnSize); } storeError setSize (sal_uInt32 nSize) { return setSize_Impl (nSize); } private: virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) = 0; virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) = 0; virtual storeError peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) = 0; virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) = 0; virtual storeError getSize_Impl (sal_uInt32 & rnSize) = 0; virtual storeError setSize_Impl (sal_uInt32 nSize) = 0; }; /*======================================================================*/ 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; } }; struct FileHandle { oslFileHandle m_handle; FileHandle() : m_handle(0) {} operator oslFileHandle() { return m_handle; } bool operator != (FileHandle const & rhs) { return (m_handle != rhs.m_handle); } oslFileError initialize (rtl_uString * pFilename, sal_uInt32 nFlags) { // Verify arguments. if (!pFilename || !nFlags) return osl_File_E_INVAL; // Convert into FileUrl. OUString aFileUrl; if (osl_getFileURLFromSystemPath (pFilename, &(aFileUrl.pData)) != osl_File_E_None) { // Not system path. Maybe a file url, already. rtl_uString_assign (&(aFileUrl.pData), pFilename); } // Acquire handle. return osl_openFile (aFileUrl.pData, &m_handle, nFlags); } struct CloseFile { void operator()(FileHandle & rFile) const { if (rFile.m_handle != 0) { // Release handle. (void) osl_closeFile (rFile.m_handle); rFile.m_handle = 0; } } }; typedef CloseFile destructor_type; }; struct FileMapping { void * m_pAddr; sal_uInt64 m_uSize; FileMapping() : m_pAddr(0), m_uSize(0) {} bool operator != (FileMapping const & rhs) const { return ((m_pAddr != rhs.m_pAddr) || (m_uSize != rhs.m_uSize)); } oslFileError initialize (oslFileHandle hFile) { // Determine mapping size. oslFileError result = osl_getFileSize (hFile, &m_uSize); if (result != osl_File_E_None) return result; if (m_uSize > SAL_MAX_UINT32) return osl_File_E_OVERFLOW; // Acquire mapping. return osl_mapFile (hFile, &m_pAddr, m_uSize, 0, 0); } struct UnmapFile { void operator ()(FileMapping & rMapping) const { if ((rMapping.m_pAddr != 0) && (rMapping.m_uSize != 0)) { // Release mapping. (void) osl_unmapFile (rMapping.m_pAddr, rMapping.m_uSize); rMapping.m_pAddr = 0, rMapping.m_uSize = 0; } } }; typedef UnmapFile destructor_type; }; /*======================================================================*/ class FilePageAccess : public IPageAccess { oslFileHandle m_hFile; public: static storeError ERROR_FROM_NATIVE (oslFileError eErrno); static sal_uInt32 MODE_TO_NATIVE (storeAccessMode eMode); public: explicit FilePageAccess (oslFileHandle hFile = 0) : m_hFile (hFile) {} virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize); private: virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); /* see @ OFileLockBytes */ virtual storeError peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); virtual storeError getSize_Impl (sal_uInt32 & rnSize); virtual storeError setSize_Impl (sal_uInt32 nSize); protected: virtual ~FilePageAccess(); private: /** Not implemented. */ FilePageAccess (FilePageAccess const &); FilePageAccess & operator= (FilePageAccess const &); }; storeError FilePageAccess::initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) { (void) eAccessMode; // UNUSED (void) nPageSize; // UNUSED return store_E_Unknown; // NYI } FilePageAccess::~FilePageAccess() { if (m_hFile != 0) (void) osl_closeFile (m_hFile); } storeError FilePageAccess::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) { PageHolder page (0/*allocate()*/); /* @@@ construct w/ deallocator argument @@@ */ if (!page.get()) return store_E_OutOfMemory; swap(page, rPage); return peekAt (nOffset, rPage.get(), 0/*size*/); } storeError FilePageAccess::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) { return pokeAt (nOffset, rPage.get(), 0/*size*/); } storeError FilePageAccess::peekAt_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 ERROR_FROM_NATIVE(result); if (nDone != nBytes) return (nDone != 0) ? store_E_CantRead : store_E_NotExists; return store_E_None; } storeError FilePageAccess::pokeAt_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 ERROR_FROM_NATIVE(result); if (nDone != nBytes) return store_E_CantWrite; return store_E_None; } storeError FilePageAccess::getSize_Impl (sal_uInt32 & rnSize) { sal_uInt64 uSize = 0; oslFileError result = osl_getFileSize (m_hFile, &uSize); if (result != osl_File_E_None) return ERROR_FROM_NATIVE(result); if (uSize > SAL_MAX_UINT32) return store_E_CantSeek; rnSize = sal::static_int_cast(uSize); return store_E_None; } storeError FilePageAccess::setSize_Impl (sal_uInt32 nSize) { oslFileError result = osl_setFileSize (m_hFile, nSize); if (result != osl_File_E_None) return ERROR_FROM_NATIVE(result); return store_E_None; } storeError FilePageAccess::ERROR_FROM_NATIVE (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_NOSPC: return store_E_OutOfSpace; case osl_File_E_OVERFLOW: return store_E_CantSeek; default: return store_E_Unknown; } } sal_uInt32 FilePageAccess::MODE_TO_NATIVE(storeAccessMode eAccessMode) { sal_uInt32 nMode = 0; switch (eAccessMode) { case store_AccessCreate: case store_AccessReadCreate: nMode |= osl_File_OpenFlag_Create; // fall through case store_AccessReadWrite: nMode |= osl_File_OpenFlag_Write; // fall through case store_AccessReadOnly: nMode |= osl_File_OpenFlag_Read; break; default: OSL_PRECOND(0, "store::FilePageAccess: unknown storeAccessMode"); } return nMode; } /*===*/ class MemoryPageAccess : public IPageAccess { /** Representation. */ sal_uInt8 * m_pData; sal_uInt32 m_nSize; /** Callback function to release Representation. */ typedef void (*destructor_type)(sal_uInt8 * pData, sal_uInt32 nSize); destructor_type m_destructor; /** Default destructor callback. */ static void freeMemory (sal_uInt8 * pData, sal_uInt32 nSize); public: MemoryPageAccess() : m_pData (0), m_nSize (0), m_destructor (MemoryPageAccess::freeMemory) {} MemoryPageAccess (sal_uInt8 * pData, sal_uInt32 nSize, destructor_type destructor = MemoryPageAccess::freeMemory) : m_pData (pData), m_nSize (nSize), m_destructor (destructor) {} virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize); private: /** Page (size aligned) access. */ virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset); virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset); /** Low level access. */ virtual storeError peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes); virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); virtual storeError getSize_Impl (sal_uInt32 & rnSize); virtual storeError setSize_Impl (sal_uInt32 nSize); protected: virtual ~MemoryPageAccess(); private: /** Not implemented. */ MemoryPageAccess (MemoryPageAccess const &); MemoryPageAccess & operator= (MemoryPageAccess const &); }; storeError MemoryPageAccess::initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) { (void) eAccessMode; // UNUSED (void) nPageSize; // UNUSED return store_E_Unknown; // NYI } MemoryPageAccess::~MemoryPageAccess() { if (m_destructor != 0) { // release resource. (*m_destructor)(m_pData, m_nSize); } } storeError MemoryPageAccess::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) { /* OSL_PRECOND(nOffset % size == 0, "Unaligned page read."); */ PageHolder page (reinterpret_cast< PageData* >(m_pData + nOffset)); swap(page, rPage); return store_E_None; } storeError MemoryPageAccess::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) { PageData const * pagedata = rPage.get(); if (!(pagedata != 0)) return store_E_InvalidParameter; return pokeAt (nOffset, pagedata, pagedata->size()); } storeError MemoryPageAccess::peekAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) { // [SECURITY:ValInput] sal_uInt8 * dst_lo = static_cast(pBuffer); if (!(dst_lo != 0)) return store_E_InvalidParameter; sal_uInt8 * dst_hi = dst_lo + nBytes; if (!(dst_lo <= dst_hi)) return store_E_InvalidParameter; // ... sal_uInt8 const * src_lo = m_pData + nOffset; if (!(src_lo <= m_pData + m_nSize)) return store_E_CantSeek; sal_uInt8 const * src_hi = src_lo + nBytes; if (!(src_hi <= m_pData + m_nSize)) return store_E_CantRead; // copy. memcpy (pBuffer, src_lo, (src_hi - src_lo)); return store_E_None; } storeError MemoryPageAccess::pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) { // [SECURITY:ValInput] sal_uInt8 const * src_lo = static_cast(pBuffer); if (!(src_lo != 0)) return store_E_InvalidParameter; sal_uInt8 const * src_hi = src_lo + nBytes; if (!(src_lo <= src_hi)) return store_E_InvalidParameter; sal_uInt64 const uSize = nOffset + nBytes; if (uSize > SAL_MAX_UINT32) return store_E_CantSeek; // ... if (uSize > m_nSize) { // increase size. storeError eErrCode = setSize (sal::static_int_cast(uSize)); if (eErrCode != store_E_None) return eErrCode; } 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; // copy. memcpy (dst_lo, src_lo, (src_hi - src_lo)); return store_E_None; } storeError MemoryPageAccess::getSize_Impl (sal_uInt32 & rnSize) { rnSize = m_nSize; return store_E_None; } storeError MemoryPageAccess::setSize_Impl (sal_uInt32 nSize) { if (nSize != m_nSize) { sal_uInt8 * pData = static_cast(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; } void MemoryPageAccess::freeMemory (sal_uInt8 * pData, sal_uInt32 /*nSize*/) { rtl_freeMemory (pData); } /*===*/ class MappedPageAccess : public MemoryPageAccess { /** @see MemoryPageAccess::destructor_type callback function. */ static void unmapFile (sal_uInt8 * pData, sal_uInt32 nSize); public: MappedPageAccess (sal_uInt8 * pData, sal_uInt32 nSize); virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize); virtual storeError writePageAt (PageHolder const & rPage, sal_uInt32 nOffset); private: virtual storeError pokeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes); virtual storeError setSize_Impl (sal_uInt32 nSize); protected: virtual ~MappedPageAccess() {} }; MappedPageAccess::MappedPageAccess (sal_uInt8 * pData, sal_uInt32 nSize) : MemoryPageAccess (pData, nSize, MappedPageAccess::unmapFile) { } storeError MappedPageAccess::initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) { OSL_PRECOND(eAccessMode == store_AccessReadOnly, "store::MappedPageAccess: invalid AccessMode"); return MemoryPageAccess::initialize (eAccessMode, nPageSize); } storeError MappedPageAccess::writePageAt (PageHolder const & /*rPage*/, sal_uInt32 /*nOffset*/) { return store_E_AccessViolation; } storeError MappedPageAccess::pokeAt_Impl (sal_uInt32 /*nOffset*/, void const * /*pBuffer*/, sal_uInt32 /*nBytes*/) { return store_E_AccessViolation; } storeError MappedPageAccess::setSize_Impl (sal_uInt32 /*nSize*/) { return store_E_AccessViolation; } void MappedPageAccess::unmapFile (sal_uInt8 * pData, sal_uInt32 nSize) { (void) osl_unmapFile (pData, nSize); } /*======================================================================== * * main. * *======================================================================*/ #include int SAL_CALL main (int argc, char ** argv) { OSL_PRECOND(argc >= 1, "t_page: error: insufficient number of arguments."); if (argc < 1) return 0; { void *a = (void*)1, *b = (void*)2; swap(a, b); } { PageObject a; PageObject b (a); PageObject c; c = b; a = a; } { TestBIOS aBIOS; TestClient aClient; aClient.dwim (aBIOS); } if (argc > 1) { rtl_uString * pFilename = 0; rtl_uString_newFromAscii (&pFilename, argv[1]); storeAccessMode eAccessMode = store_AccessReadOnly; // Acquire file handle. ResourceHolder h1; oslFileError result = h1.get().initialize (pFilename, FilePageAccess::MODE_TO_NATIVE(eAccessMode)); if (result == osl_File_E_None) { ResourceHolder h2 (h1); h1 = h2; if (eAccessMode == store_AccessReadOnly) { ResourceHolder m1; result = m1.get().initialize (h1.get()); const sal_uInt32 nSize = sal::static_int_cast(m1.get().m_uSize); (void) nSize; // UNUSED ResourceHolder m2 (m1); m1 = m2; return result; } } } return 0; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */