securityanddataprivacytools/securitytools/certapp/utils/utils.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 10 Sep 2009 14:01:51 +0300
changeset 8 35751d3474b7
parent 0 2c201484c85f
permissions -rw-r--r--
Revision: 200935

/*
* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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 <fstream>
#include "utils.h"
#include "logger.h"

#ifndef __LINUX__
#include <windows.h>
#endif

typedef unsigned char TUint8;
typedef unsigned int TUint;

#ifdef __LINUX__
void OpenUtf8FStreamForRead(std::fstream &aFStream, const char *aUtf8FileName)
{
	aFStream.open(aUtf8FileName, std::ios_base::binary | std::ios_base::in);
}

void OpenUtf8FStreamForWrite(std::fstream &aFStream, const char *aUtf8FileName)
{
	aFStream.open(aUtf8FileName, std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);
}

#else

WCHAR *WindowsUtf8ToUtf16(const char *aUtf8)
{
	int utf8Len = strlen(aUtf8) + 1; // We want to copy the terminator to the new string
	int utf16Space = MultiByteToWideChar(CP_UTF8, 0, aUtf8, utf8Len, 0, 0);
	if(utf16Space <= 0)
		{
		dbg << Log::Indent() << "Failed to convert UTF-8 '" << aUtf8 << "' to UTF16" << Log::Endl();
		FatalError();
		return 0;
		}
	// prog << Log::Indent() << "utf16Space " << utf16Space << Log::Endl();
	WCHAR *utf16 = new WCHAR[utf16Space];
	(void) MultiByteToWideChar(CP_UTF8, 0, aUtf8, utf8Len, utf16, utf16Space);
#if 0
	prog << Log::Indent() << "Raw UTF16 name is (chars " << utf16Space << ")" << Log::Endl();
	for(int i=0; i<utf16Space*2; ++i)
		{
		prog << TUint(((TUint8 *)utf16)[i]) << Log::Endl();
		}
#endif
	return utf16;
}

CHAR *WindowsUtf16ToUtf8(const WCHAR *aUtf16)
{
	int utf16Len = wcslen(aUtf16) + 1; // We want to copy the terminator to the new string
	int utf8Space = WideCharToMultiByte(CP_UTF8, 0, aUtf16, utf16Len, 0, 0, 0, 0);
	if(utf8Space <= 0)
		{
		dbg << Log::Indent() << "Failed to convert UTF16 string to UTF8" << Log::Endl();
		FatalError();
		return 0;
		}
	//prog << Log::Indent() << "utf8Space " << utf8Space << Log::Endl();
	CHAR *utf8 = new CHAR[utf8Space];
	(void) WideCharToMultiByte(CP_UTF8, 0, aUtf16, utf16Len, utf8, utf8Space, 0, 0);

#if 0
	prog << Log::Indent() << "Raw UTF8 name is (chars " << utf8Space << ")" << Log::Endl();
	for(int i=0; i<utf8Space; ++i)
		{
		prog << TUint(((TUint8 *)utf8)[i]) << Log::Endl();
		}
#endif
	return utf8;
}

WCHAR *WindowsRetrieveDosName(const WCHAR *aLongName)
{
	// Convert to a short DOS file name. File MUST already exist!
	// len will be space required for string and terminator
	DWORD len = GetShortPathNameW((WCHAR *)aLongName, 0, 0);
	if( len <= 0 )
		{
		prog << Log::Indent() << "Failed to find existing file and retrieve short name" << Log::Endl();
		return 0;
		}
	
	//prog << Log::Indent() << "space required for short name is " << len << Log::Endl();
	WCHAR *shortName = new WCHAR[len];
	(void) GetShortPathNameW(aLongName, shortName, len);
	return shortName;
}

void OpenUtf8FStreamForRead(std::fstream &aFStream, const char *aUtf8FileName)
{
	// Unfortunately the windows C++ STL library will not open files specified via a UTF-8 filename.
	// The workaround is to convert the UTF-8 name to the short DOS compatible name and open that instead

	// First convert the UTF-8 name to UTF-16 for use with the windows APIs
	WCHAR *utf16Name = WindowsUtf8ToUtf16(aUtf8FileName);

	// Obtain short DOS compatible name for file
	WCHAR *utf16NameDos = WindowsRetrieveDosName(utf16Name);
	if(utf16NameDos == 0)
		{
		aFStream.setstate(std::ios_base::badbit);
		delete [] utf16Name;
		return;
		}

	char *utf8NameDos = WindowsUtf16ToUtf8(utf16NameDos);

	aFStream.open(utf8NameDos, std::ios_base::binary | std::ios_base::in);

	delete [] utf8NameDos;
	delete [] utf16NameDos;
	delete [] utf16Name;
	return;
}

void OpenUtf8FStreamForWrite(std::fstream &aFStream, const char *aUtf8FileName)
{
	// Unfortunately the windows C++ STL library will not open files specified via a UTF-8 filename.
	// The workaround is to make sure the file already exists and then convert the UTF-8 name to the short DOS compatible name 
	// and open that instead

	// First convert the UTF-8 name to UTF-16 for use with the windows APIs
	WCHAR *utf16Name = WindowsUtf8ToUtf16(aUtf8FileName);

	// Make sure the file exists
	HANDLE fh = CreateFileW((WCHAR *)utf16Name, GENERIC_WRITE, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0,  CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
	if(fh == INVALID_HANDLE_VALUE)
		{
		dbg << Log::Indent() << "Failed to create file '" << aUtf8FileName << "'" << Log::Endl();
		aFStream.setstate(std::ios_base::badbit);
		delete [] utf16Name;
		return;
		}
	// Close handle
	CloseHandle(fh);


	// Obtain short DOS compatible name for file
	WCHAR *utf16NameDos = WindowsRetrieveDosName(utf16Name);
	if(utf16NameDos == 0)
		{
		aFStream.setstate(std::ios_base::badbit);
		delete [] utf16Name;
		return;
		}

	char *utf8NameDos = WindowsUtf16ToUtf8(utf16NameDos);

	aFStream.open(utf8NameDos, std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);

	delete [] utf8NameDos;
	delete [] utf16NameDos;
	delete [] utf16Name;
	return;
}
#endif

// End of file