mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-23 12:35:50 +00:00
Add RandomAccessFile
This commit is contained in:
@@ -140,6 +140,7 @@
|
|||||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileOutputStream.h" />
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileOutputStream.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_core\files\beast_FileSearchPath.h" />
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileSearchPath.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_core\files\beast_MemoryMappedFile.h" />
|
<ClInclude Include="..\..\modules\beast_core\files\beast_MemoryMappedFile.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_RandomAccessFile.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_core\files\beast_TemporaryFile.h" />
|
<ClInclude Include="..\..\modules\beast_core\files\beast_TemporaryFile.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_core\json\beast_JSON.h" />
|
<ClInclude Include="..\..\modules\beast_core\json\beast_JSON.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_core\logging\beast_FileLogger.h" />
|
<ClInclude Include="..\..\modules\beast_core\logging\beast_FileLogger.h" />
|
||||||
@@ -437,6 +438,12 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_RandomAccessFile.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\modules\beast_core\files\beast_TemporaryFile.cpp">
|
<ClCompile Include="..\..\modules\beast_core\files\beast_TemporaryFile.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
|||||||
@@ -623,6 +623,9 @@
|
|||||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SharedObjectArray.h">
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_SharedObjectArray.h">
|
||||||
<Filter>beast_core\containers</Filter>
|
<Filter>beast_core\containers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_RandomAccessFile.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
||||||
@@ -967,6 +970,9 @@
|
|||||||
<ClCompile Include="..\..\modules\beast_crypto\math\beast_UnsignedInteger.cpp">
|
<ClCompile Include="..\..\modules\beast_crypto\math\beast_UnsignedInteger.cpp">
|
||||||
<Filter>beast_crypto\math</Filter>
|
<Filter>beast_crypto\math</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_RandomAccessFile.cpp">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="..\..\TODO.txt" />
|
<Text Include="..\..\TODO.txt" />
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ namespace beast
|
|||||||
#include "files/beast_FileInputStream.cpp"
|
#include "files/beast_FileInputStream.cpp"
|
||||||
#include "files/beast_FileOutputStream.cpp"
|
#include "files/beast_FileOutputStream.cpp"
|
||||||
#include "files/beast_FileSearchPath.cpp"
|
#include "files/beast_FileSearchPath.cpp"
|
||||||
|
#include "files/beast_RandomAccessFile.cpp"
|
||||||
#include "files/beast_TemporaryFile.cpp"
|
#include "files/beast_TemporaryFile.cpp"
|
||||||
|
|
||||||
#include "json/beast_JSON.cpp"
|
#include "json/beast_JSON.cpp"
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ namespace beast
|
|||||||
#include "files/beast_FileOutputStream.h"
|
#include "files/beast_FileOutputStream.h"
|
||||||
#include "files/beast_FileSearchPath.h"
|
#include "files/beast_FileSearchPath.h"
|
||||||
#include "files/beast_MemoryMappedFile.h"
|
#include "files/beast_MemoryMappedFile.h"
|
||||||
|
#include "files/beast_RandomAccessFile.h"
|
||||||
#include "files/beast_TemporaryFile.h"
|
#include "files/beast_TemporaryFile.h"
|
||||||
#include "json/beast_JSON.h"
|
#include "json/beast_JSON.h"
|
||||||
#include "logging/beast_FileLogger.h"
|
#include "logging/beast_FileLogger.h"
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.com
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
RandomAccessFile::RandomAccessFile (int bufferSizeToUse) noexcept
|
||||||
|
: fileHandle (nullptr)
|
||||||
|
, currentPosition (0)
|
||||||
|
, bufferSize (bufferSizeToUse)
|
||||||
|
, bytesInBuffer (0)
|
||||||
|
, writeBuffer (bmax (bufferSizeToUse, 16)) // enforce minimum size of 16
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomAccessFile::~RandomAccessFile ()
|
||||||
|
{
|
||||||
|
close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::open (File const& path, Mode mode)
|
||||||
|
{
|
||||||
|
close ();
|
||||||
|
|
||||||
|
return nativeOpen (path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomAccessFile::close ()
|
||||||
|
{
|
||||||
|
if (isOpen ())
|
||||||
|
{
|
||||||
|
flushBuffer ();
|
||||||
|
nativeFlush ();
|
||||||
|
nativeClose ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::setPosition (FileOffset newPosition)
|
||||||
|
{
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
if (newPosition != currentPosition)
|
||||||
|
{
|
||||||
|
flushBuffer ();
|
||||||
|
|
||||||
|
result = nativeSetPosition (newPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount)
|
||||||
|
{
|
||||||
|
return nativeRead (buffer, numBytes, pActualAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::write (const void* data, ByteCount numBytes, ByteCount* pActualAmount)
|
||||||
|
{
|
||||||
|
bassert (data != nullptr && ((ssize_t) numBytes) >= 0);
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
ByteCount amountWritten = 0;
|
||||||
|
|
||||||
|
if (bytesInBuffer + numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
memcpy (writeBuffer + bytesInBuffer, data, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = flushBuffer ();
|
||||||
|
|
||||||
|
if (result.wasOk ())
|
||||||
|
{
|
||||||
|
if (numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
bassert (bytesInBuffer == 0);
|
||||||
|
|
||||||
|
memcpy (writeBuffer + bytesInBuffer, data, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ByteCount bytesWritten;
|
||||||
|
|
||||||
|
result = nativeWrite (data, numBytes, &bytesWritten);
|
||||||
|
|
||||||
|
if (result.wasOk ())
|
||||||
|
currentPosition += bytesWritten;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pActualAmount != nullptr)
|
||||||
|
*pActualAmount = amountWritten;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::truncate ()
|
||||||
|
{
|
||||||
|
Result result = flush ();
|
||||||
|
|
||||||
|
if (result.wasOk ())
|
||||||
|
result = nativeTruncate ();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::flush ()
|
||||||
|
{
|
||||||
|
Result result = flushBuffer ();
|
||||||
|
|
||||||
|
if (result.wasOk ())
|
||||||
|
result = nativeFlush ();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::flushBuffer ()
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
if (bytesInBuffer > 0)
|
||||||
|
{
|
||||||
|
result = nativeWrite (writeBuffer, bytesInBuffer);
|
||||||
|
bytesInBuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class RandomAccessFileTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RandomAccessFileTests () : UnitTest ("RandomAccessFile")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Payload
|
||||||
|
{
|
||||||
|
Payload (int maxBytes)
|
||||||
|
: bufferSize (maxBytes)
|
||||||
|
, data (maxBytes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a pseudo-random payload
|
||||||
|
void generate (int64 seedValue) noexcept
|
||||||
|
{
|
||||||
|
Random r (seedValue);
|
||||||
|
|
||||||
|
bytes = 1 + r.nextInt (bufferSize);
|
||||||
|
|
||||||
|
bassert (bytes >= 1 && bytes <= bufferSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes; ++i)
|
||||||
|
data [i] = static_cast <unsigned char> (r.nextInt ());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (Payload const& other) const noexcept
|
||||||
|
{
|
||||||
|
if (bytes == other.bytes)
|
||||||
|
{
|
||||||
|
return memcmp (data.getData (), other.data.getData (), bytes) == 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int const bufferSize;
|
||||||
|
int bytes;
|
||||||
|
HeapBlock <char> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void runTest ()
|
||||||
|
{
|
||||||
|
Result result = file.open (File::createTempFile ("tests"), RandomAccessFile::readWrite);
|
||||||
|
|
||||||
|
expect (result.wasOk (), "Should be ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RandomAccessFile file;
|
||||||
|
};
|
||||||
|
|
||||||
|
static RandomAccessFileTests randomAccessFileTests;
|
||||||
242
Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h
Normal file
242
Subtrees/beast/modules/beast_core/files/beast_RandomAccessFile.h
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.com
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_RANDOMACCESSFILE_H_INCLUDED
|
||||||
|
#define BEAST_RANDOMACCESSFILE_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../misc/beast_Result.h"
|
||||||
|
|
||||||
|
/** Provides random access reading and writing to an operating system file.
|
||||||
|
|
||||||
|
This class wraps the underlying native operating system routines for
|
||||||
|
opening and closing a file for reading and/or writing, seeking within
|
||||||
|
the file, and performing read and write operations. There are also methods
|
||||||
|
provided for obtaining an input or output stream which will work with
|
||||||
|
the file.
|
||||||
|
|
||||||
|
Writes are batched using an internal buffer. The buffer is flushed when
|
||||||
|
it fills, the current position is manually changed, or the file
|
||||||
|
is closed. It is also possible to explicitly flush the buffer.
|
||||||
|
|
||||||
|
@note All files are opened in binary mode. No text newline conversions
|
||||||
|
are performed.
|
||||||
|
|
||||||
|
@see FileInputStream, FileOutputStream
|
||||||
|
*/
|
||||||
|
class BEAST_API RandomAccessFile : Uncopyable, LeakChecked <RandomAccessFile>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The type of an FileOffset.
|
||||||
|
|
||||||
|
This can be useful when writing templates.
|
||||||
|
*/
|
||||||
|
typedef int64 FileOffset;
|
||||||
|
|
||||||
|
/** The type of a byte count.
|
||||||
|
|
||||||
|
This can be useful when writing templates.
|
||||||
|
*/
|
||||||
|
typedef size_t ByteCount;
|
||||||
|
|
||||||
|
/** The access mode.
|
||||||
|
|
||||||
|
@see open
|
||||||
|
*/
|
||||||
|
enum Mode
|
||||||
|
{
|
||||||
|
readOnly,
|
||||||
|
readWrite
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an unopened file object.
|
||||||
|
|
||||||
|
@see open, isOpen
|
||||||
|
*/
|
||||||
|
explicit RandomAccessFile (int bufferSizeToUse = 16384) noexcept;
|
||||||
|
|
||||||
|
/** Destroy the file object.
|
||||||
|
|
||||||
|
If the operating system file is open it will be closed.
|
||||||
|
*/
|
||||||
|
~RandomAccessFile ();
|
||||||
|
|
||||||
|
/** Determine if a file is open.
|
||||||
|
|
||||||
|
@return `true` if the operating system file is open.
|
||||||
|
*/
|
||||||
|
bool isOpen () const noexcept { return fileHandle != nullptr; }
|
||||||
|
|
||||||
|
/** Opens a file object.
|
||||||
|
|
||||||
|
The file is opened with the specified permissions. The initial
|
||||||
|
position is set to the beginning of the file.
|
||||||
|
|
||||||
|
@note If a file is already open, it will be closed first.
|
||||||
|
|
||||||
|
@param path The path to the file
|
||||||
|
@param mode The access permissions
|
||||||
|
@return An indication of the success of the operation.
|
||||||
|
|
||||||
|
@see Mode
|
||||||
|
*/
|
||||||
|
Result open (File const& path, Mode mode);
|
||||||
|
|
||||||
|
/** Closes the file object.
|
||||||
|
|
||||||
|
Any data that needs to be flushed will be written before the file is closed.
|
||||||
|
|
||||||
|
@note If no file is opened, this call does nothing.
|
||||||
|
*/
|
||||||
|
void close ();
|
||||||
|
|
||||||
|
/** Retrieve the @ref File associated with this object.
|
||||||
|
|
||||||
|
@return The associated @ref File.
|
||||||
|
*/
|
||||||
|
File const& getFile () const noexcept { return file; }
|
||||||
|
|
||||||
|
/** Get the current position.
|
||||||
|
|
||||||
|
The next read or write will take place from here.
|
||||||
|
|
||||||
|
@return The current position, as an absolute byte FileOffset from the begining.
|
||||||
|
*/
|
||||||
|
FileOffset getPosition () const noexcept { return currentPosition; }
|
||||||
|
|
||||||
|
/** Set the current position.
|
||||||
|
|
||||||
|
The next read or write will take place at this location.
|
||||||
|
|
||||||
|
@param newPosition The byte FileOffset from the beginning of the file to move to.
|
||||||
|
|
||||||
|
@return `true` if the operation was successful.
|
||||||
|
*/
|
||||||
|
Result setPosition (FileOffset newPosition);
|
||||||
|
|
||||||
|
/** Read data at the current position.
|
||||||
|
|
||||||
|
The caller is responsible for making sure that the memory pointed to
|
||||||
|
by `buffer` is at least as large as `bytesToRead`.
|
||||||
|
|
||||||
|
@note The file must have been opened with read permission.
|
||||||
|
|
||||||
|
@param buffer The memory to store the incoming data
|
||||||
|
@param numBytes The number of bytes to read.
|
||||||
|
@param pActualAmount Pointer to store the actual amount read, or `nullptr`.
|
||||||
|
|
||||||
|
@return `true` if all the bytes were read.
|
||||||
|
*/
|
||||||
|
Result read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0);
|
||||||
|
|
||||||
|
/** Write data at the current position.
|
||||||
|
|
||||||
|
The current position is advanced past the data written. If data is
|
||||||
|
written past the end of the file, the file size is increased on disk.
|
||||||
|
|
||||||
|
The caller is responsible for making sure that the memory pointed to
|
||||||
|
by `buffer` is at least as large as `bytesToWrite`.
|
||||||
|
|
||||||
|
@note The file must have been opened with write permission.
|
||||||
|
|
||||||
|
@param data A pointer to the data buffer to write to the file.
|
||||||
|
@param numBytes The number of bytes to write.
|
||||||
|
@param pActualAmount Pointer to store the actual amount written, or `nullptr`.
|
||||||
|
|
||||||
|
@return `true` if all the data was written.
|
||||||
|
*/
|
||||||
|
Result write (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0);
|
||||||
|
|
||||||
|
/** Truncate the file at the current position.
|
||||||
|
*/
|
||||||
|
Result truncate ();
|
||||||
|
|
||||||
|
/** Flush the output buffers.
|
||||||
|
|
||||||
|
This calls the operating system to make sure all data has been written.
|
||||||
|
*/
|
||||||
|
Result flush();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private:
|
||||||
|
Result flushBuffer ();
|
||||||
|
|
||||||
|
// Some of these these methods are implemented natively on
|
||||||
|
// the corresponding platform.
|
||||||
|
//
|
||||||
|
// See beast_posix_SharedCode.h and beast_win32_Files.cpp
|
||||||
|
Result nativeOpen (File const& path, Mode mode);
|
||||||
|
void nativeClose ();
|
||||||
|
Result nativeSetPosition (FileOffset newPosition);
|
||||||
|
Result nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0);
|
||||||
|
Result nativeWrite (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0);
|
||||||
|
Result nativeTruncate ();
|
||||||
|
Result nativeFlush ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
File file;
|
||||||
|
void* fileHandle;
|
||||||
|
FileOffset currentPosition;
|
||||||
|
ByteCount const bufferSize;
|
||||||
|
ByteCount bytesInBuffer;
|
||||||
|
HeapBlock <char> writeBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BEAST_API RandomAccessFileInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit RandomAccessFileInputStream (RandomAccessFile& file) : m_file (file) { }
|
||||||
|
|
||||||
|
int64 getTotalLength() { return m_file.getFile ().getSize (); }
|
||||||
|
bool isExhausted() { return getPosition () == getTotalLength (); }
|
||||||
|
int read (void* destBuffer, int maxBytesToRead)
|
||||||
|
{
|
||||||
|
size_t actualBytes = 0;
|
||||||
|
m_file.read (destBuffer, maxBytesToRead, &actualBytes);
|
||||||
|
return actualBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 getPosition() { return m_file.getPosition (); }
|
||||||
|
bool setPosition (int64 newPosition) { return m_file.setPosition (newPosition); }
|
||||||
|
void skipNextBytes (int64 numBytesToSkip) { m_file.setPosition (getPosition () + numBytesToSkip); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RandomAccessFile& m_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BEAST_API RandomAccessFileOutputStream : public OutputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit RandomAccessFileOutputStream (RandomAccessFile& file) : m_file (file) { }
|
||||||
|
|
||||||
|
void flush() { m_file.flush (); }
|
||||||
|
int64 getPosition() { return m_file.getPosition (); }
|
||||||
|
bool setPosition (int64 newPosition) { return m_file.setPosition (newPosition); }
|
||||||
|
bool write (const void* dataToWrite, size_t numberOfBytes) { return m_file.write (dataToWrite, numberOfBytes); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RandomAccessFile& m_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -45,13 +45,16 @@
|
|||||||
|
|
||||||
@code
|
@code
|
||||||
|
|
||||||
class MyClass : Uncopyable
|
class MyClass : public Uncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//...
|
//...
|
||||||
};
|
};
|
||||||
|
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
@note The derivation should be public or else child classes which
|
||||||
|
also derive from Uncopyable may not compile.
|
||||||
*/
|
*/
|
||||||
class Uncopyable
|
class Uncopyable
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -504,6 +504,176 @@ Result FileOutputStream::truncate()
|
|||||||
return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
|
return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
RandomAccessFile::RandomAccessFile (int bufferSizeToUse) noexcept
|
||||||
|
: fileHandle (nullptr)
|
||||||
|
, currentPosition (0)
|
||||||
|
, writeBuffer (bufferSizeToUse)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomAccessFile::~RandomAccessFile ()
|
||||||
|
{
|
||||||
|
close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::open (File const& path, Mode mode)
|
||||||
|
{
|
||||||
|
close ();
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
if (path.exists())
|
||||||
|
{
|
||||||
|
int oflag;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case readOnly:
|
||||||
|
oflag = O_RDONLY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case readWRite:
|
||||||
|
oflag = O_RDWR;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
const int f = ::open (path.getFullPathName().toUTF8(), oflag, 00644);
|
||||||
|
|
||||||
|
if (f != -1)
|
||||||
|
{
|
||||||
|
currentPosition = lseek (f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (currentPosition >= 0)
|
||||||
|
{
|
||||||
|
file = path;
|
||||||
|
fileHandle = fdToVoidPointer (f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = getResultForErrno();
|
||||||
|
::close (f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = getResultForErrno();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == readWrite)
|
||||||
|
{
|
||||||
|
const int f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644);
|
||||||
|
|
||||||
|
if (f != -1)
|
||||||
|
{
|
||||||
|
file = path;
|
||||||
|
fileHandle = fdToVoidPointer (f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = getResultForErrno();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// file doesn't exist and we're opening read-only
|
||||||
|
Result::fail (String (strerror (ENOENT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomAccessFile::close ()
|
||||||
|
{
|
||||||
|
if (fileHandle != nullptr)
|
||||||
|
{
|
||||||
|
file = File::nonexistent ();
|
||||||
|
::close (getFD (fileHandle));
|
||||||
|
fileHandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::setPosition (Offset newPosition)
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
off_t const actual = lseek (getFD (fileHandle), newPosition, SEEK_SET);
|
||||||
|
|
||||||
|
if (actual != newPosition)
|
||||||
|
result = getResultForErrno();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount )
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
ssize_t amount = ::read (getFD (fileHandle), buffer, numBytes);
|
||||||
|
|
||||||
|
if (amount < 0)
|
||||||
|
{
|
||||||
|
result = getResultForErrno();
|
||||||
|
amount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pActualAmount != nullptr)
|
||||||
|
*pActualAmount = amount;
|
||||||
|
|
||||||
|
return (size_t) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::write (void const* data, ByteCount numBytes, size_t* pActualAmount)
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
ssize_t const actual = ::write (getFD (fileHandle), data, numBytes);
|
||||||
|
|
||||||
|
if (actual == -1)
|
||||||
|
{
|
||||||
|
status = getResultForErrno();
|
||||||
|
actual = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pActualAmount != nullptr)
|
||||||
|
*pActualAmount = actual;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::truncate ()
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
|
||||||
|
return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomAccessFile::flush ()
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
if (fileHandle != nullptr)
|
||||||
|
{
|
||||||
|
if (fsync (getFD (fileHandle)) == -1)
|
||||||
|
status = getResultForErrno();
|
||||||
|
|
||||||
|
#if BEAST_ANDROID
|
||||||
|
// This stuff tells the OS to asynchronously update the metadata
|
||||||
|
// that the OS has cached aboud the file - this metadata is used
|
||||||
|
// when the device is acting as a USB drive, and unless it's explicitly
|
||||||
|
// refreshed, it'll get out of step with the real file.
|
||||||
|
const LocalRef<jstring> t (javaString (file.getFullPathName()));
|
||||||
|
android.activity.callVoidMethod (BeastAppActivity.scanFile, t.get());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
|
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -307,6 +307,161 @@ Result FileOutputStream::truncate()
|
|||||||
: WindowsFileHelpers::getResultForLastError();
|
: WindowsFileHelpers::getResultForLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
Result RandomAccessFile::nativeOpen (File const& path, Mode mode)
|
||||||
|
{
|
||||||
|
bassert (! isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
DWORD dwDesiredAccess;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case readOnly:
|
||||||
|
dwDesiredAccess = GENERIC_READ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case readWrite:
|
||||||
|
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
DWORD dwCreationDisposition;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case readOnly:
|
||||||
|
dwCreationDisposition = OPEN_EXISTING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case readWrite:
|
||||||
|
dwCreationDisposition = OPEN_ALWAYS;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
HANDLE h = CreateFile (path.getFullPathName().toWideCharPointer(),
|
||||||
|
dwDesiredAccess,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
0,
|
||||||
|
dwCreationDisposition,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
file = path;
|
||||||
|
fileHandle = h;
|
||||||
|
|
||||||
|
result = setPosition (0);
|
||||||
|
|
||||||
|
if (result.failed ())
|
||||||
|
nativeClose ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = WindowsFileHelpers::getResultForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RandomAccessFile::nativeClose ()
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
CloseHandle ((HANDLE) fileHandle);
|
||||||
|
|
||||||
|
file = File::nonexistent ();
|
||||||
|
fileHandle = nullptr;
|
||||||
|
currentPosition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::nativeSetPosition (FileOffset newPosition)
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
li.QuadPart = newPosition;
|
||||||
|
li.LowPart = SetFilePointer ((HANDLE) fileHandle,
|
||||||
|
(LONG) li.LowPart,
|
||||||
|
&li.HighPart,
|
||||||
|
FILE_BEGIN);
|
||||||
|
|
||||||
|
if (li.LowPart != INVALID_SET_FILE_POINTER)
|
||||||
|
{
|
||||||
|
currentPosition = li.QuadPart;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = WindowsFileHelpers::getResultForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount )
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
DWORD actualNum = 0;
|
||||||
|
|
||||||
|
if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
|
||||||
|
result = WindowsFileHelpers::getResultForLastError();
|
||||||
|
|
||||||
|
if (pActualAmount != nullptr)
|
||||||
|
*pActualAmount = actualNum;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::nativeWrite (void const* data, ByteCount numBytes, size_t* pActualAmount)
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
DWORD actualNum = 0;
|
||||||
|
|
||||||
|
if (! WriteFile ((HANDLE) fileHandle, data, (DWORD) numBytes, &actualNum, 0))
|
||||||
|
result = WindowsFileHelpers::getResultForLastError();
|
||||||
|
|
||||||
|
if (pActualAmount != nullptr)
|
||||||
|
*pActualAmount = actualNum;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::nativeTruncate ()
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
if (! SetEndOfFile ((HANDLE) fileHandle))
|
||||||
|
result = WindowsFileHelpers::getResultForLastError();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RandomAccessFile::nativeFlush ()
|
||||||
|
{
|
||||||
|
bassert (isOpen ());
|
||||||
|
|
||||||
|
Result result (Result::ok ());
|
||||||
|
|
||||||
|
if (! FlushFileBuffers ((HANDLE) fileHandle))
|
||||||
|
result = WindowsFileHelpers::getResultForLastError();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
|
void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
class BEAST_API MemoryOutputStream
|
class BEAST_API MemoryOutputStream
|
||||||
: public OutputStream
|
: public OutputStream
|
||||||
, LeakChecked <MemoryOutputStream>
|
, LeakChecked <MemoryOutputStream>
|
||||||
, Uncopyable
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class File;
|
|||||||
|
|
||||||
@see InputStream, MemoryOutputStream, FileOutputStream
|
@see InputStream, MemoryOutputStream, FileOutputStream
|
||||||
*/
|
*/
|
||||||
class BEAST_API OutputStream
|
class BEAST_API OutputStream : public Uncopyable
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user