Skip to content

Commit

Permalink
Add static isAscii checks to FileDescriptor class. Refs #7263
Browse files Browse the repository at this point in the history
  • Loading branch information
martyngigg committed Jul 4, 2013
1 parent 5eec929 commit bbc2514
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ namespace Mantid
*/
class MANTID_KERNEL_DLL FileDescriptor
{
public:
/// Returns true if the file is considered ascii
static bool isAscii(const std::string & filename, const size_t nbytes=256);
/// Returns true if the stream is considered ascii
static bool isAscii(std::istream & data, const size_t nbytes=256);

public:
/// Constructor accepting a filename
FileDescriptor(const std::string & filename);
Expand Down
61 changes: 61 additions & 0 deletions Code/Mantid/Framework/Kernel/src/FileDescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,67 @@ namespace Mantid
{
namespace Kernel
{
//----------------------------------------------------------------------------------------------
// Public static methods
//----------------------------------------------------------------------------------------------
/**
* Check if the given file appears to be an ASCII file. The check searches the
* first nbytes of the file and returns false if a non-ascii character is found.
* If the file is shorter than nbytes then it checks until the end of the stream.
* @param filename A string pointing to an existing file
* @param bytes The number of bytes of the file to check (Default=256)
* @returns True if the file is considered ASCII, false otherwise
* @throws std::invalid_argument if the file cannot be opened
* @throws std::runtime_error if an error is occurred while reading the stream
*/
bool FileDescriptor::isAscii(const std::string & filename, const size_t nbytes)
{
std::ifstream data(filename.c_str(), std::ios::in | std::ios::binary);
if(!data)
{
throw std::invalid_argument("FileDescriptor::isAscii() - Unable to open file '"
+ filename + "'");
}
return FileDescriptor::isAscii(data, nbytes);
}

/**
* Check if the given stream appears to point to an ASCII data. The check searches the
* next nbytes of the stream and returns false if a non-ascii character is found.
* If the stream is shorter than nbytes or a reading error occurs then it simply returns
* the result up to that point
* The stream is reset to the position is was at when entering the function
* @param data An input stream opened in binary mode
* @param bytes The number of bytes of the file to check (Default=256)
* @returns True if the stream is considered ASCII, false otherwise
*/
bool FileDescriptor::isAscii(std::istream & data, const size_t nbytes)
{
const std::streampos startPos = data.tellg();
char byte('\0');
size_t counter(0);
bool result(true);
while(counter < nbytes)
{
data >> byte;
if(!data) // reading error
{
data.clear();
break;
}
unsigned long ch = static_cast<unsigned long>(byte);
if( !(ch <= 0x7F) ) // non-ascii
{
result = false;
break;
}
++counter;
}

data.seekg(startPos);
return result;
}

//----------------------------------------------------------------------------------------------
// Public methods
//----------------------------------------------------------------------------------------------
Expand Down
60 changes: 58 additions & 2 deletions Code/Mantid/Framework/Kernel/test/FileDescriptorTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,51 @@ class FileDescriptorTest : public CxxTest::TestSuite
if(Poco::File(nxsPath).exists()) m_testNexusPath = nxsPath.toString();
Poco::Path nonNxsPath(*it, "CSP79590.raw");
if(Poco::File(nonNxsPath).exists()) m_testNonNexusPath = nonNxsPath.toString();
Poco::Path asciiPath(*it, "AsciiExample.txt");
if(Poco::File(asciiPath).exists()) m_testAsciiPath = asciiPath.toString();

if(!m_testNexusPath.empty() && !m_testNonNexusPath.empty()) break;
if(!m_testNexusPath.empty() && !m_testNonNexusPath.empty() &&
!m_testAsciiPath.empty()) break;
}
if(m_testNexusPath.empty() || m_testNonNexusPath.empty())
if(m_testNexusPath.empty() || m_testNonNexusPath.empty() || m_testAsciiPath.empty())
{
throw std::runtime_error("Unable to find test files for FileDescriptorTest. "
"The AutoTestData directory needs to be in the search path");
}
}

//===================== Success cases ============================================
void test_isAscii_Returns_True_For_Ascii_Filename()
{
TS_ASSERT(FileDescriptor::isAscii(m_testAsciiPath));
}

void test_isAscii_Returns_False_For_Binary_Filename()
{
TS_ASSERT(!FileDescriptor::isAscii(m_testNonNexusPath));
}

void test_isAscii_Returns_True_For_Stream_Pointing_At_Ascii_File_And_Stream_Is_Returned_To_Position_On_Entry()
{
std::ifstream is(m_testAsciiPath, std::ios::in|std::ios::binary);
// move stream along one to check it is returned to here
is.seekg(1);

TS_ASSERT(FileDescriptor::isAscii(is));
TS_ASSERT_EQUALS(1, is.tellg());
}

void test_isAscii_Returns_False_For_Stream_Pointing_At_Ascii_File_And_Stream_Is_Returned_To_Position_On_Entry()
{
std::ifstream is(m_testNonNexusPath, std::ios::in|std::ios::binary);
// move stream along one to check it is returned to here
is.seekg(1);

TS_ASSERT(!FileDescriptor::isAscii(is));
TS_ASSERT_EQUALS(1, is.tellg());
}


void test_Constructor_With_Existing_File_Initializes_Description_Fields()
{
const std::string filename = m_testNexusPath;
Expand Down Expand Up @@ -80,6 +114,27 @@ class FileDescriptorTest : public CxxTest::TestSuite
}

//===================== Failure cases ============================================
void test_IsAscii_Throws_For_Inaccessible_Filename()
{
TS_ASSERT_THROWS(FileDescriptor::isAscii(""), std::invalid_argument);
TS_ASSERT_THROWS(FileDescriptor::isAscii("__not_a_File.txt__"), std::invalid_argument);
}

void test_IsAscii_Returns_True_For_Ascii_Stream_Shorter_Than_NBytes_Requested_And_Clears_Error_Flags()
{
// Fake data
std::istringstream is;
is.str("abcdef"); // 6 bytes

TS_ASSERT(FileDescriptor::isAscii(is, 6)); // Equal to length
TS_ASSERT_EQUALS(0, is.tellg());
TS_ASSERT(is.good());

TS_ASSERT(FileDescriptor::isAscii(is, 10)); // Larger
TS_ASSERT_EQUALS(0, is.tellg());
TS_ASSERT(is.good());
}

void test_Constructor_Throws_With_Empty_filename()
{
TS_ASSERT_THROWS(FileDescriptor(""), std::invalid_argument);
Expand All @@ -93,6 +148,7 @@ class FileDescriptorTest : public CxxTest::TestSuite
private:
std::string m_testNexusPath;
std::string m_testNonNexusPath;
std::string m_testAsciiPath;
};


Expand Down

0 comments on commit bbc2514

Please sign in to comment.