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 // File
// public: // public:
File::File(QFile *openfile, QObject *parent) : File::File(QFile *openfile, QTextCodec *codec, QObject *parent) :
QObject(parent), QObject(parent),
m_file(openfile) m_file(openfile)
{ {
m_fileStream.setDevice(m_file); m_fileStream.setDevice(m_file);
if ((QTextCodec *)NULL == codec) {
m_fileStream.setCodec(QTextCodec::codecForName("UTF-8"));
} else {
m_fileStream.setCodec(codec);
}
} }
File::~File() File::~File()
@ -273,12 +278,40 @@ QString FileSystem::absolute(const QString &relativePath) const
return QFileInfo(relativePath).absoluteFilePath(); 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 // Files
QObject *FileSystem::_open(const QString &path, const QString &mode) const QObject *FileSystem::_open(const QString &path, const QVariantMap &opts) const
{ {
File *f = NULL; File *f = NULL;
QFile *_f = new QFile(path); QFile *_f = new QFile(path);
QFile::OpenMode modeCode = QFile::NotOpen; 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 // Ensure only one "mode character" has been selected
if ( mode.length() != 1) { 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 // Try to Open
if ( _f->open(modeCode) ) { if ( _f->open(modeCode) ) {
f = new File(_f); f = new File(_f, codec);
if ( f ) { if ( f ) {
return f; return f;
} }

View File

@ -33,6 +33,7 @@
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
#include <QFile> #include <QFile>
#include <QTextCodec>
#include <QTextStream> #include <QTextStream>
#include <QVariant> #include <QVariant>
@ -41,7 +42,7 @@ class File : public QObject
Q_OBJECT Q_OBJECT
public: public:
File(QFile *openfile, QObject *parent = 0); File(QFile *openfile, QTextCodec *codec, QObject *parent = 0);
virtual ~File(); virtual ~File();
public slots: public slots:
@ -87,10 +88,10 @@ public slots:
bool _removeTree(const QString &path) const; bool _removeTree(const QString &path) const;
// Files // Files
// 'open(path, mode)' implemented in "filesystem-shim.js" using '_open(path, mode)' // 'open(path, mode|options)' implemented in "filesystem-shim.js" using '_open(path, opts)'
QObject *_open(const QString &path, const QString &mode) const; QObject *_open(const QString &path, const QVariantMap &opts) const;
// 'read(path)' implemented in "filesystem-shim.js" // 'read(path, options)' implemented in "filesystem-shim.js"
// 'write(path, mode)' implemented in the "filesystem-shim.js" // 'write(path, mode|options)' implemented in the "filesystem-shim.js"
// 'remove(path)' implemented in "filesystem-shim.js" using '_remove(path)' // 'remove(path)' implemented in "filesystem-shim.js" using '_remove(path)'
bool _remove(const QString &path) const; bool _remove(const QString &path) const;
// 'copy(source, destination)' implemented in "filesystem-shim.js" using '_copy(source, destination)' // '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. * It will throw exception if it fails.
* *
* @param path Path of the file to open * @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 * @return "file" object
*/ */
exports.open = function (path, mode) { exports.open = function (path, modeOrOpts) {
var file = exports._open(path, mode); 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) { if (file) {
return file; return file;
} }
@ -51,10 +70,16 @@ exports.open = function (path, mode) {
* It will throw an exception if it fails. * It will throw an exception if it fails.
* *
* @param path Path of the file to read from * @param path Path of the file to read from
* @param opts Options.
* - charset An IANA, case insensitive, charset name.
* @return file content * @return file content
*/ */
exports.read = function (path) { exports.read = function (path, opts) {
var f = exports.open(path, 'r'), if (opts == null || typeof opts !== 'object') {
opts = {};
}
opts.mode = 'r';
var f = exports.open(path, opts),
content = f.read(); content = f.read();
f.close(); f.close();
@ -66,10 +91,17 @@ exports.read = function (path) {
* *
* @param path Path of the file to read from * @param path Path of the file to read from
* @param content Content to write to the file * @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) { exports.write = function (path, content, modeOrOpts) {
var f = exports.open(path, mode); if (modeOrOpts == null) {
modeOrOpts = {};
}
var f = exports.open(path, modeOrOpts);
f.write(content); f.write(content);
f.close(); f.close();

View File

@ -3,6 +3,7 @@ describe("Basic Files API (read, write, remove, ...)", function() {
FILENAME_COPY = FILENAME + ".copy", FILENAME_COPY = FILENAME + ".copy",
FILENAME_MOVED = FILENAME + ".moved", FILENAME_MOVED = FILENAME + ".moved",
FILENAME_EMPTY = FILENAME + ".empty", FILENAME_EMPTY = FILENAME + ".empty",
FILENAME_ENC = FILENAME + ".enc",
ABSENT = "absent-01.test"; ABSENT = "absent-01.test";
it("should be able to create and write a file", function() { 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); fs.copy(ABSENT, FILENAME_COPY);
}).toThrow("Unable to copy file '" + ABSENT + "' at '" + 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);
});
}); });