To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / main / SmallSession.cpp

History | View | Annotate | Download (5.59 KB)

1
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2

    
3
/*
4
    Sonic Lineup
5
    Comparative visualisation and alignment of related audio recordings
6
    Centre for Digital Music, Queen Mary, University of London.
7
    
8
    This program is free software; you can redistribute it and/or
9
    modify it under the terms of the GNU General Public License as
10
    published by the Free Software Foundation; either version 2 of the
11
    License, or (at your option) any later version.  See the file
12
    COPYING included with this distribution for more information.
13
*/
14

    
15
#include "SmallSession.h"
16

    
17
#include "base/TempWriteFile.h"
18
#include "base/XmlExportable.h"
19
#include "base/Exceptions.h"
20

    
21
#include <QTextStream>
22
#include <QTextCodec>
23
#include <QXmlDefaultHandler>
24

    
25
void
26
SmallSession::save(const SmallSession &session, QString sessionFile)
27
{
28
    TempWriteFile tempFile(sessionFile);
29
    QString tempFilePath(tempFile.getTemporaryFilename());
30

    
31
    QFile f(tempFilePath);
32
    if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
33
        throw std::runtime_error("Failed to open temporary file for writing");
34
    }
35
    
36
    QTextStream out(&f);
37
    out.setCodec(QTextCodec::codecForName("UTF-8"));
38
    
39
    out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
40
        << "<!DOCTYPE sonic-lineup>\n"
41
        << "<vect>\n";
42

    
43
    out << (QString("  <model id=\"1\" type=\"wavefile\" "
44
                    "mainModel=\"true\" file=\"%1\"/>\n")
45
            .arg(XmlExportable::encodeEntities(session.mainFile)));
46

    
47
    for (int i = 0; in_range_for(session.additionalFiles, i); ++i) {
48

    
49
        out << (QString("  <model id=\"%1\" type=\"wavefile\" "
50
                        "mainModel=\"false\" file=\"%2\"/>\n")
51
                .arg(i + 2)
52
                .arg(XmlExportable::encodeEntities
53
                     (session.additionalFiles[i])));
54
    }
55

    
56
    out << "</vect>\n";
57

    
58
    f.close();
59

    
60
    try {
61
        tempFile.moveToTarget();
62
    } catch (const FileOperationFailed &f) {
63
        throw std::runtime_error("Failed to move temporary file to save target");
64
    }
65
}
66

    
67
class SmallSessionReadHandler : public QXmlDefaultHandler
68
{
69
public:
70
    SmallSessionReadHandler() :
71
        m_inVectContext(false) {
72
    }
73
    virtual ~SmallSessionReadHandler() {
74
    }
75
    
76
    bool startElement(const QString & /* namespaceURI */,
77
                      const QString & /* localName */,
78
                      const QString &qName,
79
                      const QXmlAttributes& attributes) override {
80

    
81
        QString name = qName.toLower();
82

    
83
        if (name == "vect") {
84
            if (m_inVectContext) {
85
                m_errorString = "Nested session contexts found";
86
            } else {
87
                m_inVectContext = true;
88
            }
89
        } else if (name == "model") {
90
            if (!m_inVectContext) {
91
                m_errorString = "Model found outside session context";
92
            } else {
93
                readModel(attributes);
94
            }
95
        } else {
96
            SVCERR << "WARNING: SmallSessionReadHandler: Unexpected element \""
97
                   << name << "\"" << endl;
98
        }
99

    
100
        return true;
101
    }
102

    
103
    void readModel(const QXmlAttributes &attributes) {
104
        
105
        QString type = attributes.value("type").trimmed();
106
        bool isMainModel = (attributes.value("mainModel").trimmed() == "true");
107

    
108
        if (type == "wavefile") {
109
            
110
            QString file = attributes.value("file");
111

    
112
            if (isMainModel) {
113
                if (m_session.mainFile != "") {
114
                    m_errorString = "Duplicate main model found";
115
                } else {
116
                    m_session.mainFile = file;
117
                }
118
            } else {
119
                m_session.additionalFiles.push_back(file);
120
            }
121

    
122
        } else {
123
            SVCERR << "WARNING: SmallSessionReadHandler: Unsupported model type \""
124
                   << type << "\"" << endl;
125
        }
126
    }
127
    
128
    bool error(const QXmlParseException &exception) override {
129
        m_errorString =
130
            QString("%1 at line %2, column %3")
131
            .arg(exception.message())
132
            .arg(exception.lineNumber())
133
            .arg(exception.columnNumber());
134
        SVCERR << "ERROR: SmallSessionReadHandler: " << m_errorString << endl;
135
        return QXmlDefaultHandler::error(exception);
136
    }
137
    
138
    bool fatalError(const QXmlParseException &exception) override {
139
        m_errorString =
140
            QString("%1 at line %2, column %3")
141
            .arg(exception.message())
142
            .arg(exception.lineNumber())
143
            .arg(exception.columnNumber());
144
        SVCERR << "ERROR: SmallSessionReadHandler: " << m_errorString << endl;
145
        return QXmlDefaultHandler::fatalError(exception);
146
    }
147

    
148
    bool isOK() const { return (m_errorString == ""); }
149
    QString getErrorString() const { return m_errorString; }
150
    SmallSession getSession() const { return m_session; }
151
    
152
private:
153
    SmallSession m_session;
154
    QString m_errorString;
155
    bool m_inVectContext;
156
};
157

    
158
SmallSession
159
SmallSession::load(QString path)
160
{
161
    QFile f(path);
162
    if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
163
        throw std::runtime_error("Failed to open file for reading");
164
    }
165

    
166
    SmallSessionReadHandler handler;
167
    QXmlSimpleReader reader;
168
    reader.setContentHandler(&handler);
169
    reader.setErrorHandler(&handler);
170

    
171
    QXmlInputSource source(&f);
172
    bool ok = reader.parse(source);
173

    
174
    if (!handler.isOK()) {
175
        throw std::runtime_error
176
            (("Session XML load failed: " + handler.getErrorString())
177
             .toStdString());
178
    } else if (!ok) {
179
        throw std::runtime_error("Session XML parse failed");
180
    }
181

    
182
    return handler.getSession();
183
}
184