Skip to content
This repository has been archived by the owner on Sep 2, 2021. It is now read-only.

Commit

Permalink
Now BOM is preserved in Win and MAC (#610)
Browse files Browse the repository at this point in the history
* Now BOM is preserved in Win and MAC

* Added error strings for failure in encode/decode and utf-16

* Mac related error string changes

* Addressed review comments

* minor change

* Addressed win review comments
  • Loading branch information
saurabh95 authored and swmitra committed Jun 27, 2017
1 parent d1c7e6f commit d1b1c3e
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 72 deletions.
12 changes: 8 additions & 4 deletions appshell/appshell_extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,32 +304,36 @@ class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
ExtensionString filename = argList->GetString(1);
ExtensionString encoding = argList->GetString(2);
std::string contents = "";
bool preserveBOM = false;

error = ReadFile(filename, encoding, contents);
error = ReadFile(filename, encoding, contents, preserveBOM);

// Set response args for this function
responseArgs->SetString(2, contents);
responseArgs->SetString(3, encoding);
responseArgs->SetBool(4, preserveBOM);
}
} else if (message_name == "WriteFile") {
// Parameters:
// 0: int32 - callback id
// 1: string - filename
// 2: string - data
// 3: string - encoding
if (argList->GetSize() != 4 ||
if (argList->GetSize() != 5 ||
argList->GetType(1) != VTYPE_STRING ||
argList->GetType(2) != VTYPE_STRING ||
argList->GetType(3) != VTYPE_STRING) {
argList->GetType(3) != VTYPE_STRING ||
argList->GetType(4) != VTYPE_BOOL) {
error = ERR_INVALID_PARAMS;
}

if (error == NO_ERROR) {
ExtensionString filename = argList->GetString(1);
std::string contents = argList->GetString(2);
ExtensionString encoding = argList->GetString(3);
bool preserveBOM = argList->GetBool(4);

error = WriteFile(filename, contents, encoding);
error = WriteFile(filename, contents, encoding, preserveBOM);
// No additional response args for this function
}
} else if (message_name == "SetPosixPermissions") {
Expand Down
19 changes: 17 additions & 2 deletions appshell/appshell_extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,21 @@ if (!appshell.app) {
* @constant An unsupported encoding value was specified.
*/
appshell.fs.ERR_UNSUPPORTED_ENCODING = 5;

/**
* @constant File could not be encoded.
*/
appshell.fs.ERR_ENCODE_FILE_FAILED = 18;

/**
* @constant File could not be decoded.
*/
appshell.fs.ERR_DECODE_FILE_FAILED = 19;

/**
* @constant File was encoded with utf-16
*/
appshell.fs.ERR_UNSUPPORTED_UTF16_ENCODING = 20;

/**
* @constant File could not be written.
Expand Down Expand Up @@ -394,8 +409,8 @@ if (!appshell.app) {
* @return None. This is an asynchronous call that sends all return information to the callback.
*/
native function WriteFile();
appshell.fs.writeFile = function (path, data, encoding, callback) {
WriteFile(callback || _dummyCallback, path, data, encoding);
appshell.fs.writeFile = function (path, data, encoding, preserveBOM, callback) {
WriteFile(callback || _dummyCallback, path, data, encoding, preserveBOM);
};

/**
Expand Down
73 changes: 34 additions & 39 deletions appshell/appshell_extensions_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
#include <sys/utsname.h>
#include <mach-o/arch.h>

#define UTF8_BOM "\xEF\xBB\xBF"

NSMutableArray* pendingOpenFiles;

@interface ChromeWindowsTerminatedObserver : NSObject
Expand Down Expand Up @@ -647,62 +649,53 @@ int32 GetFileInfo(ExtensionString filename, uint32& modtime, bool& isDir, double
return ConvertNSErrorCode(error, true);
}

int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string& contents)
int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string& contents, bool& preserveBOM)
{
if (encoding == "utf8") {
encoding = "UTF-8";
}
NSString* path = [NSString stringWithUTF8String:filename.c_str()];

NSStringEncoding enc;
int32 error = NO_ERROR;

NSString* fileContents = nil;
if (encoding == "UTF-8") {
enc = NSUTF8StringEncoding;
NSError* NSerror = nil;
fileContents = [NSString stringWithContentsOfFile:path encoding:enc error:&NSerror];
}

if (fileContents)
{
contents = [fileContents UTF8String];
return NO_ERROR;
} else {

try {
std::ifstream file(filename.c_str());
std::stringstream ss;
ss << file.rdbuf();
contents = ss.str();
std::string detectedCharSet;
try {
std::ifstream file(filename.c_str());
std::stringstream ss;
ss << file.rdbuf();
contents = ss.str();
std::string detectedCharSet;
try {
if (encoding == "UTF-8") {
CharSetDetect ICUDetector;
ICUDetector(contents.c_str(), contents.size(), detectedCharSet);
}
else {
detectedCharSet = encoding;
}
if (!detectedCharSet.empty()) {
if (encoding == "UTF-8") {
CharSetDetect ICUDetector;
ICUDetector(contents.c_str(), contents.size(), detectedCharSet);
}
else {
detectedCharSet = encoding;
}
if (detectedCharSet == "UTF-16LE" || detectedCharSet == "UTF-16BE") {
return ERR_UNSUPPORTED_UTF16_ENCODING;
}
if (detectedCharSet != "UTF-8") {
try {
std::transform(detectedCharSet.begin(), detectedCharSet.end(), detectedCharSet.begin(), ::toupper);
DecodeContents(contents, detectedCharSet);
encoding = detectedCharSet;
} catch (...) {
error = ERR_DECODE_FILE_FAILED;
}
else {
error = ERR_UNSUPPORTED_ENCODING;
}
} catch (...) {
error = ERR_UNSUPPORTED_ENCODING;
}
else {
CheckAndRemoveUTF8BOM(contents, preserveBOM);
}
} catch (...) {
error = ERR_CANT_READ;
error = ERR_UNSUPPORTED_ENCODING;
}
} catch (...) {
error = ERR_CANT_READ;
}

return error;
}

int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding)
int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding, bool preserveBOM)
{
const char *filenameStr = filename.c_str();
int32 error = NO_ERROR;
Expand All @@ -715,8 +708,10 @@ int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString
CharSetEncode ICUEncoder(encoding);
ICUEncoder(contents);
} catch (...) {
error = ERR_CANT_READ;
error = ERR_ENCODE_FILE_FAILED;
}
} else if (encoding == "UTF-8" && preserveBOM) {
contents = UTF8_BOM + contents;
}

try {
Expand Down
10 changes: 10 additions & 0 deletions appshell/appshell_extensions_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include <unicode/ucsdet.h>
#include <unicode/ucnv.h>

#define UTF8_BOM "\xEF\xBB\xBF"

CharSetDetect::CharSetDetect() {
m_charsetDetector_ = NULL;
m_icuError = U_ZERO_ERROR;
Expand Down Expand Up @@ -88,3 +90,11 @@ void DecodeContents(std::string &contents, const std::string& encoding) {
}
}
#endif

void CheckAndRemoveUTF8BOM(std::string& contents, bool& preserveBOM) {
if (contents.length() >= 3 && contents.substr(0,3) == UTF8_BOM) {
contents.erase(0,3);
preserveBOM = true;
}
}

47 changes: 26 additions & 21 deletions appshell/appshell_extensions_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,30 @@
// Extension error codes. These MUST be in sync with the error
// codes in appshell_extensions.js
#if !defined(OS_WIN) // NO_ERROR is defined on windows
static const int NO_ERROR = 0;
static const int NO_ERROR = 0;
#endif
static const int ERR_UNKNOWN = 1;
static const int ERR_INVALID_PARAMS = 2;
static const int ERR_NOT_FOUND = 3;
static const int ERR_CANT_READ = 4;
static const int ERR_UNSUPPORTED_ENCODING = 5;
static const int ERR_CANT_WRITE = 6;
static const int ERR_OUT_OF_SPACE = 7;
static const int ERR_NOT_FILE = 8;
static const int ERR_NOT_DIRECTORY = 9;
static const int ERR_FILE_EXISTS = 10;
static const int ERR_BROWSER_NOT_INSTALLED = 11;
static const int ERR_CL_TOOLS_CANCELLED = 12;
static const int ERR_CL_TOOLS_RMFAILED = 13;
static const int ERR_CL_TOOLS_MKDIRFAILED = 14;
static const int ERR_UNKNOWN = 1;
static const int ERR_INVALID_PARAMS = 2;
static const int ERR_NOT_FOUND = 3;
static const int ERR_CANT_READ = 4;
static const int ERR_UNSUPPORTED_ENCODING = 5;
static const int ERR_CANT_WRITE = 6;
static const int ERR_OUT_OF_SPACE = 7;
static const int ERR_NOT_FILE = 8;
static const int ERR_NOT_DIRECTORY = 9;
static const int ERR_FILE_EXISTS = 10;
static const int ERR_BROWSER_NOT_INSTALLED = 11;
static const int ERR_CL_TOOLS_CANCELLED = 12;
static const int ERR_CL_TOOLS_RMFAILED = 13;
static const int ERR_CL_TOOLS_MKDIRFAILED = 14;
static const int ERR_CL_TOOLS_SYMLINKFAILED = 15;
static const int ERR_CL_TOOLS_SERVFAILED = 16;
static const int ERR_CL_TOOLS_NOTSUPPORTED = 17;
static const int ERR_CL_TOOLS_SERVFAILED = 16;
static const int ERR_CL_TOOLS_NOTSUPPORTED = 17;
static const int ERR_ENCODE_FILE_FAILED = 18;
static const int ERR_DECODE_FILE_FAILED = 19;
static const int ERR_UNSUPPORTED_UTF16_ENCODING = 20;

static const int ERR_PID_NOT_FOUND = -9999; // negative int to avoid confusion with real PIDs
static const int ERR_PID_NOT_FOUND = -9999; // negative int to avoid confusion with real PIDs

typedef uint8_t u8;
typedef uint16_t u16;
Expand Down Expand Up @@ -112,6 +115,8 @@ class CharSetEncode
void DecodeContents(std::string &contents, const std::string& encoding);
#endif

void CheckAndRemoveUTF8BOM(std::string& contents, bool& preserveBOM);

// Native extension code. These are implemented in appshell_extensions_mac.mm
// and appshell_extensions_win.cpp
int32 OpenLiveBrowser(ExtensionString argURL, bool enableRemoteDebugging);
Expand Down Expand Up @@ -158,9 +163,9 @@ int32 Rename(ExtensionString oldName, ExtensionString newName);

int32 GetFileInfo(ExtensionString filename, uint32& modtime, bool& isDir, double& size, ExtensionString& realPath);

int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string& contents);
int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string& contents, bool& hasBOM);

int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding);
int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding, bool preserveBOM);

int32 SetPosixPermissions(ExtensionString filename, int32 mode);

Expand Down Expand Up @@ -207,4 +212,4 @@ int32 GetMenuPosition(CefRefPtr<CefBrowser> browser, const ExtensionString& comm

void DragWindow(CefRefPtr<CefBrowser> browser);

std::string GetSystemUniqueID();
std::string GetSystemUniqueID();
21 changes: 15 additions & 6 deletions appshell/appshell_extensions_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
#define UNICODE_LEFT_ARROW 0x2190
#define UNICODE_DOWN_ARROW 0x2193

#define UTF8_BOM "\xEF\xBB\xBF"

// Forward declarations for functions at the bottom of this file
void ConvertToNativePath(ExtensionString& filename);
void ConvertToUnixPath(ExtensionString& filename);
Expand Down Expand Up @@ -858,8 +860,6 @@ CharSetMap charSetMap =
{ "SHIFT_JIS", 932 },
{ "ISO-8859-3", 28593 },
{ "ISO-8859-4", 28594 },
{ "UTF-16LE", 1200 },
{ "UTF-16BE", 1201},
{ "WINDOWS-1257", 1257 },
{ "WINDOWS-1258", 1258 },
{ "GB2312", 936 },
Expand Down Expand Up @@ -933,7 +933,7 @@ class ReadFileHandle {



int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string& contents)
int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string& contents, bool& preserveBOM)
{
if (encoding == L"utf8") {
encoding = L"UTF-8";
Expand Down Expand Up @@ -985,6 +985,9 @@ int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string&
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> conv;
detectedCharSet = conv.to_bytes(encoding);
}
if (detectedCharSet == "UTF-16LE" || detectedCharSet == "UTF-16LE") {
return ERR_UNSUPPORTED_UTF16_ENCODING;
}
std::transform(detectedCharSet.begin(), detectedCharSet.end(), detectedCharSet.begin(), ::toupper);
CharSetMap::iterator iter = charSetMap.find(detectedCharSet);

Expand All @@ -1001,13 +1004,16 @@ int32 ReadFile(ExtensionString filename, ExtensionString& encoding, std::string&
error = NO_ERROR;
}
catch (...) {
error = ERR_UNSUPPORTED_ENCODING;
error = ERR_DECODE_FILE_FAILED;
}
}
} catch (...) {
error = ERR_UNSUPPORTED_ENCODING;
}
}
if (encoding == L"UTF-8") {
CheckAndRemoveUTF8BOM(contents, preserveBOM);
}
}
else {
error = ConvertWinErrorCode(GetLastError(), false);
Expand Down Expand Up @@ -1057,7 +1063,7 @@ static void WideToCharSet(const std::wstring &aUTF16string, long codePage, std::



int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding)
int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding, bool preserveBOM)
{
if (encoding == L"utf8") {
encoding = L"UTF-8";
Expand All @@ -1071,9 +1077,12 @@ int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString
WideToCharSet(content, iter->second, contents);
}
else {
error = ERR_UNSUPPORTED_ENCODING;
error = ERR_ENCODE_FILE_FAILED;
}
}
if (encoding == L"UTF-8" && preserveBOM) {
contents = UTF8_BOM + contents;
}

HANDLE hFile = CreateFile(filename.c_str(), GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
Expand Down

0 comments on commit d1b1c3e

Please sign in to comment.