]> git.lyx.org Git - lyx.git/blob - src/support/filename.C
* src/text2.C: deleteEmptyParagraphMechanism(): fix a crash in
[lyx.git] / src / support / filename.C
1 /**
2  * \file filename.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "support/filename.h"
14 #include "support/filetools.h"
15 #include "support/lstrings.h"
16 #include "support/os.h"
17 #include "support/qstring_helpers.h"
18
19 #include <QFile>
20
21 #include <boost/assert.hpp>
22
23 #include <map>
24 #include <sstream>
25 #include <algorithm>
26
27
28 using std::map;
29 using std::string;
30
31
32 namespace lyx {
33 namespace support {
34
35
36 FileName::FileName()
37 {}
38
39
40 FileName::~FileName()
41 {}
42
43
44 FileName::FileName(string const & abs_filename)
45         : name_(abs_filename)
46 {
47         BOOST_ASSERT(empty() || absolutePath(name_));
48         BOOST_ASSERT(!contains(name_, '\\'));
49 }
50
51
52 void FileName::set(string const & name)
53 {
54         name_ = name;
55         BOOST_ASSERT(absolutePath(name_));
56         BOOST_ASSERT(!contains(name_, '\\'));
57 }
58
59
60 void FileName::erase()
61 {
62         name_.erase();
63 }
64
65
66 string const FileName::toFilesystemEncoding() const
67 {
68         QByteArray const encoded = QFile::encodeName(toqstr(name_));
69         return string(encoded.begin(), encoded.end());
70 }
71
72
73 FileName const FileName::fromFilesystemEncoding(string const & name)
74 {
75         QByteArray const encoded(name.c_str(), name.length());
76         return FileName(fromqstr(QFile::decodeName(encoded)));
77 }
78
79
80 bool operator==(FileName const & lhs, FileName const & rhs)
81 {
82         return lhs.absFilename() == rhs.absFilename();
83 }
84
85
86 bool operator!=(FileName const & lhs, FileName const & rhs)
87 {
88         return lhs.absFilename() != rhs.absFilename();
89 }
90
91
92 bool operator<(FileName const & lhs, FileName const & rhs)
93 {
94         return lhs.absFilename() < rhs.absFilename();
95 }
96
97
98 bool operator>(FileName const & lhs, FileName const & rhs)
99 {
100         return lhs.absFilename() > rhs.absFilename();
101 }
102
103
104 std::ostream & operator<<(std::ostream & os, FileName const & filename)
105 {
106         return os << filename.absFilename();
107 }
108
109
110 DocFileName::DocFileName()
111         : save_abs_path_(true)
112 {}
113
114
115 DocFileName::DocFileName(string const & abs_filename, bool save_abs)
116         : FileName(abs_filename), save_abs_path_(save_abs), zipped_valid_(false)
117 {}
118
119
120 DocFileName::DocFileName(FileName const & abs_filename, bool save_abs)
121         : FileName(abs_filename), save_abs_path_(save_abs), zipped_valid_(false)
122 {}
123
124
125 void DocFileName::set(string const & name, string const & buffer_path)
126 {
127         save_abs_path_ = absolutePath(name);
128         name_ = save_abs_path_ ? name : makeAbsPath(name, buffer_path).absFilename();
129         zipped_valid_ = false;
130 }
131
132
133 void DocFileName::erase()
134 {
135         name_.erase();
136         zipped_valid_ = false;
137 }
138
139
140 string const DocFileName::relFilename(string const & path) const
141 {
142         return makeRelPath(name_, path);
143 }
144
145
146 string const DocFileName::outputFilename(string const & path) const
147 {
148         return save_abs_path_ ? name_ : makeRelPath(name_, path);
149 }
150
151
152 string const DocFileName::mangledFilename(std::string const & dir) const
153 {
154         // We need to make sure that every DocFileName instance for a given
155         // filename returns the same mangled name.
156         typedef map<string, string> MangledMap;
157         static MangledMap mangledNames;
158         MangledMap::const_iterator const it = mangledNames.find(name_);
159         if (it != mangledNames.end())
160                 return (*it).second;
161
162         // Now the real work
163         string mname = os::internal_path(name_);
164         // Remove the extension.
165         mname = changeExtension(name_, string());
166         // Replace '/' in the file name with '_'
167         mname = subst(mname, "/", "_");
168         // Replace '.' in the file name with '_'
169         mname = subst(mname, ".", "_");
170         // Replace ' ' in the file name with '_'
171         mname = subst(mname, " ", "_");
172         // Replace ':' in the file name with '_'
173         mname = subst(mname, ":", "_");
174         // Add the extension back on
175         mname = changeExtension(mname, getExtension(name_));
176
177         // Prepend a counter to the filename. This is necessary to make
178         // the mangled name unique.
179         static int counter = 0;
180         std::ostringstream s;
181         s << counter++ << mname;
182         mname = s.str();
183
184         // MiKTeX's YAP (version 2.4.1803) crashes if the file name
185         // is longer than about 160 characters. MiKTeX's pdflatex
186         // is even pickier. A maximum length of 100 has been proven to work.
187         // If dir.size() > max length, all bets are off for YAP. We truncate
188         // the filename nevertheless, keeping a minimum of 10 chars.
189
190         string::size_type max_length = std::max(100 - ((int)dir.size() + 1), 10);
191
192         // If the mangled file name is too long, hack it to fit.
193         // We know we're guaranteed to have a unique file name because
194         // of the counter.
195         if (mname.size() > max_length) {
196                 int const half = (int(max_length) / 2) - 2;
197                 if (half > 0) {
198                         mname = mname.substr(0, half) + "___" +
199                                 mname.substr(mname.size() - half);
200                 }
201         }
202
203         mangledNames[name_] = mname;
204         return mname;
205 }
206
207
208 bool DocFileName::isZipped() const
209 {
210         if (!zipped_valid_) {
211                 zipped_ = zippedFile(*this);
212                 zipped_valid_ = true;
213         }
214         return zipped_;
215 }
216
217
218 string const DocFileName::unzippedFilename() const
219 {
220         return unzippedFileName(name_);
221 }
222
223
224 bool operator==(DocFileName const & lhs, DocFileName const & rhs)
225 {
226         return lhs.absFilename() == rhs.absFilename() &&
227                 lhs.saveAbsPath() == rhs.saveAbsPath();
228 }
229
230
231 bool operator!=(DocFileName const & lhs, DocFileName const & rhs)
232 {
233         return !(lhs == rhs);
234 }
235
236 } // namespace support
237 } // namespace lyx