Merge pull request #199 from execjosh/fix-issue-367

Charset option for `fs.{open,read,write}`
1.5
Ariya Hidayat 2012-02-04 23:40:31 -08:00
commit d40fb8e637
4 changed files with 106 additions and 16 deletions

View File

@ -37,11 +37,16 @@
// File
// public:
File::File(QFile *openfile, QObject *parent) :
File::File(QFile *openfile, QTextCodec *codec, QObject *parent) :
QObject(parent),
m_file(openfile)
{
m_fileStream.setDevice(m_file);
if ((QTextCodec *)NULL == codec) {
m_fileStream.setCodec(QTextCodec::codecForName("UTF-8"));
} else {
m_fileStream.setCodec(codec);
}
}
File::~File()
@ -273,12 +278,40 @@ QString FileSystem::absolute(const QString &relativePath) const
return QFileInfo(relativePath).absoluteFilePath();
}
static inline QString getCharset(const QVariant &val) {
QVariant::Type type = val.type();
// val must be either a string or null/undefined.
if (QVariant::String != type && QVariant::Invalid != type) {
qDebug() << "FileSystem::open - " << "Charset must be a string!";
return QString();
}
QString charset = val.toString();
// Default to UTF-8
if (charset.isEmpty()) {
charset = "UTF-8";
}
return charset;
}
// Files
QObject *FileSystem::_open(const QString &path, const QString &mode) const
QObject *FileSystem::_open(const QString &path, const QVariantMap &opts) const
{
File *f = NULL;
QFile *_f = new QFile(path);
QFile::OpenMode modeCode = QFile::NotOpen;
QVariant modeVar = opts["mode"];
// Ensure only strings
if (modeVar.type() != QVariant::String) {
qDebug() << "FileSystem::open - " << "Mode must be a string!" << modeVar;
return NULL;
}
QString mode = modeVar.toString();
// Ensure only one "mode character" has been selected
if ( mode.length() != 1) {
@ -316,9 +349,16 @@ QObject *FileSystem::_open(const QString &path, const QString &mode) const
}
}
QString charset = getCharset(opts["charset"]);
QTextCodec *codec = QTextCodec::codecForName(charset.toAscii());
if ((QTextCodec *)NULL == codec) {
qDebug() << "FileSystem::open - " << "Unknown charset:" << charset;
return NULL;
}
// Try to Open
if ( _f->open(modeCode) ) {
f = new File(_f);
f = new File(_f, codec);
if ( f ) {
return f;
}

View File

@ -33,6 +33,7 @@
#include <QObject>
#include <QStringList>
#include <QFile>
#include <QTextCodec>
#include <QTextStream>
#include <QVariant>
@ -41,7 +42,7 @@ class File : public QObject
Q_OBJECT
public:
File(QFile *openfile, QObject *parent = 0);
File(QFile *openfile, QTextCodec *codec, QObject *parent = 0);
virtual ~File();
public slots:
@ -87,10 +88,10 @@ public slots:
bool _removeTree(const QString &path) const;
// Files
// 'open(path, mode)' implemented in "filesystem-shim.js" using '_open(path, mode)'
QObject *_open(const QString &path, const QString &mode) const;
// 'read(path)' implemented in "filesystem-shim.js"
// 'write(path, mode)' implemented in the "filesystem-shim.js"
// 'open(path, mode|options)' implemented in "filesystem-shim.js" using '_open(path, opts)'
QObject *_open(const QString &path, const QVariantMap &opts) const;
// 'read(path, options)' implemented in "filesystem-shim.js"
// 'write(path, mode|options)' implemented in the "filesystem-shim.js"
// 'remove(path)' implemented in "filesystem-shim.js" using '_remove(path)'
bool _remove(const QString &path) const;
// 'copy(source, destination)' implemented in "filesystem-shim.js" using '_copy(source, destination)'

View File

@ -36,11 +36,30 @@
* It will throw exception if it fails.
*
* @param path Path of the file to open
* @param mode Open Mode. A string made of 'r', 'w', 'a/+' characters.
* @param modeOrOpts
* mode: Open Mode. A string made of 'r', 'w', 'a/+' characters.
* opts: Options.
* - mode (see Open Mode above)
* - charset An IANA, case insensitive, charset name.
* @return "file" object
*/
exports.open = function (path, mode) {
var file = exports._open(path, mode);
exports.open = function (path, modeOrOpts) {
var file, opts;
// Extract charset from opts
if (modeOrOpts == null) {
// Empty options
opts = {};
} else if (typeof modeOrOpts !== 'object') {
opts = {
mode: modeOrOpts
};
} else {
opts = modeOrOpts;
}
// Open file
file = exports._open(path, opts);
if (file) {
return file;
}
@ -51,10 +70,16 @@ exports.open = function (path, mode) {
* It will throw an exception if it fails.
*
* @param path Path of the file to read from
* @param opts Options.
* - charset An IANA, case insensitive, charset name.
* @return file content
*/
exports.read = function (path) {
var f = exports.open(path, 'r'),
exports.read = function (path, opts) {
if (opts == null || typeof opts !== 'object') {
opts = {};
}
opts.mode = 'r';
var f = exports.open(path, opts),
content = f.read();
f.close();
@ -66,10 +91,17 @@ exports.read = function (path) {
*
* @param path Path of the file to read from
* @param content Content to write to the file
* @param mode Open Mode. A string made of 'w' or 'a / +' characters.
* @param modeOrOpts
* mode: Open Mode. A string made of 'r', 'w', 'a/+' characters.
* opts: Options.
* - mode (see Open Mode above)
* - charset An IANA, case insensitive, charset name.
*/
exports.write = function (path, content, mode) {
var f = exports.open(path, mode);
exports.write = function (path, content, modeOrOpts) {
if (modeOrOpts == null) {
modeOrOpts = {};
}
var f = exports.open(path, modeOrOpts);
f.write(content);
f.close();

View File

@ -3,6 +3,7 @@ describe("Basic Files API (read, write, remove, ...)", function() {
FILENAME_COPY = FILENAME + ".copy",
FILENAME_MOVED = FILENAME + ".moved",
FILENAME_EMPTY = FILENAME + ".empty",
FILENAME_ENC = FILENAME + ".enc",
ABSENT = "absent-01.test";
it("should be able to create and write a file", function() {
@ -80,4 +81,20 @@ describe("Basic Files API (read, write, remove, ...)", function() {
fs.copy(ABSENT, FILENAME_COPY);
}).toThrow("Unable to copy file '" + ABSENT + "' at '" + FILENAME_COPY + "'");
});
it("should be read/write utf8 text by default", function() {
var content, output = "ÄABCÖ";
try {
var f = fs.open(FILENAME_ENC, "w");
f.write(output);
f.close();
f = fs.open(FILENAME_ENC, "r");
content = f.read();
f.close();
fs.remove(FILENAME_ENC);
} catch (e) { }
expect(content).toEqual(output);
});
});