~ubuntu-branches/ubuntu/saucy/clementine/saucy

« back to all changes in this revision

Viewing changes to src/scripting/scriptarchive.cpp

  • Committer: Package Import Robot
  • Author(s): Thomas PIERSON
  • Date: 2012-01-01 20:43:39 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120101204339-lsb6nndwhfy05sde
Tags: 1.0.1+dfsg-1
New upstream release. (Closes: #653926, #651611, #657391)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* This file is part of Clementine.
2
 
   Copyright 2010, David Sansome <me@davidsansome.com>
3
 
 
4
 
   Clementine is free software: you can redistribute it and/or modify
5
 
   it under the terms of the GNU General Public License as published by
6
 
   the Free Software Foundation, either version 3 of the License, or
7
 
   (at your option) any later version.
8
 
 
9
 
   Clementine is distributed in the hope that it will be useful,
10
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
   GNU General Public License for more details.
13
 
 
14
 
   You should have received a copy of the GNU General Public License
15
 
   along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
16
 
*/
17
 
 
18
 
#include "config.h"
19
 
#include "scriptarchive.h"
20
 
#include "core/utilities.h"
21
 
 
22
 
#include <QDir>
23
 
#include <QFile>
24
 
#include <QTemporaryFile>
25
 
#include <QtConcurrentRun>
26
 
 
27
 
#ifdef HAVE_LIBARCHIVE
28
 
# include <archive.h>
29
 
# include <archive_entry.h>
30
 
#endif
31
 
 
32
 
#ifdef HAVE_LIBARCHIVE
33
 
namespace {
34
 
  // Read callbacks for libarchive
35
 
  struct IODeviceReadState {
36
 
    QIODevice* device_;
37
 
    char buf_[4096];
38
 
  };
39
 
 
40
 
  ssize_t IODeviceRead(struct archive* a, void* client_data, const void** buf) {
41
 
    IODeviceReadState* state = reinterpret_cast<IODeviceReadState*>(client_data);
42
 
 
43
 
    *buf = state->buf_;
44
 
    return state->device_->read(state->buf_, sizeof(state->buf_));
45
 
  }
46
 
 
47
 
  int IODeviceClose(struct archive* a, void* client_data) {
48
 
    IODeviceReadState* state = reinterpret_cast<IODeviceReadState*>(client_data);
49
 
 
50
 
    state->device_->close();
51
 
    return 0;
52
 
  }
53
 
 
54
 
  // Utility function to copy an entry to a QIODevice
55
 
  void CopyArchiveEntry(struct archive* in, struct archive* out) {
56
 
    char buf[4096];
57
 
    forever {
58
 
      size_t bytes_read = archive_read_data(in, buf, sizeof(buf));
59
 
      if (bytes_read == ARCHIVE_FATAL ||
60
 
          bytes_read == ARCHIVE_WARN ||
61
 
          bytes_read == ARCHIVE_RETRY) {
62
 
        qWarning() << "Error reading archive:" << archive_error_string(in);
63
 
        return;
64
 
      }
65
 
      if (bytes_read == 0) {
66
 
        break;
67
 
      }
68
 
 
69
 
      if (archive_write_data(out, buf, bytes_read) == -1) {
70
 
        qWarning() << "Error extracting archive:" << archive_error_string(out);
71
 
        return;
72
 
      }
73
 
    }
74
 
  }
75
 
}
76
 
#endif // HAVE_LIBARCHIVE
77
 
 
78
 
ScriptArchive::ScriptArchive(ScriptManager* manager)
79
 
  : manager_(manager)
80
 
{
81
 
}
82
 
 
83
 
ScriptArchive::~ScriptArchive() {
84
 
  if (!temp_dir_name_.isEmpty() && QFile::exists(temp_dir_name_)) {
85
 
    Utilities::RemoveRecursive(temp_dir_name_);
86
 
  }
87
 
}
88
 
 
89
 
QFuture<bool> ScriptArchive::LoadFromFileAsync(const QString& filename) {
90
 
  return QtConcurrent::run(this, &ScriptArchive::LoadFromFile, filename);
91
 
}
92
 
 
93
 
QFuture<bool> ScriptArchive::LoadFromDeviceAsync(QIODevice* device) {
94
 
  return QtConcurrent::run(this, &ScriptArchive::LoadFromDevice, device);
95
 
}
96
 
 
97
 
bool ScriptArchive::LoadFromFile(const QString& filename) {
98
 
  QFile file(filename);
99
 
  if (!file.open(QIODevice::ReadOnly)) {
100
 
    return false;
101
 
  }
102
 
 
103
 
  return LoadFromDevice(&file);
104
 
}
105
 
 
106
 
bool ScriptArchive::LoadFromDevice(QIODevice* device) {
107
 
#ifdef HAVE_LIBARCHIVE
108
 
  archive* a = archive_read_new();
109
 
  archive_read_support_compression_gzip(a);
110
 
  archive_read_support_format_tar(a);
111
 
 
112
 
  IODeviceReadState read_state;
113
 
  read_state.device_ = device;
114
 
 
115
 
  // Open the archive
116
 
  if (archive_read_open(a, &read_state, NULL, IODeviceRead, IODeviceClose)) {
117
 
    archive_read_finish(a);
118
 
    return false;
119
 
  }
120
 
 
121
 
  info_.clear();
122
 
 
123
 
  // Open a writer to a location in /tmp
124
 
  temp_dir_name_ = Utilities::MakeTempDir();
125
 
  archive* writer = archive_write_disk_new();
126
 
  archive_write_disk_set_options(writer,
127
 
    ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_SECURE_NODOTDOT);
128
 
 
129
 
  archive_entry* entry;
130
 
  archive_entry* out_entry = archive_entry_new();
131
 
  while (archive_read_next_header(a, &entry) == 0) {
132
 
    // Figure out where we'll extract this file
133
 
    const QString pathname = QString::fromUtf8(archive_entry_pathname(entry));
134
 
    const QString destination = temp_dir_name_ + "/" + pathname;
135
 
 
136
 
    // Copy the header and change the path name
137
 
    archive_entry_clear(out_entry);
138
 
    archive_entry_set_size(out_entry, archive_entry_size(entry));
139
 
    archive_entry_set_filetype(out_entry, archive_entry_filetype(entry));
140
 
    archive_entry_set_mode(out_entry, archive_entry_mode(entry));
141
 
    archive_entry_copy_pathname(out_entry, destination.toLocal8Bit().constData());
142
 
 
143
 
    // Write the file
144
 
    archive_write_header(writer, out_entry);
145
 
    CopyArchiveEntry(a, writer);
146
 
 
147
 
    // Have we found a script.ini?
148
 
    const QStringList source_parts = pathname.split('/');
149
 
 
150
 
    if (source_parts.count() == 2 && source_parts[1] == ScriptInfo::kIniFileName) {
151
 
      // Parse it
152
 
      ScriptInfo info;
153
 
      info.InitFromFile(manager_,
154
 
                        destination.section('/', -2, -2),
155
 
                        destination.section('/', 0, -2),
156
 
                        destination);
157
 
 
158
 
      if (info.is_valid()) {
159
 
        info_ << info;
160
 
      }
161
 
    }
162
 
  }
163
 
 
164
 
  archive_entry_free(out_entry);
165
 
  archive_read_finish(a);
166
 
 
167
 
  return !info_.isEmpty();
168
 
#else // HAVE_LIBARCHIVE
169
 
  return false;
170
 
#endif // HAVE_LIBARCHIVE
171
 
}
172
 
 
173
 
bool ScriptArchive::Install() const {
174
 
  // Where should they go?
175
 
  QString destination = Utilities::GetConfigPath(Utilities::Path_Scripts);
176
 
 
177
 
  // Copy each directory
178
 
  foreach (const ScriptInfo& info, info_) {
179
 
    if (!Utilities::CopyRecursive(info.path(), destination))
180
 
      return false;
181
 
  }
182
 
 
183
 
  return true;
184
 
}