blob: d15bd73182b97e21712d8f13c9e45519dd4e9732 [file] [log] [blame]
/*
* Project: VizKit
* Version: 2.3
* Date: 20090823
* File: VisualFile.cpp
*
*/
/***************************************************************************
Copyright (c) 2004-2009 Heiko Wichmann (http://www.imagomat.de/vizkit)
This software is provided 'as-is', without any expressed or implied warranty.
In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated
but is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
***************************************************************************/
#include "VisualFile.h"
#include "VisualString.h"
#include "VisualErrorHandling.h"
#include "VisualConfiguration.h"
#if TARGET_OS_MAC
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/Folders.h> // FSFindFolder
#endif
#if TARGET_OS_WIN
#include <shlobj.h> // SHGetSpecialFolderPathW
//#include <io.h> // _access
#endif
using namespace VizKit;
VisualFile::VisualFile() {
knownWhetherFileOrDirectoryExists = true;
doesExistBool = false;
isDirectory = false;
#if TARGET_OS_MAC
currForkRefNum = 0;
#endif
#if TARGET_OS_WIN
filePathWin[0] = L'\0';
currHandle = NULL;
#endif
}
VisualFile::~VisualFile() {
this->clear();
}
VisualFile::VisualFile(const VisualFile& other) : VisualObject(other) {
copy(other);
}
VisualFile& VisualFile::operator=(const VisualFile& other) {
if (this == &other) return *this;
VisualObject::operator=(other);
this->clear();
this->copy(other);
return *this;
}
bool VisualFile::initWithDirectoryOfTemporaryItems() {
bool success = true;
this->clear();
#if TARGET_OS_MAC
OSErr osErr = FSFindFolder(kUserDomain, kTemporaryFolderType, kCreateFolder, &(this->fsRef)); // ~/Library/Caches/TemporaryItems/
if (osErr != noErr) {
success = false;
}
#endif
#if TARGET_OS_WIN
BOOL createFolderIfNotAlreadyThere = true;
HRESULT hr = SHGetSpecialFolderPathW(NULL, (LPWSTR)filePathWin, CSIDL_INTERNET_CACHE, createFolderIfNotAlreadyThere);
if (!hr) {
success = false;
}
#endif
isDirectory = true;
knownWhetherFileOrDirectoryExists = true;
doesExistBool = true;
return success;
}
bool VisualFile::initWithUserDesktopDirectory() {
bool success = true;
this->clear();
#if TARGET_OS_MAC
OSErr osErr = FSFindFolder(kUserDomain, kDesktopFolderType, kCreateFolder, &(this->fsRef));
if (osErr != noErr) {
success = false;
}
#endif
#if TARGET_OS_WIN
BOOL createFolderIfNotAlreadyThere = true;
HRESULT hr = SHGetSpecialFolderPathW(NULL, (LPWSTR)this->filePathWin, CSIDL_DESKTOPDIRECTORY, createFolderIfNotAlreadyThere);
if (!hr) {
success = false;
}
#endif
isDirectory = true;
knownWhetherFileOrDirectoryExists = true;
doesExistBool = true;
return success;
}
bool VisualFile::initWithPreferenceStoreDirectory() {
bool success = true;
this->clear();
#if TARGET_OS_MAC
OSErr osErr = FSFindFolder(kUserDomain, kPreferencesFolderType, kCreateFolder, &(this->fsRef));
if (osErr != noErr) {
return false;
}
#endif
#if TARGET_OS_WIN
BOOL createFolderIfNotAlreadyThere = true;
HRESULT hr = SHGetSpecialFolderPathW(NULL, (LPWSTR)this->filePathWin, CSIDL_APPDATA, createFolderIfNotAlreadyThere);
if (!hr) {
return false;
}
#endif
isDirectory = true;
knownWhetherFileOrDirectoryExists = true;
doesExistBool = true;
return success;
}
#if TARGET_OS_MAC
bool VisualFile::initWithResourcesDirectory() {
bool success = true;
this->clear();
CFStringRef pluginName = CFStringCreateWithCString(kCFAllocatorDefault, VisualConfiguration::kVisualPluginDomainIdentifier, kCFStringEncodingASCII);
CFBundleRef bundleRef = CFBundleGetBundleWithIdentifier(pluginName);
if (!bundleRef) {
return false;
}
CFURLRef resourcesDirectoryUrlRef = CFBundleCopyResourcesDirectoryURL(bundleRef);
if (!resourcesDirectoryUrlRef) {
return false;
}
FSRef newFsRef;
Boolean CFURLGetFSRefSuccess = CFURLGetFSRef(resourcesDirectoryUrlRef, &newFsRef);
if (!CFURLGetFSRefSuccess) {
CFRelease(resourcesDirectoryUrlRef);
return false;
} else {
this->fsRef = newFsRef;
}
CFRelease(resourcesDirectoryUrlRef);
isDirectory = true;
knownWhetherFileOrDirectoryExists = true;
doesExistBool = true;
return success;
}
#endif
VisualFile* VisualFile::clone(void) const {
return new VisualFile(*this);
}
bool VisualFile::appendFileName(VisualString& aFileName) {
bool success = false;
#if TARGET_OS_MAC
OSStatus osStatus = noErr;
Boolean isDir = false;
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &(this->fsRef));
CFURLRef urlWithFileName = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, url, aFileName.getCharactersPointer(), isDir);
CFRelease(url);
FSRef newFsRef;
Boolean CFURLGetFSRefSuccess = CFURLGetFSRef(urlWithFileName, &newFsRef);
if (!CFURLGetFSRefSuccess) {
// FSRef can only be set for existing files or directories
CFIndex fileNameLength = CFStringGetLength(aFileName.getCharactersPointer());
const uint16* fileNameConstChars = CFStringGetCharactersPtr(aFileName.getCharactersPointer());
uint16* fileNameChars = NULL;
if (fileNameConstChars == NULL) {
fileNameChars = (uint16*)malloc(fileNameLength * sizeof(uint16));
CFStringGetCharacters(aFileName.getCharactersPointer(), CFRangeMake(0, fileNameLength), fileNameChars);
}
FSCatalogInfoBitmap whichInfo = (FSCatalogInfoBitmap)NULL;
const FSCatalogInfo* catalogInfo = NULL;
FSSpec newSpec;
OSErr osErr = noErr;
FSRef prevFsRef = this->fsRef;
if (fileNameConstChars == NULL) {
osErr = FSCreateFileUnicode(&prevFsRef, fileNameLength, fileNameChars, whichInfo, catalogInfo, &(this->fsRef), &newSpec);
} else {
osErr = FSCreateFileUnicode(&prevFsRef, fileNameLength, fileNameConstChars, whichInfo, catalogInfo, &(this->fsRef), &newSpec);
}
if (osErr != noErr) {
osStatus = 1000;
}
if (fileNameChars != NULL) {
free(fileNameChars);
fileNameChars = NULL;
}
} else {
this->fsRef = newFsRef;
}
CFRelease(urlWithFileName);
knownWhetherFileOrDirectoryExists = true;
doesExistBool = true;
if (osStatus == noErr)
{
success = true;
}
#endif
#if TARGET_OS_WIN
wchar_t backslash[2];
backslash[0] = 0x5c;
backslash[1] = L'\0';
wcscat(this->filePathWin, backslash);
wcscat(this->filePathWin, aFileName.getCharactersPointer());
knownWhetherFileOrDirectoryExists = false;
doesExistBool = false;
success = true;
#endif
this->isDirectory = false;
return success;
}
bool VisualFile::open() {
bool success = false;
#if TARGET_OS_MAC
OSErr osErr = FSOpenFork(&(this->fsRef), 0, NULL, fsWrDenyPerm, &(this->currForkRefNum));
if (osErr == noErr) {
success = true;
}
#endif
#if TARGET_OS_WIN
DWORD dwDesiredAccess = GENERIC_READ;
DWORD dwShareMode = FILE_SHARE_READ;
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
DWORD dwCreationDisposition = OPEN_ALWAYS; // open the file if it exists, else create new one
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
HANDLE hTemplateFile = NULL;
this->currHandle = CreateFileW((LPCWSTR)this->filePathWin,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
if (this->currHandle != INVALID_HANDLE_VALUE) {
knownWhetherFileOrDirectoryExists = true;
doesExistBool = true;
success = true;
}
#endif
return success;
}
bool VisualFile::close() {
bool success = false;
#if TARGET_OS_MAC
OSErr osErr = FSCloseFork(this->currForkRefNum);
this->currForkRefNum = 0;
if (osErr == noErr) {
success = true;
}
#endif
#if TARGET_OS_WIN
BOOL closeHandleSuccess = CloseHandle(this->currHandle);
if (closeHandleSuccess) {
success = true;
}
#endif
return success;
}
bool VisualFile::getData(void** dataOut, size_t& size) {
bool success = true;
bool debug = false;
char logStr[2048];
if (debug == true) {
writeLog("getData() start");
}
success = this->open();
if (!success) {
return success;
}
if (debug == true) {
writeLog("aFile.open()");
}
uint32 numberOfBytesToReadPerFill = 0;
// some small optimization
size = 0;
success = this->getSize(size);
if (!success) {
success = false;
} else {
if (size > 4096) {
numberOfBytesToReadPerFill = 4096;
} else {
numberOfBytesToReadPerFill = 512;
}
}
if (!success) {
size = 0;
return success;
}
bool readOn = true;
uint32 actualCount = 0;
uint32 offset = 0;
uint32 numberOfBufferFills = (size / numberOfBytesToReadPerFill) + 1;
uint16 bufferFillCount = 0;
uint32 numberOfBytesRead = 0;
char* buffer = (char*)malloc(numberOfBytesToReadPerFill * numberOfBufferFills);
char* bufferStart = buffer;
sint8 readDataValue = 0;
while (readOn == true) {
actualCount = numberOfBytesToReadPerFill;
readDataValue = this->readData(buffer, actualCount, offset);
bufferFillCount++;
if (readDataValue != 1) {
readOn = false;
if (readDataValue == -1) {
if (debug == true) {
writeLog("OK: readData: eofErr");
}
} else {
writeLog("ERR: readData");
success = false;
}
} else {
offset += actualCount;
buffer = buffer + actualCount;
if (debug == true) {
sprintf(logStr, "OK: readData (cnt: %d, totalBytes: %d, req: %d, read: %d)", bufferFillCount, numberOfBytesRead, numberOfBytesToReadPerFill, actualCount);
writeLog(logStr);
}
}
numberOfBytesRead += actualCount;
if (debug == true) {
printf("----------------------\n");
printf("BUFFER:\n%s\n", bufferStart);
printf("----------------------\n");
}
}
success = this->close();
if (debug == true) {
writeLog("aFile.close()");
}
*dataOut = (void*)bufferStart;
size = numberOfBytesRead;
return success;
}
sint8 VisualFile::readData(char* buffer, uint32& numberOfbytes, uint32 startOffset) {
sint8 retVal = 0;
#if TARGET_OS_MAC
ByteCount numberOfbytesRequested = static_cast<ByteCount>(numberOfbytes);
//osErr = FSReadFork(this->currForkRefNum, fsFromStart, startOffset, numberOfbytesRequested, buffer, static_cast<ByteCount*>(&numberOfbytes));
OSErr osErr = FSReadFork(this->currForkRefNum, fsFromStart, startOffset, numberOfbytesRequested, buffer, reinterpret_cast<ByteCount*>(&numberOfbytes));
if (osErr == noErr) {
retVal = 1;
} else if (osErr == eofErr) {
retVal = -1; // eof
}
#endif
#if TARGET_OS_WIN
DWORD nNumberOfBytesToRead = numberOfbytes;
LPOVERLAPPED lpOverlapped = NULL;
DWORD numOfBytes = 0;
BOOL success = ReadFile(this->currHandle, buffer, nNumberOfBytesToRead, &numOfBytes, lpOverlapped);
if (success) {
numberOfbytes = static_cast<uint32>(numOfBytes);
if (numberOfbytes == 0) {
retVal = -1; // eof
} else {
retVal = 1;
}
}
#endif
return retVal;
}
bool VisualFile::remove() {
bool success = true;
#if TARGET_OS_MAC
OSErr osErr = FSDeleteObject(&(this->fsRef));
if (osErr != noErr) {
success = false;
}
#endif
#if TARGET_OS_WIN
return false; // todo
#endif
knownWhetherFileOrDirectoryExists = true;
doesExistBool = false;
return success;
}
/*
bool VisualFile::doesExist(void) {
#if TARGET_OS_WIN
if (this->knownWhetherFileOrDirectoryExists == false) {
this->doesExistBool =
test test
this->knownWhetherFileOrDirectoryExists = true;
}
#endif
return this->doesExistBool;
}
*/
void VisualFile::getFilePath(VisualString& filePath) const {
#if TARGET_OS_MAC
CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &(this->fsRef));
CFStringRef cfString = NULL;
if (url != NULL) {
cfString = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
CFRelease(url);
}
if (cfString != NULL) {
filePath = VisualString(cfString);
CFRelease(cfString);
}
#endif
#if TARGET_OS_WIN
if (wcslen(filePathWin) > 0) {
filePath = VisualString(this->filePathWin);
}
#endif
}
bool VisualFile::getSize(size_t& size) const {
bool success = false;
size = 0;
#if TARGET_OS_MAC
FSCatalogInfo info;
OSErr osErr = FSGetCatalogInfo(&(this->fsRef), kFSCatInfoDataSizes, &info, NULL, NULL, NULL);
if (osErr == noErr) {
size = (size_t)(info.dataLogicalSize); // UInt64
success = true;
}
#endif
#if TARGET_OS_WIN
DWORD dwDesiredAccess = GENERIC_READ;
DWORD dwShareMode = FILE_SHARE_READ;
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
DWORD dwCreationDisposition = OPEN_ALWAYS; // open the file if it exists, else create new one
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
HANDLE hTemplateFile = NULL;
HANDLE fileHandle = CreateFileW((LPCWSTR)this->filePathWin,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
if (fileHandle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER sizeUInt64;
BOOL GetFileSizeExSuccess = GetFileSizeEx(fileHandle, &sizeUInt64);
CloseHandle(fileHandle);
if (GetFileSizeExSuccess) {
size = (size_t)sizeUInt64.QuadPart;
success = true;
}
}
#endif
return success;
}
VisualFile* VisualFile::createWithDirectoryOfTemporaryItems() {
VisualFile* aVisualFile = new VisualFile;
bool success = aVisualFile->initWithDirectoryOfTemporaryItems();
if (!success) {
delete aVisualFile;
aVisualFile = NULL;
}
return aVisualFile;
}
VisualFile* VisualFile::createWithUserDesktopDirectory() {
VisualFile* aVisualFile = new VisualFile;
bool success = aVisualFile->initWithUserDesktopDirectory();
if (!success) {
delete aVisualFile;
aVisualFile = NULL;
}
return aVisualFile;
}
VisualFile* VisualFile::createWithPreferenceStoreDirectory() {
VisualFile* aVisualFile = new VisualFile;
bool success = aVisualFile->initWithPreferenceStoreDirectory();
if (!success) {
delete aVisualFile;
aVisualFile = NULL;
}
return aVisualFile;
}
#if TARGET_OS_MAC
VisualFile* VisualFile::createWithResourcesDirectory() {
VisualFile* aVisualFile = new VisualFile;
bool success = aVisualFile->initWithResourcesDirectory();
if (!success) {
delete aVisualFile;
aVisualFile = NULL;
}
return aVisualFile;
}
#endif
void VisualFile::copy(const VisualFile& other) {
this->doesExistBool = other.doesExistBool;
this->knownWhetherFileOrDirectoryExists = other.knownWhetherFileOrDirectoryExists;
this->isDirectory = other.isDirectory;
#if TARGET_OS_MAC
this->fsRef = other.fsRef;
this->currForkRefNum = other.currForkRefNum;
#endif
#if TARGET_OS_WIN
this->currHandle = other.currHandle;
#endif
#if TARGET_OS_WIN
wcscpy(this->filePathWin, other.filePathWin);
#endif
}
void VisualFile::clear() {
#if TARGET_OS_MAC
this->currForkRefNum = 0;
#endif
#if TARGET_OS_WIN
this->currHandle = NULL;
#endif
this->knownWhetherFileOrDirectoryExists = true;
this->doesExistBool = false;
this->isDirectory = false;
}
#if TARGET_OS_WIN
bool VisualFile::getDataOfResource(int nameId, char* type, void** data, uint32& size) {
bool success = true;
HRSRC resInfoHandle;
HGLOBAL resHandle;
HMODULE plugInHandle;
char pluginFileName[256];
sprintf(pluginFileName, "%s.dll", VisualConfiguration::visualizerPluginIdentifierName);
plugInHandle = GetModuleHandle(pluginFileName);
if (plugInHandle == NULL) {
writeLog("pluginHandle is NULL");
return false;
}
resInfoHandle = FindResource(plugInHandle, MAKEINTRESOURCE(nameId), type);
if (resInfoHandle == NULL) {
writeLog("resInfoHandle is NULL");
return false;
}
resHandle = LoadResource(plugInHandle, resInfoHandle);
*data = LockResource(resHandle);
size = SizeofResource(plugInHandle, resInfoHandle);
return success;
}
#endif
bool VisualFile::writeDataToFile(void** data, uint32 size, VisualFile& aFile) {
bool success = true;
VisualString filePathString;
aFile.getFilePath(filePathString);
const char* const filePathCString = filePathString.getUtf8Representation();
#if TARGET_OS_WIN
FILE* file;
fopen_s(&file, filePathCString, "w+b");
int bytesWritten = 0;
bytesWritten = fwrite(*data, sizeof(char), size, file);
fclose(file);
#endif
#if TARGET_OS_MAC
FILE* file = fopen(filePathCString, "w+b");
size_t bytesWritten = 0;
bytesWritten = fwrite(*data, sizeof(char), size, file);
fclose(file);
#endif
return success;
}