Angus Leeming wrote:

> The attached patch simply refactors the name mangling code in
> insetgraphics into a separate function. OK to commit?
> 
> If we're unable to resolve this "long file name causes gs to die"
> problem, then I'd suggest reworking the function to use the file
> name only and a unique counter ID.

This new version backports the name mangling scheme from LyX 1.4 and
then limits the length of the resulting absolute file path to a
maximum of 200 characters. The file name is guaranteed to remain
unique because we use the same counter ID magic that is used in LyX
1.4.

It works perfectly here on a Linux machine with
ESP Ghostscript 7.07.1 (2003-07-12)

I'll try it out on Windows over the w/e.

-- 
Angus
Index: src/insets/insetgraphics.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insetgraphics.C,v
retrieving revision 1.146.2.12
diff -u -p -r1.146.2.12 insetgraphics.C
--- src/insets/insetgraphics.C	4 Jul 2005 11:26:41 -0000	1.146.2.12
+++ src/insets/insetgraphics.C	8 Jul 2005 16:43:12 -0000
@@ -91,6 +91,7 @@ TODO
 #include "BoostFormat.h"
 
 #include <algorithm> // For the std::max
+#include <map>
 
 using std::ostream;
 using std::endl;
@@ -523,6 +524,64 @@ string const InsetGraphics::createLatexO
 }
 
 
+namespace {
+
+// Create a human-readable filename version of the input absolute path.
+// Eg /home/angus/foo\ bar/image.eps -> ID_home_angus_foo_bar_image.eps
+// where ID is a unique integer ID.
+string const mangled_filename(string const & input, int const max_length)
+{
+	// We need to make sure that every FileName instance for a given
+	// filename returns the same mangled name.
+	typedef std::map<string, string> MangledMap;
+	static MangledMap mangledNames;
+	MangledMap::const_iterator const it = mangledNames.find(input);
+	if (it != mangledNames.end())
+		return (*it).second;
+
+	// Now the real work
+	string mname = os::internal_path(input);
+	// Remove the extension.
+	mname = ChangeExtension(input, string());
+	// Replace '/' in the file name with '_'
+	mname = subst(mname, "/", "_");
+	// Replace '.' in the file name with '_'
+	mname = subst(mname, ".", "_");
+	// Replace ' ' in the file name with '_'
+	mname = subst(mname, " ", "_");
+	// Add the extension back on
+	mname = ChangeExtension(mname, GetExtension(input));
+
+#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(_WIN32)
+	// Mangle the drive letter in a Windows-style path.
+	if (mname.size() >= 2 && mname[1] == ':')
+		mname[1] = '_';
+#endif
+
+	// Prepend a counter to the filename. This is necessary to make
+	// the mangled name unique.
+	static int counter = 0;
+	std::ostringstream s;
+	s << counter++ << mname;
+	mname = STRCONV(s.str());
+
+	// If the mangled file name is too long, hack it to fit.
+	// We know we're guaranteed to have a unique file name because
+	// of the counter.
+	if (int(mname.size()) > max_length) {
+		int const half = (max_length / 2) - 2;
+		if (half > 0) {
+			mname = mname.substr(0, half) + "___" +
+				mname.substr(mname.size() - half);
+		}
+	}
+	mangledNames[input] = mname;
+	return mname;
+}
+
+}
+
+
 string const InsetGraphics::prepareFile(Buffer const * buf) const
 {
 	// LaTeX can cope if the graphics file doesn't exist, so just
@@ -619,28 +678,17 @@ string const InsetGraphics::prepareFile(
 		<< "\tthe orig file is: " << orig_file_with_path << endl;
 
 	if (lyxrc.use_tempdir) {
-		string const ext_tmp = GetExtension(orig_file_with_path);
-		// without ext and /
-		temp_file = subst(
-			ChangeExtension(orig_file_with_path, string()), "/", "_");
-		// Replace ' ' in the file name with '_'
-		temp_file = subst(temp_file, " ", "_");
-		// without dots and again with ext
-		temp_file = ChangeExtension(
-			subst(temp_file, ".", "_"), ext_tmp);
-
-#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(_WIN32)
-		// Mangle the drive letter in a Windows-style path.
-		if (temp_file.size() >= 2 && temp_file[1] == ':')
-			temp_file[1] = '_';
-#endif
+		// gs (<= 8.51) appears to crash if the file name
+		// is too long.
+		int const max_filelength = 200 - (int(buf->tmppath.size()) + 1);
+		temp_file = mangled_filename(orig_file_with_path, max_filelength);
 
 		// now we have any_dir_file.ext
 		temp_file = MakeAbsPath(temp_file, buf->tmppath);
 		lyxerr[Debug::GRAPHICS]
 			<< "\tchanged to: " << temp_file << endl;
 
-		// if the file doen't exists, copy it into the tempdir
+		// if the file doen't exist, copy it into the tempdir
 		if (file_has_changed || !IsFileReadable(temp_file)) {
 			bool const success = lyx::copy(orig_file_with_path, temp_file);
 			lyxerr[Debug::GRAPHICS]

Reply via email to