javacommons/fileutils/src/nativefileiohandler.cpp
branchRCL_3
changeset 14 04becd199f91
child 24 6c158198356e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/fileutils/src/nativefileiohandler.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,395 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Handler File IO Operations
+ *
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <unistd.h>
+#include <string>
+
+#include "javacommonutils.h"
+#include "jniarrayutils.h"
+#include "logger.h"
+
+#include "nativefileiohandler.h"
+
+using namespace std;
+using namespace java::util;
+using namespace java::fileutils;
+
+NativeFileIOHandler::NativeFileIOHandler(const std::wstring aName)
+{
+    // Set the current locale to suit unicode for entire process
+    setlocale(LC_ALL, "");
+    mFileName = aName;
+    mFileDescriptor = 0;
+    mClosedTemporarily = false;
+
+    // Setting to -1 implies reading is not being done.
+    // On call to openForReading, set this to 0 and increment on subsequent reads
+    mReadPosition = -1;
+
+    // Setting to -1 implies writing is not being done.
+    // On call to openForWriting, set this to 0 and increment on subsequent writes
+    mWritePosition = -1;
+}
+
+NativeFileIOHandler::~NativeFileIOHandler()
+{
+    // Set the current locale to suit unicode for entire process
+    if (mFileDescriptor)
+    {
+        close(mFileDescriptor);
+    }
+}
+
+long NativeFileIOHandler::skip(const long aOffset)
+{
+    JELOG2(EJavaFile);
+
+    handleReopenCase();
+
+    // lseek can set the offset beyond end of file.
+    // but there will be no scenario where read position goes beyond end of file.
+
+    // First set file offset to read position.
+    int newOffset = lseek(mFileDescriptor, mReadPosition, SEEK_SET);
+
+    if (newOffset < 0)
+    {
+        WLOG1(EJavaFile, "NativeFileIOHandler::skip: Seek failure. %d", errno);
+        return 0;
+    }
+    else
+    {
+        // Now set the file offset in relation to the current read position.
+        newOffset = lseek(mFileDescriptor, aOffset, SEEK_CUR);
+        if (newOffset < 0)
+        {
+            WLOG1(EJavaFile, "NativeFileIOHandler::skip: Seek failure. %d",
+                  errno);
+            return 0;
+        }
+    }
+
+    long retVal = newOffset - mReadPosition;
+    mReadPosition = newOffset;
+    return retVal;
+}
+
+int NativeFileIOHandler::readBytes(char* aBuffer, int aLength)
+{
+    JELOG2(EJavaFile);
+
+    // Throws exception in case of errors.
+    handleReopenCase();
+
+    // lseek can set the offset beyond end of file.
+    // but there will be no scenario where read position goes beyond end of file.
+    int error = lseek(mFileDescriptor, mReadPosition, SEEK_SET);
+
+    if (error < 0)
+    {
+        WLOG2(
+            EJavaFile,
+            "NativeFileIOHandler::readBytes:Seek failure. Read aborted:%d : Seek to: %d",
+            errno, mReadPosition);
+        // Errno cannot be thrown in S60. Causes random crashes.
+        // So copy and throw.
+        int err = errno;
+        throw err;
+    }
+
+    int bytesRead = read(mFileDescriptor, aBuffer, aLength);
+    if (bytesRead < 0)
+    {
+        LOG1(EJavaFile, EInfo,
+             "NativeFileIOHandler::readBytes: Read failure: %d", errno);
+        int err = errno;
+        throw err;
+    }
+
+    // Adding 0 does no harm ;-)
+    mReadPosition += bytesRead;
+    return bytesRead;
+}
+
+int NativeFileIOHandler::writeBytes(char* aBuffer, int aLength)
+{
+    JELOG2(EJavaFile);
+
+    // Throws exception in case of error
+    handleReopenCase();
+
+    // lseek can set the offset beyond end of file.
+    // but there will be no scenario where read position goes beyond end of file.
+    int error = lseek(mFileDescriptor, mWritePosition, SEEK_SET);
+    if (error < 0)
+    {
+        WLOG1(
+            EJavaFile,
+            "NativeFileIOHandler::writeBytes: Seek failure. Write aborted: %d",
+            errno);
+        // Errno cannot be thrown in S60. Causes random crashes.
+        // So copy and throw.
+        int err = errno;
+        throw err;
+    }
+
+    int bytesWritten = write(mFileDescriptor, aBuffer, aLength);
+    if (bytesWritten <= 0)
+    {
+        LOG1(EJavaFile, EInfo,
+             "NativeFileIOHandler::writeBytes: Write failure: %d", errno);
+        int err = errno;
+        throw err;
+    }
+
+    mWritePosition += bytesWritten;
+    return bytesWritten;
+}
+
+void NativeFileIOHandler::stopReading()
+{
+    JELOG2(EJavaFile);
+    mReadPosition = -1;
+    closeStream();
+}
+
+void NativeFileIOHandler::stopWriting()
+{
+    JELOG2(EJavaFile);
+    mWritePosition = -1;
+    closeStream();
+}
+
+void NativeFileIOHandler::closeStream()
+{
+    JELOG2(EJavaFile);
+    if ((-1 == mReadPosition) && (-1 == mWritePosition))
+    {
+        close(mFileDescriptor);
+        mFileDescriptor = 0;
+    }
+}
+
+void NativeFileIOHandler::openForReading()
+{
+    JELOG2(EJavaFile);
+
+    if (!mFileDescriptor)
+    {
+        // it will never come here if it is not a file.
+        // so, if there is a trailing slash, remove it.
+        char ch = mFileName.at(mFileName.length() - 1);
+        if (ch == '\\' || ch == '/')
+        {
+            mFileName = mFileName.substr(0, mFileName.length() - 1);
+        }
+
+        char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName);
+        if (access(utf8Name, R_OK) < 0)
+        {
+            // We do not have write access
+            delete[] utf8Name;
+            ELOG(EJavaFile,
+                 "NativeFileUtils::OpenForReading: Exiting in between. no read permission");
+            int error = errno;
+            throw error;
+        }
+        mFileDescriptor = open(utf8Name, O_RDWR);
+
+        // If open fails with Read Write mode, try read mode atleast.
+        if (mFileDescriptor < 0)
+        {
+            mFileDescriptor = open(utf8Name, O_RDONLY);
+        }
+
+        delete[] utf8Name;
+        if (mFileDescriptor < 0)
+        {
+            // There is some problem opening the file. Throw the cause for error.
+            mFileDescriptor = 0;
+            ELOG(
+                EJavaFile,
+                "NativeFileUtils::OpenForReading: Exiting in between unable to open in read only");
+            int error = errno;
+            throw error;
+        }
+    }
+
+    mReadPosition = 0;
+}
+
+void NativeFileIOHandler::openForWriting(const long aOffset)
+{
+    JELOG2(EJavaFile);
+    char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName);
+
+    if (access(utf8Name, W_OK) < 0)
+    {
+        WLOG(EJavaFile,
+             "NativeFileIOHandler::openForWriting: Access not allowed");
+        // We do not have write access
+        delete[] utf8Name;
+        int error = errno;
+        throw error;
+    }
+
+    if (!mFileDescriptor)
+    {
+        // it will never come here if it is not a file.
+        // so, if there is a trailing slash, remove it.
+        char ch = mFileName.at(mFileName.length() - 1);
+        if (ch == '\\' || ch == '/')
+        {
+            mFileName = mFileName.substr(0, mFileName.length() - 1);
+        }
+
+        mFileDescriptor = open(utf8Name, O_RDWR);
+
+        if (mFileDescriptor < 0)
+        {
+            delete[] utf8Name;
+            mFileDescriptor = 0;
+            int error = errno;
+            throw error;
+        }
+    }
+
+    mWritePosition = 0;
+    if (aOffset > 0)
+    {
+        // We will need to stat the file and find out its size just to make sure
+        // lseek does not set the offset to beyond end of file.
+        struct stat fileStat;
+        int error = lstat(utf8Name, &fileStat);
+
+        if (error < 0)
+        {
+            int error = errno;
+            throw error;
+        }
+        long fileSize = fileStat.st_size;
+
+        if (aOffset >= fileSize)
+        {
+            // Move to end of file
+            if (lseek(mFileDescriptor, 0, SEEK_END) < 0)
+            {
+                delete[] utf8Name;
+                int error = errno;
+                throw error;
+            }
+            mWritePosition = fileSize;
+        }
+        else
+        {
+            // Move to given offset
+            if (lseek(mFileDescriptor, aOffset, SEEK_SET) < 0)
+            {
+                delete[] utf8Name;
+                int error = errno;
+                throw error;
+            }
+            mWritePosition = aOffset;
+        }
+    }
+    delete[] utf8Name;
+}
+
+void NativeFileIOHandler::closeFileToReopen()
+{
+    JELOG2(EJavaFile);
+
+    // We dont try to synchronize here. It must be done from java.
+    // In case of multithreaded apps, set hidden should not be done while read
+    // is in progress.
+    if (mFileDescriptor)
+    {
+        LOG(EJavaFile, EInfo,
+            "NativeFileUtils::closeFileToReopen: Closing already open Files");
+        LOG1(EJavaFile, EInfo, "        Current Read Offset: %ld",
+             mReadPosition);
+        LOG1(EJavaFile, EInfo, "        Current Write Offset: %ld",
+             mWritePosition);
+        mClosedTemporarily = true;
+        close(mFileDescriptor);
+        mFileDescriptor = 0;
+    }
+}
+
+void NativeFileIOHandler::handleReopenCase()
+{
+    JELOG2(EJavaFile);
+    if (!mClosedTemporarily)
+    {
+        return;
+    }
+
+    if ((-1 == mWritePosition) && (-1 == mReadPosition))
+    {
+        return;
+    }
+
+    if (mWritePosition > -1)
+    {
+        LOG(EJavaFile, EInfo,
+            "NativeFileUtils::handleReopenCase: Reopening for write");
+        long curWritePos = mWritePosition;
+        openForWriting(curWritePos);
+    }
+    else if (mReadPosition > -1)
+    {
+        LOG(EJavaFile, EInfo,
+            "NativeFileUtils::handleReopenCase: Reopening for read");
+        long curReadPos = mReadPosition;
+        openForReading();
+        mReadPosition = curReadPos;
+    }
+
+    LOG(EJavaFile, EInfo, "NativeFileUtils::handleReopenCase: File Open");
+    LOG1(EJavaFile, EInfo, "        Setting Read Offset: %ld", mReadPosition);
+    LOG1(EJavaFile, EInfo, "        Setting Write Offset: %ld", mWritePosition);
+
+    mClosedTemporarily = false;
+}
+
+long NativeFileIOHandler::available()
+{
+    JELOG2(EJavaFile);
+    char* utf8Name = JavaCommonUtils::wstringToUtf8(mFileName);
+
+    struct stat fileStat;
+    int error = lstat(utf8Name, &fileStat);
+
+    if (error < 0)
+    {
+        int error = errno;
+        throw error;
+    }
+    long fileSize = fileStat.st_size;
+
+    if (mReadPosition > 0)
+    {
+        return (fileSize - mReadPosition);
+    }
+    else
+    {
+        return fileSize;
+    }
+}