blob: 219c3c6f40c7bc5e30e504ca40eb979753bc3654 [file] [log] [blame]
/**************************************************************
*
* 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.
*
*************************************************************/
/*
* t_page.cxx
*/
#include "osl/diagnose.h"
#include "rtl/alloc.h"
#include "rtl/ref.hxx"
#include "storbase.hxx"
#include "osl/file.h"
#include "rtl/ustring.hxx"
/*========================================================================
*
* OTest...
*
*======================================================================*/
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<long*>(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<long*>(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<SharedCount>(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 0 /* OLD */
typedef store::OStorePageData PageData;
#else /* NEW */
#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;
STORE_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;
}
};
#endif /* NEW */
class IPageAllocator
{
public:
virtual void deallocate (void * p) = 0;
};
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<rtl_cache_type*>(lhs.m_cache, rhs.m_cache);
swap<SharedCount>(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<PageAllocator>(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<SharedCount>(lhs.m_refcount, rhs.m_refcount);
swap<PageData*>(lhs.m_pagedata, rhs.m_pagedata);
swap<PageHolder::allocator_type>(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<PageHolder>(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<U>(p) ? static_cast<U*>(p) : 0;
}
template< class U >
static U const * dynamic_page_cast (PageData const * p)
{
return isA<U>(p) ? static_cast<U const *>(p) : 0;
}
public:
static PageHolderObject<T> construct (rtl::Reference< PageData::Allocator > const & rxAllocator)
{
PageHolderObject<T> tmp;
if (rxAllocator.is())
{
PageHolder xPage (rxAllocator->construct<T>(), rxAllocator);
store::swap<PageHolder>(tmp.m_xPage, xPage);
}
return tmp;
}
explicit PageHolderObject (PageHolder const & rxPage = PageHolder())
: m_xPage (rxPage)
{}
void swap (PageHolderObject<T> & rhs)
{
store::swap<PageHolder>(m_xPage, rhs.m_xPage);
}
PageHolderObject (PageHolderObject<T> const & rhs)
: m_xPage (rhs.m_xPage)
{
}
PageHolderObject<T> & operator= (PageHolderObject<T> const & rhs)
{
PageHolderObject<T> tmp (rhs);
this->swap(tmp);
return *this;
}
T * operator->()
{
T * pImpl = dynamic_page_cast<T>(m_xPage.get());
OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator->(): Null pointer");
return pImpl;
}
T const * operator->() const
{
T const * pImpl = dynamic_page_cast<T>(m_xPage.get());
OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator->(): Null pointer");
return pImpl;
}
T & operator*()
{
T * pImpl = dynamic_page_cast<T>(m_xPage.get());
OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer");
return *pImpl;
}
T const & operator*() const
{
T const * pImpl = dynamic_page_cast<T>(m_xPage.get());
OSL_PRECOND(pImpl != 0, "store::PageHolder<T>::operator*(): Null pointer");
return *pImpl;
}
static storeError guard (PageHolder & rxPage)
{
T * pImpl = dynamic_page_cast<T>(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<T>(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<T*>(pagedata);
return 0;
}
template< class T >
T * dynamic_page_cast (PageData const * pagedata)
{
if ((pagedata != 0) && (pagedata->type() == T::theTypeId))
return static_cast<T*>(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<T>::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<TestData>::verify);
aObj.loadAt (1024, rBIOS);
TestObjectV2 aObj2;
aObj2.dwim();
aObj2->dwim();
}
};
/*======================================================================*/
#if 0 /* NYI */
BIOS::load (PageObject & rPage, sal_uInt32 nOffset)
{
result = m_xCache->readPageAt (rPage.get(), nOffset);
if (result == NotExists)
{
result = m_xLockBytes->readPageAt (rPage.get(), nOffset);
if (result != None)
return result;
result = rPage.verify();
if (result != None)
return result;
result = m_xCache->writePageAt (rPage.get(), nOffset);
}
return result;
}
BIOS::save (PageObject & rPage, sal_uInt32 nOffset)
{
rPage.guard();
result = m_xLockBytes->writePageAt (rPage.get(), nOffset);
if (result != None)
return result;
return m_xCache->writePageAt (rPage.get(), nOffset);
}
BIOS::init (rxLockBytes, eAccessMode, nPageSize)
{
SuperPage super;
if (eAccessMode == store_AccessCreate)
{
sal_uInt16 pagesize = nPageSize;
if ((STORE_MINIMUM_PAGESIZE > pagesize) || (pagesize > STORE_MAXIMUM_PAGESIZE))
return store_E_InvalidParameter;
pagesize = ((pagesize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
rxLockBytes->init (pagesize);
super = allocator->construct<SuperPage>();
super->guard();
rxLockBytes->writeAt (0, super, super->size());
}
if (eAccessMode != store_AccessCreate)
{
rxLockBytes->readAt (0, &super, super::theSize);
super.verify();
}
if (eErrCode != store_E_NotExists)
}
#endif /* NYI */
/*======================================================================*/
#if 0 /* NYI */
class PageCache
{
std::set<const sal_uInt32, PageObject> m_pages;
public:
storeError readPageAt (PageObject & rPage, sal_uInt32 nOffset);
storeError writePageAt (PageObject const & rPage, sal_uInt32 nOffset);
};
#endif /* NYI */
/*======================================================================*/
class IPageAllocator;
class IPageAccess
{
public:
virtual storeError initialize (storeAccessMode eAccessMode, sal_uInt16 nPageSize) = 0;
virtual IPageAllocator & getAllocator () = 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<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;
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<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;
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.
rtl::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<PageHolder>(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<sal_uInt32>(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<PageHolder>(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;
#if 0 /* NYI */
sal_uInt16 const bytes = pagedata->size(); // Descr.m_nSize;
OSL_ASSERT(bytes >= PageData::thePageSize);
offset = rPage.location(); // Descr.m_nAddr;
OSL_ASSERT(nOffset == offset);
OSL_PRECOND(offset % bytes == 0, "Unaligned page write.");
#endif /* NYI */
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<sal_uInt8*>(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<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 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<sal_uInt32>(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<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;
}
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);
}
#if 0 /* NYI */
storeError MemoryPageAccess_createInstance (
rtl::Reference< IPageAccess > & rxPageAccess,
storeAccessMode eAccessMode,
sal_uInt16 nPageSize
)
{
rxPageAccess = new MemoryPageAccess();
if (!rxPageAccess.is())
return store_E_OutOfMemory;
return rxPageAccess->initialize (eAccessMode, nPageSize);
}
storeError FilePageAccess_createInstance (
rtl::Reference< IPageAccess > & rxPageAccess,
rtl_uString * pFilename,
storeAccessMode eAccessMode,
sal_uInt16 nPageSize
)
{
// Acquire file handle.
ResourceHolder<FileHandle> xFile;
result = xFile.get().initialize (pFilename, MODE_TO_NATIVE(eAccessMode));
if (result != osl_File_E_None)
return ERROR_FROM_NATIVE(result);
if (eAccessMode == store_AccessReadOnly)
{
ResourceHolder<FileMapping> xMapping;
result = xMapping.get().initialize (xFile.get());
if (result == osl_File_E_None)
{
const sal_uInt32 nSize = sal::static_int_cast<sal_uInt32>(xMapping.get().m_uSize);
rxPageAccess = new MappedPageAccess (xMapping.get().m_pAddr, nSize);
if (!rxPageAccess.is())
return store_E_OutOfMemory;
(void) xMapping.release();
}
}
if (!rxPageAccess.is())
{
rxPageAccess = new FilePageAccess (xFile.get());
if (!rxPageAccess.is())
return store_E_OutOfMemory;
(void) xFile.release();
}
return rxPageAccess->initialize (eAccessMode, nPageSize);
}
#endif /* NYI */
/*========================================================================
*
* test...
*
*======================================================================*/
#if 0 /* NYI */
struct IDataBlock
{
virtual sal_uInt16 singleCount() const = 0;
virtual sal_uInt32 singleLink (sal_uInt16 nIndex) const = 0;
virtual void singleLink (sal_uInt16 nIndex, sal_uInt32 nAddr) = 0;
virtual storeError get() = 0;
virtual storeError put() = 0;
virtual storeError truncate() = 0;
};
struct InodePageData : public PageData
{
virtual INameBlock & getNameBlock() = 0;
virtual IDataBlock & getDataBlock() = 0;
};
template< class page_data_type >
page_data_type * query (PageData *, page_data_type *);
template<> InodePageDataV2*
query (PageData & rData, InodePageDataV2 *)
{
if (rData.isKindOf(InodePageDataV2::m_nTypeId))
return static_cast<InodePageDataV2*>(&rData);
return 0;
}
class InodePageObject : public PageObject
{
public:
static InodePageObject createInstance (PageData & rData)
{
if (query(&rData, static_cast<InodePageDataV2*>(0)))
return InodePageObjectV2 (static_cast<InodePageDataV2&>(rData));
else if (query(&rData, static_cast<InodePageDataV1*>(0)))
return InodePageObjectV1 (static_cast<InodePageDataV1&>(rData));
}
};
#endif /* NYI */
/*========================================================================
*
* main.
*
*======================================================================*/
#include <stdio.h>
#if 0 /* EXP */
class Interface
{
public:
virtual void deallocate(void *) /* = 0 */;
};
class Implementation : public Interface
{
SharedCount m_count;
public:
Implementation() : Interface() { printf("Ctor(%p)\n", this); }
~Implementation() { printf("Dtor(%p)\n", this); }
Implementation (Implementation const & rhs) : Interface(), m_count (rhs.m_count) { printf("CopyCtor(%p)\n", this); }
virtual void deallocate(void *) {}
};
Interface Interface_createInstance()
{
Implementation aInst;
return aInst;
}
#endif /* EXP */
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<void*>(a, b);
}
{
PageObject a;
PageObject b (a);
PageObject c;
c = b;
a = a;
}
{
TestBIOS aBIOS;
TestClient aClient;
aClient.dwim (aBIOS);
}
#if 0 /* EXP */
{
Interface aIfc1 (Interface_createInstance());
Interface aIfc2 (aIfc1);
}
#endif /* EXP */
if (argc > 1)
{
rtl_uString * pFilename = 0;
rtl_uString_newFromAscii (&pFilename, argv[1]);
storeAccessMode eAccessMode = store_AccessReadOnly;
// Acquire file handle.
ResourceHolder<FileHandle> h1;
oslFileError result = h1.get().initialize (pFilename, FilePageAccess::MODE_TO_NATIVE(eAccessMode));
if (result == osl_File_E_None)
{
ResourceHolder<FileHandle> h2 (h1);
h1 = h2;
if (eAccessMode == store_AccessReadOnly)
{
ResourceHolder<FileMapping> m1;
result = m1.get().initialize (h1.get());
const sal_uInt32 nSize = sal::static_int_cast<sal_uInt32>(m1.get().m_uSize);
(void) nSize; // UNUSED
ResourceHolder<FileMapping> m2 (m1);
m1 = m2;
result = osl_File_E_None;
}
}
}
return 0;
}