diff -r 61bc0f252b2b -r bac7acad7cb3 camerauis/cameraxui/cxengine/src/cxefilenamegeneratorsymbian.cpp --- a/camerauis/cameraxui/cxengine/src/cxefilenamegeneratorsymbian.cpp Tue Aug 31 15:03:46 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,708 +0,0 @@ -/* -* Copyright (c) 2009-2010 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: -* -*/ -#include -#include -#include // For CCoeEnv -#include - -#include "cxefilenamegeneratorsymbian.h" -#include "cxeengine.h" -#include "cxenamespace.h" -#include "cxutils.h" -#include "cxesysutil.h" -#include "cxesettings.h" -#include "cxeerror.h" -#include "cxeerrormappingsymbian.h" - -#include "OstTraceDefinitions.h" -#ifdef OST_TRACE_COMPILER_IN_USE -#include "cxefilenamegeneratorsymbianTraces.h" -#endif - - -using namespace Cxe; - -// =========================================================================== -// Local constants - -static const int KMultipleFolderNumberChars = 2; -static const int KMaxMonthFolders = 260; -static const int KBase10 = 10; -static const int KMaxFilesPerFolder = 100; - -const char* CAMERA_FOLDER = "Camera"; -const char* FOLDER_SEPARATOR = "\\"; -const char* WILDCARD_CHARACTER = "?"; - -const char CHAR_OFFSET = 'A'; -const char DIGIT_OFFSET = '0'; -const char MAX_CHAR = 'Z'; - -const TInt64 KMinRequiredSpaceImage = 2000000; - -// Whether there's enough space for video or not is handled lower in the SW stack -// so this is set to 0 to fix an error -const TInt64 KMinRequiredSpaceVideo = 0; - - - -// =========================================================================== -// Local functions - -/** -* Convert QString to TPtrC16. -*/ -inline TPtrC16 convertToTPtrC16(const QString& string) -{ - return TPtrC16(reinterpret_cast(string.utf16())); -} - - -// =========================================================================== -// Class functions - -/** - * Constructor - */ -CxeFilenameGeneratorSymbian::CxeFilenameGeneratorSymbian(CxeSettings &settings, CameraMode mode) - : mFs(CCoeEnv::Static()->FsSession()), - mSettings(settings), - mCurrentMode(mode) -{ - CX_DEBUG_ENTER_FUNCTION(); - OstTrace0(camerax_performance, CXEFILENAMEGENERATOR_1, "msg: e_CX_FILENAMEGENERATOR_NEW 1"); - - // Set default values (used in case of error retrieving values) - mCurrentMonth = ""; - mMonthCounterImage = -1; - mMonthCounterVideo = -1; - mImageCounter = 0; - mVideoCounter = 0; - - // Retrieve last used counter values from settings - mCurrentMonth = mSettings.get(CxeSettingIds::FNAME_MONTH_FOLDER, ""); - mImageCounter = mSettings.get(CxeSettingIds::FNAME_IMAGE_COUNTER, 0); - mVideoCounter = mSettings.get(CxeSettingIds::FNAME_VIDEO_COUNTER, 0); - - OstTrace0(camerax_performance, CXEFILENAMEGENERATOR_2, "msg: e_CX_FILENAMEGENERATOR_NEW 0"); - CX_DEBUG_EXIT_FUNCTION(); -} - -/** - * Destructor - */ -CxeFilenameGeneratorSymbian::~CxeFilenameGeneratorSymbian() -{ - CX_DEBUG_ENTER_FUNCTION(); - - CX_DEBUG_EXIT_FUNCTION(); -} - -/** - * This must be called for every burst capture. - */ -void CxeFilenameGeneratorSymbian::startNewImageFilenameSequence() -{ - CX_DEBUG_ENTER_FUNCTION(); - - /* NOTES - When the client calls this function, we should start a new "sequence" of filenames... - What I mean here is that for burst capture, we have filename sequences like... - Filename1 - Filename1(002) - Filename1(003) - and so on... - - So this function says "Ok, I'm starting a new capture sequence here... so reset your variables" - This should be done below... - Development efforts need to be aware of Edrive vs. Cdrive, and also multiple drive support. - */ - - CX_DEBUG_EXIT_FUNCTION(); -} - -/** - * Generates the next file name in the sequence. - * @param filename: A QString reference to hold the filename - * @return error id, Id::None if no error - */ -CxeError::Id CxeFilenameGeneratorSymbian::nextImageFilenameInSequence(QString &qfName, const QString &fileExt) -{ - CX_DEBUG_IN_FUNCTION(); - - /** @todo: When the client calls this function, the next filename in the - * sequence is retrieved. The entire path should be included... e.g - * C//PHOTOS//SOMETHING//HELLO//Filename001.jpg - */ - return generateFilename(qfName, fileExt); -} - -/** - * Generates image/video file name depending on the current active mode. - * @param filename: A QString reference to hold the filename - * @return error id, CxeError::None if no error. - */ -CxeError::Id CxeFilenameGeneratorSymbian::generateFilename(QString &qfName, const QString &fileExt) -{ - CX_DEBUG_ENTER_FUNCTION(); - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_GENERATENAME_1, "msg: e_CX_GENERATE_FILENAME 1"); - - // Make sure that the path for images/videos exists - QString path; - int err = selectFolder(path); - - // Continue generating filename, if no errors encountered yet - if (!err) { - // Generate and append the file name to construct the full path - QString fileName; - err = generateUniqueFileName(path, fileName, fileExt); - if (!err) { - qfName = path + fileName; - } - } - - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_GENERATENAME_2, "msg: e_CX_GENERATE_FILENAME 0"); - CX_DEBUG_EXIT_FUNCTION(); - return CxeErrorHandlingSymbian::map(err); -} - -/** - * Generates a unique file name in the given path. - * @param filePath Path for the file (reference) - * @param fileName Name of the file (reference) - * @return Symbian error code (used internally) - */ -int CxeFilenameGeneratorSymbian::generateUniqueFileName(QString &filePath, QString &fileName, const QString &ext) -{ - CX_DEBUG_ENTER_FUNCTION(); - - // At this point the path must exist. - // Remote possibility / security threat that it doesn't exist or is not a folder. - TEntry entry; - int ferr = mFs.Entry(convertToTPtrC16(filePath), entry); - if (ferr != KErrNone || !entry.IsDir()) { - return ferr; - } - - // Initialize counters and file extension - int *fileCounter = &mImageCounter; - - if (mCurrentMode==VideoMode) { - fileCounter = &mVideoCounter; - } - - QString fnFormat("%1%2%3"); - QString number; - - // get the file name suffix - QString baseFileName; - mSettings.get(CxeSettingIds::FNAME_FOLDER_SUFFIX, baseFileName); - - while (true) { - // Generate new name - number = number.sprintf("%04d", *fileCounter); - fileName = fnFormat.arg(number, baseFileName, ext); - - CX_DEBUG(("Checking filename [%s]", fileName.toAscii().constData())); - - // Check if it exists - ferr = checkExistence(filePath + fileName); - if (ferr == KErrNone) { - // Filename has already been used in this location, try the next number - CX_DEBUG(("File exists already")); - (*fileCounter)++; - } else if (ferr == KErrNotFound) { - // No file with this name, use it. - CX_DEBUG(("Filename free, using it")); - ferr = KErrNone; - break; - } else { - // Filename could not be reserved. Log actual error and report as general error. - CX_DEBUG(("[WARNING] Error %d generating filename!", ferr)); - ferr = KErrGeneral; - break; - } - } - - // Increment counter if image mode. Video counter is incremented when - // video has been actually recorded - if (mCurrentMode == ImageMode) { - raiseCounterValue(); - } - - CX_DEBUG_EXIT_FUNCTION(); - return ferr; -} - -/** - * Computes the suffix to be used in destination folder name. - */ -void CxeFilenameGeneratorSymbian::computeFolderSuffix(int folderNumber, QString &suffix) -{ - CX_DEBUG_ENTER_FUNCTION(); - - // Clear any old content. - suffix = ""; - - // Example: - // if folderNumber is 15 - // 15/10 = 1 (int) - // A + 1 = B - suffix += (CHAR_OFFSET + folderNumber/KBase10); - // 15%10 = 5 - // 0 + 5 = 5 - // => suffix = B5 - suffix += (DIGIT_OFFSET + folderNumber%KBase10); - CX_DEBUG_EXIT_FUNCTION(); -} - -/** - * Compute the month counter value (0 to 259 => A0 to Z9). - * @param - * @return Symbian error code (internal to class) - */ -int CxeFilenameGeneratorSymbian::computeMonthCounter(QString &path, QString& monthFolder, int &monthCounter) -{ - CX_DEBUG_ENTER_FUNCTION(); - bool done = false; - - // Query the month folder: path\YYYYMM?? - QString queryPath = path + monthFolder; - for (int charCount = 0; charCount < KMultipleFolderNumberChars; charCount++) { - queryPath += WILDCARD_CHARACTER; - } - CX_DEBUG(("Listing folders with wildcards: [%s]", queryPath.toAscii().constData())); - - // Get a list of folders for this month, sorted in descending alphabetical order. - // The first entry should be the latest used folder. - CDir* dirList; - int err = mFs.GetDir(convertToTPtrC16(queryPath), - KEntryAttMatchExclusive|KEntryAttDir, - ESortByName|EDescending, - dirList); - - // On errors (or empty list of folders), let's default to zero. - // Errors here should be recoverable when we start to - // count files within current directory. - monthCounter = 0; - - // If directory listing worked fine, then figure out the last month folder number - if (err == KErrNone) { - int monthFolderCount = dirList->Count(); - CX_DEBUG(("Matching folder count: %d", monthFolderCount)); - int index = 0; - // Look through the list of folders in the month for the highest numbered folder - // with the format YYYYMMAX Where YYYY is the year MM is the month A is an alphabetical - // character in the range a-z or A-Z and X is a digit 0-9 - while ( index < monthFolderCount && !done ) { - // The list is sorted in descending order. Get the last 2 characters from - // the first directory in the list these indicate the highest folder number - TPtrC name = ( *dirList )[index].iName; - int nameLength = name.Length(); - - // Check the first character is in the range a-z or A-Z - // and the second character is in the range 0-9 - TChar firstChar = name[nameLength - KMultipleFolderNumberChars]; - firstChar.UpperCase(); - TChar secondChar = name[nameLength - 1]; - int secondCharVal = secondChar.GetNumericValue(); - - // If 1st character is NOT in the range(A-Z) then disregard this folder - if (firstChar < CHAR_OFFSET || firstChar > MAX_CHAR) { - done = false; - } - // If 2nd character is NOT in the range(0-9) then disregard this folder - else if (secondCharVal < 0 || secondCharVal > KBase10-1) { - done = false; - } - else { - done = true; - } - - // If no problems were encountered, then calculate the folder number - if (done) { - // 10's part of folder number is represented by characters A-Z - // convert the character into a decimal value (*10) and add on the units. - monthCounter = ((int)firstChar-(int)CHAR_OFFSET)*KBase10 + secondCharVal; - CX_DEBUG(("Calculated month counter value: %d", monthCounter)); - // Make sure that month counter doesn't exceed Z9 - if (monthCounter >= KMaxMonthFolders) { - monthCounter = KMaxMonthFolders - 1; - } - } - index++; - } - } else { - CX_DEBUG(("[WARNING] Error %d listing month folders!", err)); - } - - delete dirList; - CX_DEBUG_EXIT_FUNCTION(); - return err; -} - -/** - * Checks that the month folder exists: creates the folder if required. - * Returns error code if the folder can't be created. - */ -int CxeFilenameGeneratorSymbian::selectFolder(QString &suggestedPath) -{ - CX_DEBUG_ENTER_FUNCTION(); - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_SELECTFOLDER_1, "msg: e_CX_SELECT_FOLDER 1"); - - // Compose the path string and select counter based on mode. - QString basePath = "%1%2\\"; - int *monthCounter = &mMonthCounterImage; - - if (ImageMode == mCurrentMode) { - basePath = basePath.arg(mImagesPath, mCurrentMonth); - } - else { // VideoMode - basePath = basePath.arg(mVideosPath, mCurrentMonth); - monthCounter = &mMonthCounterVideo; - } - CX_DEBUG(("Base path [%s]", basePath.toAscii().constData())); - - QString suffix; - QString newPath; - int status(KErrNone); - bool created(false); - - while (true) { - // Construct the complete path - computeFolderSuffix(*monthCounter, suffix); - newPath = basePath + mCurrentMonth + suffix + FOLDER_SEPARATOR; - - // Check if the folder exists, and create if not. - CX_DEBUG(("Checking new path [%s] ..", newPath.toAscii().constData())); - status = ensureExists(newPath, created); - - // Check if the folder can be used. - if (status == KErrNone) { - // If the folder was newly created, it's empty and can be used. - // If the folder is last available month folder, - // we need to use it even if it has "too many" files. - if (created || *monthCounter >= (KMaxMonthFolders-1)) { - CX_DEBUG(("Newly created folder, or the last month folder available, using it")); - suggestedPath = newPath; - break; - } else { - // For other folders, if the folder already exists then make sure - // that it doesn't contain maximum number of files already. - CX_DEBUG(("Folder already existed, check the amount of files..")); - CDir* fileList; - status = mFs.GetDir(convertToTPtrC16(newPath), - KEntryAttMaskSupported, - ESortNone, - fileList); - CX_DEBUG(("Folder contains %d files", fileList->Count())); - - bool spaceRemaining(fileList->Count() < KMaxFilesPerFolder); - - delete fileList; - fileList = NULL; - - if (status == KErrNone && spaceRemaining) { - // Not too many files on the folder, use it. - CX_DEBUG(("File count acceptable, using this folder")); - suggestedPath = newPath; - break; - } else { - // Need to check the next folder, this one is full, - // or we had error listing it's contents. - CX_DEBUG(("Folder full, continue search")); - (*monthCounter)++; - } - } - } else { - // Unknown error encountered. - // LOG the error and use the basePath! - // Base path's existence has been checked when init was called. - CX_DEBUG(("[WARNING] - error %d encountered. Using base path as fallback.", status)); - suggestedPath = basePath; - break; - } - } - - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_SELECTFOLDER_2, "msg: e_CX_SELECT_FOLDER 0"); - CX_DEBUG_EXIT_FUNCTION(); - - // We fallback to basePath in case of unknown errors, - // so no error will be reported here. - return KErrNone; -} - - - -/** - * Initializes the month folders. - * @return Symbian error code (internal to class) - */ -int CxeFilenameGeneratorSymbian::initMonthFolders() -{ - CX_DEBUG_ENTER_FUNCTION(); - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_INITFOLDERS_1, "msg: e_CX_INIT_MONTH_FOLDER 1"); - - // Month folder: YYYYMM, with suffix: YYYYMMXX - QString monthFolder = QDate::currentDate().toString("yyyyMM"); - - // If the month folder name is different from the last used month folder name - // this indicates that a new month has been started. - if ( monthFolder.compare(mCurrentMonth) != 0 ) { - resetCounters(monthFolder); - } - - // Check/create that the month folder exists - int *monthCounter = &mMonthCounterImage; - QString path = "%1%2\\"; - if (ImageMode==mCurrentMode) { - path = path.arg(mImagesPath, monthFolder); - } - else { - path = path.arg(mVideosPath, monthFolder); - monthCounter = &mMonthCounterVideo; - } - - CX_DEBUG(("Check if exists, create if not [%s]", path.toAscii().constData())); - bool created(false); - int status(ensureExists(path, created)); - - if (status == KErrNone) { - if (created) { - // New folder, new month -> counter starts from zero. - *monthCounter = 0; - } else { - // If the month counter is un-initialised it needs to be set up. - if (*monthCounter < 0) { - status = computeMonthCounter(path, monthFolder, *monthCounter); - if (status != KErrNone) { - CX_DEBUG(("[WARNING] - Error setting month counter: %d", status)); - *monthCounter = 0; - } - } - } - } else { - //! @todo: Review error handling - // Report error - can't continue without 'camera' and camera\YYYYMM folders - CX_DEBUG(("[FATAL] - Could not create month folder, error %d", status)); - } - - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_INITFOLDERS_2, "msg: e_CX_INIT_MONTH_FOLDER 0"); - CX_DEBUG_EXIT_FUNCTION(); - return status; -} - -/** - * Checks if the passed amount of disk space is available on the passed drive. - * @return true if space available, false otherwise - */ -bool CxeFilenameGeneratorSymbian::spaceAvailable(int &driveIndex, TInt64 minSpaceInBytes) -{ - CX_DEBUG_ENTER_FUNCTION(); - - TVolumeInfo vInfo; - - // Get the drive/volume details - int status(KErrNone); - driveIndex = CxeSysUtil::getCameraDrive(mFs); - if (driveIndex >= 0) { - status = mFs.Volume(vInfo, driveIndex); - } - - CX_DEBUG_EXIT_FUNCTION(); - return (status == KErrNone) ? vInfo.iFree >= minSpaceInBytes : false; - -} - -/** - * Selects the drive to use based on preference and availability. - * @param index of the drive to be used (reference) - * @return Symbian error code (internal to class) - */ -int CxeFilenameGeneratorSymbian::selectDrive(int &drive) -{ - CX_DEBUG_ENTER_FUNCTION(); - int err = KErrNone; - TInt64 minDiskSpace = KMinRequiredSpaceImage; - - if (Cxe::VideoMode == mCurrentMode) { - minDiskSpace = KMinRequiredSpaceVideo; - } - - // Check the available space. - // Drive index is set here also. - if ( !spaceAvailable(drive, minDiskSpace)) { - // All drives are full or inaccessible - err = KErrDiskFull; - } - - CX_DEBUG_EXIT_FUNCTION(); - return err; -} - -/** - * Initializes the value of base path for the given mode and drive. - */ -void CxeFilenameGeneratorSymbian::initBasePath(QString &path, int drive) -{ - CX_DEBUG_ENTER_FUNCTION(); - - // Get the root path for the given drive. - TFileName tPath; - PathInfo::GetRootPath(tPath, drive); - - if (VideoMode == mCurrentMode) { - tPath.Append( PathInfo::VideosPath() ); - } - else { - tPath.Append( PathInfo::ImagesPath() ); - } - - //! @todo: Fetch localized Camera folder name, if/when applicable. - path = QString::fromUtf16(tPath.Ptr(), tPath.Length()); - path = path + CAMERA_FOLDER + FOLDER_SEPARATOR; - - CX_DEBUG(("Path: %s", path.toAscii().constData())); - CX_DEBUG_EXIT_FUNCTION(); -} - -/** - * Resets the image and video counters used for file name generation. - */ -void CxeFilenameGeneratorSymbian::resetCounters(QString &monthFolder) -{ - CX_DEBUG_ENTER_FUNCTION(); - - mCurrentMonth = monthFolder; - mMonthCounterImage = 0; - mMonthCounterVideo = 0; - - // Save the setting values - // Errors (if any) encountered here are not handled, since these indicate - // that settings are'nt saved. If settings are not fetched next time, - // then default settings are used. - mSettings.set(CxeSettingIds::FNAME_MONTH_FOLDER, mCurrentMonth); - - CX_DEBUG_EXIT_FUNCTION(); -} - -/** - * Initializes the base folder names and counters - * NB: Video mode init requires file name. So this should be called - * before init is called for image/video capture controls. - * Initializes only for appropriate mode (image/video). - */ -CxeError::Id CxeFilenameGeneratorSymbian::init(Cxe::CameraMode mode) -{ - CX_DEBUG_ENTER_FUNCTION(); - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_INIT_1, "msg: e_CX_FILENAMEGENERATOR_INIT 1"); - - mCurrentMode = mode; - int err = KErrNone; - bool initialized = (mode==ImageMode && !mImagesPath.isEmpty()) || - (mode==VideoMode && !mVideosPath.isEmpty()); - - if (!initialized) { - // Select a drive based on available disk space - int drive; - err = selectDrive(drive); - if (!err) { - if (mode == ImageMode) { - initBasePath(mImagesPath, drive); - } - else { - initBasePath(mVideosPath, drive); - } - - // Initialize the month folders and counters so that - // file names can be generated quickly when requested. - err = initMonthFolders(); - } - } - - OstTrace0(camerax_performance, CXEFILENAMEGENERATORSYMBIAN_INIT_2, "msg: e_CX_FILENAMEGENERATOR_INIT 0"); - CX_DEBUG_EXIT_FUNCTION(); - return CxeErrorHandlingSymbian::map(err); -} - -/** - * Raises file name counter value by one - */ -void CxeFilenameGeneratorSymbian::raiseCounterValue() -{ - if (VideoMode==mCurrentMode) { - mSettings.set(CxeSettingIds::FNAME_VIDEO_COUNTER, ++mVideoCounter); - } - else { - mSettings.set(CxeSettingIds::FNAME_IMAGE_COUNTER, ++mImageCounter); - } -} - -/** - * Check if the given file or directory exists. - * @return KErrNone, if given file/directory exists, KErrNotFound if not. - * Other Symbian error code on "real" errors. - */ -int CxeFilenameGeneratorSymbian::checkExistence(const QString& path) -{ - CX_DEBUG_ENTER_FUNCTION(); - - unsigned int placeHolder(0); - int status(mFs.Att(convertToTPtrC16(path), placeHolder)); - - CX_DEBUG_EXIT_FUNCTION(); - return status; -} - - -/** - * Check if directory exists and create if not. - * @param created When returned, holds if the folder needed to be created or not. - * @return KErrNone, if folder existed or was created successfully. - * Other Symbian error code if there were errors. - */ -int CxeFilenameGeneratorSymbian::ensureExists(const QString& path, bool& created) -{ - CX_DEBUG_ENTER_FUNCTION(); - - // Default to "not created" if errors are encountered. - created = false; - - unsigned int placeHolder(0); - TPtrC16 pathDesc(convertToTPtrC16(path)); - CX_DEBUG_SYMBIAN((_L("Checking [%S]"), &pathDesc)); - - // Check if it already exists - CX_DEBUG(("CxeFilenameGeneratorSymbian::ensureExists - check existence..")); - int status = mFs.Att(pathDesc, placeHolder); - CX_DEBUG(("CxeFilenameGeneratorSymbian::ensureExists - ..check existence")); - - if( status == KErrPathNotFound || status == KErrNotFound ) { - // Create path if doesn't exist yet. - CX_DEBUG(("CxeFilenameGeneratorSymbian::ensureExists - create path..")); - status = mFs.MkDirAll(pathDesc); - CX_DEBUG(("CxeFilenameGeneratorSymbian::ensureExists - ..create path")); - // Set "created" flag only if successfull - created = (status == KErrNone); - } - - CX_DEBUG_EXIT_FUNCTION(); - return status; -} - - -// end of file