resource_internal.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "resource_internal.hpp"
27 #include "casadi_misc.hpp"
28 #include "archiver_impl.hpp"
29 
30 #include "filesystem_impl.hpp"
31 
32 
33 namespace casadi {
34 
35 
37  serialize_mode_ = "link";
38 }
39 
40 DirResource::DirResource(const std::string& path)
41  : ResourceInternal(),
42  path_(path) {
43  path_ = path;
44 }
45 
46 void DirResource::disp(std::ostream& stream, bool more) const {
47  stream << "DirResource(\"" << path_ << "\")";
48 }
49 
51 }
52 
53 void ResourceInternal::change_option(const std::string& option_name,
54  const GenericType& option_value) {
55  if (option_name=="serialize_mode") {
56  serialize_mode_ = option_value.to_string();
57  casadi_assert(serialize_mode_=="embed" || serialize_mode_=="link",
58  "Invalid serialization mode: " + serialize_mode_ + ". Pick 'link' or 'embed'.");
59  } else {
60  casadi_error("Option '" + option_name + "' does not exist");
61  }
62 }
63 
65  casadi_assert(Filesystem::is_enabled(),
66  "Unzipping '" + path_ + "' requires advanced filesystem access. "
67  "Compile CasADi with WITH_GHC_FILESYSTEM=ON.\n"
68  "Alternatively, manually unzip it into a direcory, "
69  "and pass this directory name instead of the zip file name.");
70 
71  // Extract filename part of path
72  std::string zip_file = Filesystem::filename(path_);
73 
74  // Resolve absolute path since cwd may be changed by the user
75  lock_file_ = Filesystem::absolute(temporary_file(zip_file + ".", ".lock"));
76  dir_ = lock_file_.substr(0, lock_file_.size()-5) + ".unzipped";
77 
78  casadi_assert(Archiver::has_plugin("libzip"),
79  "Unzipping '" + path_ + "' requires libzip. Compile CasADi with WITH_LIBZIP=ON.\n"
80  "Alternatively, manually unzip it into a direcory, "
81  "and pass this directory name instead of the zip file name.");
82 
83 
84  Archiver::getPlugin("libzip").exposed.unpack(path_, dir_);
85 }
86 
88  std::string zip_file = "zip";
89  lock_file_ = Filesystem::absolute(temporary_file(zip_file + ".", ".lock"));
90  dir_ = lock_file_.substr(0, lock_file_.size()-5) + ".unzipped";
91  casadi_assert(Archiver::has_plugin("libzip"),
92  "Unzipping stream requires libzip. Compile CasADi with WITH_LIBZIP=ON.\n"
93  "Alternatively, save with serialize option set to link. ");
94 
95  Archiver::getPlugin("libzip").exposed.unpack_from_stringstream(blob_, dir_);
96  // rewind
97  blob_.clear();
98  blob_.seekg(0, std::ios::beg);
99 }
100 
101 ZipResource::ZipResource(const std::string& path)
102  : ResourceInternal() {
103  path_ = path;
104  unpack();
105 }
106 
107 ZipMemResource::ZipMemResource(const std::istream& src)
108  : ResourceInternal() {
109  blob_ << src.rdbuf();
110  unpack();
111 }
112 
113 void ZipResource::disp(std::ostream& stream, bool more) const {
114  stream << "ZipResource(\"" << path_ << "\") -> \"" << dir_ << "\"";
115 }
116 
117 void ZipMemResource::disp(std::ostream& stream, bool more) const {
118  stream << "ZipMemResource(blob) -> \"" << dir_ << "\"";
119 }
120 
122  try {
123  casadi_assert_dev(Filesystem::remove_all(dir_));
124  } catch (...) {
125  casadi_warning("Error: Cannot remove temporary directory: " + dir_);
126  }
127  try {
128  casadi_assert_dev(Filesystem::remove(lock_file_));
129  } catch (...) {
130  casadi_warning("Error: Cannot remove lock file: " + lock_file_);
131  }
132 }
133 
135  try {
136  casadi_assert_dev(Filesystem::remove_all(dir_));
137  } catch (...) {
138  casadi_warning("Error: Cannot remove temporary directory: " + dir_);
139  }
140  try {
141  casadi_assert_dev(Filesystem::remove(lock_file_));
142  } catch (...) {
143  casadi_warning("Error: Cannot remove lock file: " + lock_file_);
144  }
145 }
146 
148  s.version("ResourceInternal", 1);
149  serialize_type(s);
150  serialize_body(s);
151 }
152 
154  s.pack("ResourceInternal::type", class_name());
155 }
156 
158  s.pack("ResourceInternal::serialize_mode", serialize_mode_);
159 }
160 
162  s.unpack("ResourceInternal::serialize_mode", serialize_mode_);
163  serialize_mode_ = "link";
164 }
165 
167  s.version("ResourceInternal", 1);
168  std::string class_name;
169  s.unpack("ResourceInternal::type", class_name);
170  if (class_name=="DirResource") {
171  return DirResource::deserialize(s);
172  } else if (class_name=="ZipResource") {
173  return ZipResource::deserialize(s);
174  } else if (class_name=="ZipMemResource") {
175  return ZipMemResource::deserialize(s);
176  } else {
177  casadi_error("Cannot deserialize type '" + class_name + "'");
178  }
179 }
180 
182  ZipResource* ret = new ZipResource(s);
183  return ret;
184 }
185 
187 ZipMemResource* ret = new ZipMemResource(s);
188  return ret;
189 }
190 
192  DirResource* ret = new DirResource(s);
193  return ret;
194 }
195 
197  s.version("ZipResource", 1);
198  s.unpack("ZipResource::path", path_);
199  unpack();
200 }
201 
203 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
204  std::lock_guard<std::mutex> lock(mutex_blob_);
205 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
206  s.version("ZipMemResource", 1);
207  s.unpack("ZipMemResource::blob", blob_);
208  unpack();
209 }
210 
212  s.version("DirResource", 1);
213  s.unpack("DirResource::path", path_);
214 }
215 
217  if (serialize_mode_=="embed") {
218  // Decay into ZipMemResource
219  std::string class_name = "ZipMemResource";
220  s.pack("ResourceInternal::type", class_name);
221  } else if (serialize_mode_=="link") {
222  std::string class_name = "ZipResource";
223  s.pack("ResourceInternal::type", class_name);
224  } else {
225  casadi_error("Unknown serialization mode: '" + serialize_mode_+ "'.");
226  }
227 }
228 
230  if (serialize_mode_=="embed") {
231  // Decay into ZipMemResource
232  std::string class_name = "ZipMemResource";
233  s.pack("ResourceInternal::type", class_name);
234  } else if (serialize_mode_=="link") {
235  std::string class_name = "DirResource";
236  s.pack("ResourceInternal::type", class_name);
237  } else {
238  casadi_error("Unknown serialization mode: " + serialize_mode_);
239  }
240 }
241 
242 
245  s.version("ZipResource", 1);
246  if (serialize_mode_=="embed") {
247  // Decay into ZipMemResource
248  auto binary_ptr = Filesystem::ifstream_ptr(path_, std::ios_base::binary, false);
249  casadi_assert(binary_ptr,
250  "Could not open zip file '" + path_ + "'.");
251  s.pack("ZipMemResource::blob", *binary_ptr);
252  } else {
253  s.pack("ZipResource::path", path_);
254  }
255 }
256 
259  s.version("DirResource", 1);
260  if (serialize_mode_=="embed") {
261  // Decay into ZipMemResource
262  std::stringstream ss;
263  Archiver::getPlugin("libzip").exposed.pack_to_stream(path_, ss);
264  ss.clear();
265  ss.seekg(0, std::ios::beg);
266  s.pack("ZipMemResource::blob", ss);
267  } else {
268  s.pack("DirResource::path", path_);
269  }
270 }
271 
272 
273 
275 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
276  std::lock_guard<std::mutex> lock(mutex_blob_);
277 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
279  s.version("ZipMemResource", 1);
280  s.pack("ZipMemResource::blob", blob_);
281 
282  // rewind
283  blob_.clear();
284  blob_.seekg(0, std::ios::beg);
285 }
286 
287 
288 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void serialize_type(SerializingStream &s) const override
std::string class_name() const override
Get type name.
DirResource(const std::string &path)
Initialize with a path.
void serialize_body(SerializingStream &s) const override
const std::string & path() const override
Get path for a consumer.
void disp(std::ostream &stream, bool more) const override
Print description.
static ResourceInternal * deserialize(DeserializingStream &s)
static casadi_int remove_all(const std::string &path)
Definition: filesystem.cpp:48
static std::string absolute(const std::string &path)
Definition: filesystem.cpp:78
static std::string filename(const std::string &path)
Definition: filesystem.cpp:73
static bool is_enabled()
Definition: filesystem.cpp:83
static std::unique_ptr< std::istream > ifstream_ptr(const std::string &path, std::ios_base::openmode mode=std::ios_base::in, bool fail=true)
Definition: filesystem.cpp:135
static bool remove(const std::string &path)
Definition: filesystem.cpp:43
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
std::string to_string() const
Convert to a type.
static bool has_plugin(const std::string &pname, bool verbose=false)
Check if a plugin is available or can be loaded.
static Plugin & getPlugin(const std::string &pname)
Load and get the creator function.
RAII class base for reading from resources.
ResourceInternal()
Initialize with a path.
void serialize(SerializingStream &s) const
virtual void serialize_body(SerializingStream &s) const
void change_option(const std::string &option_name, const GenericType &option_value)
virtual void serialize_type(SerializingStream &s) const
static ResourceInternal * deserialize(DeserializingStream &s)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
virtual std::string class_name() const =0
Readable name of the internal class.
RAII class for reading from a zip held in memory.
void serialize_body(SerializingStream &s) const override
ZipMemResource(const std::istream &src)
void disp(std::ostream &stream, bool more) const override
Print description.
static ResourceInternal * deserialize(DeserializingStream &s)
RAII class for reading from a zip file.
void disp(std::ostream &stream, bool more) const override
Print description.
static ResourceInternal * deserialize(DeserializingStream &s)
void serialize_body(SerializingStream &s) const override
void serialize_type(SerializingStream &s) const override
Potentially decay into ZipMemResource.
const std::string & path() const override
Get path for a consumer.
ZipResource(const std::string &path)
Initialize with a path.
std::string class_name() const override
Get type name.
The casadi namespace.
Definition: archiver.cpp:28
std::string temporary_file(const std::string &prefix, const std::string &suffix)
std::vector< casadi_int > path(const std::vector< casadi_int > &map, casadi_int i_start)