1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26
27 #include <cstring>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <limits.h>
31
32 #include "vcl/helper.hxx"
33 #include "vcl/ppdparser.hxx"
34 #include "tools/string.hxx"
35 #include "tools/urlobj.hxx"
36 #include "osl/file.hxx"
37 #include "osl/process.h"
38 #include "rtl/bootstrap.hxx"
39
40 using namespace rtl;
41
42 namespace psp {
43
getOfficePath(enum whichOfficePath ePath)44 OUString getOfficePath( enum whichOfficePath ePath )
45 {
46 static OUString aNetPath;
47 static OUString aUserPath;
48 static OUString aConfigPath;
49 static OUString aEmpty;
50 static bool bOnce = false;
51
52 if( ! bOnce )
53 {
54 bOnce = true;
55 OUString aIni;
56 Bootstrap::get( OUString( RTL_CONSTASCII_USTRINGPARAM( "OOO_BASE_DIR" ) ), aIni );
57 aIni += OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
58 Bootstrap aBootstrap( aIni );
59 aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "CustomDataUrl" ) ), aConfigPath );
60 aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseInstallation" ) ), aNetPath );
61 aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
62 OUString aUPath = aUserPath;
63
64 if( ! aConfigPath.compareToAscii( "file://", 7 ) )
65 {
66 OUString aSysPath;
67 if( osl_getSystemPathFromFileURL( aConfigPath.pData, &aSysPath.pData ) == osl_File_E_None )
68 aConfigPath = aSysPath;
69 }
70 if( ! aNetPath.compareToAscii( "file://", 7 ) )
71 {
72 OUString aSysPath;
73 if( osl_getSystemPathFromFileURL( aNetPath.pData, &aSysPath.pData ) == osl_File_E_None )
74 aNetPath = aSysPath;
75 }
76 if( ! aUserPath.compareToAscii( "file://", 7 ) )
77 {
78 OUString aSysPath;
79 if( osl_getSystemPathFromFileURL( aUserPath.pData, &aSysPath.pData ) == osl_File_E_None )
80 aUserPath = aSysPath;
81 }
82 // ensure user path exists
83 aUPath += OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/psprint" ) );
84 #if OSL_DEBUG_LEVEL > 1
85 oslFileError eErr =
86 #endif
87 osl_createDirectoryPath( aUPath.pData, NULL, NULL );
88 #if OSL_DEBUG_LEVEL > 1
89 fprintf( stderr, "try to create \"%s\" = %d\n", OUStringToOString( aUPath, RTL_TEXTENCODING_UTF8 ).getStr(), eErr );
90 #endif
91 }
92
93 switch( ePath )
94 {
95 case ConfigPath: return aConfigPath;
96 case NetPath: return aNetPath;
97 case UserPath: return aUserPath;
98 }
99 return aEmpty;
100 }
101
getEnvironmentPath(const char * pKey)102 static OString getEnvironmentPath( const char* pKey )
103 {
104 OString aPath;
105
106 const char* pValue = getenv( pKey );
107 if( pValue && *pValue )
108 {
109 aPath = OString( pValue );
110 }
111 return aPath;
112 }
113
114 } // namespace psp
115
getPrinterPathList(std::list<OUString> & rPathList,const char * pSubDir)116 void psp::getPrinterPathList( std::list< OUString >& rPathList, const char* pSubDir )
117 {
118 rPathList.clear();
119 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
120
121 OUStringBuffer aPathBuffer( 256 );
122
123 // append net path
124 aPathBuffer.append( getOfficePath( psp::NetPath ) );
125 if( aPathBuffer.getLength() )
126 {
127 aPathBuffer.appendAscii( "/share/psprint" );
128 if( pSubDir )
129 {
130 aPathBuffer.append( sal_Unicode('/') );
131 aPathBuffer.appendAscii( pSubDir );
132 }
133 rPathList.push_back( aPathBuffer.makeStringAndClear() );
134 }
135 // append user path
136 aPathBuffer.append( getOfficePath( psp::UserPath ) );
137 if( aPathBuffer.getLength() )
138 {
139 aPathBuffer.appendAscii( "/user/psprint" );
140 if( pSubDir )
141 {
142 aPathBuffer.append( sal_Unicode('/') );
143 aPathBuffer.appendAscii( pSubDir );
144 }
145 rPathList.push_back( aPathBuffer.makeStringAndClear() );
146 }
147
148 OString aPath( getEnvironmentPath("SAL_PSPRINT") );
149 sal_Int32 nIndex = 0;
150 do
151 {
152 OString aDir( aPath.getToken( 0, ':', nIndex ) );
153 if( ! aDir.getLength() )
154 continue;
155
156 if( pSubDir )
157 {
158 aDir += "/";
159 aDir += pSubDir;
160 }
161 struct stat aStat;
162 if( stat( aDir.getStr(), &aStat ) || ! S_ISDIR( aStat.st_mode ) )
163 continue;
164
165 rPathList.push_back( OStringToOUString( aDir, aEncoding ) );
166 } while( nIndex != -1 );
167
168 #ifdef SYSTEM_PPD_DIR
169 if( pSubDir && rtl_str_compare( pSubDir, PRINTER_PPDDIR ) == 0 )
170 {
171 rPathList.push_back( rtl::OStringToOUString( rtl::OString( SYSTEM_PPD_DIR ), RTL_TEXTENCODING_UTF8 ) );
172 }
173 #endif
174
175 if( rPathList.empty() )
176 {
177 // last resort: next to program file (mainly for setup)
178 OUString aExe;
179 if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
180 {
181 INetURLObject aDir( aExe );
182 aDir.removeSegment();
183 aExe = aDir.GetMainURL( INetURLObject::NO_DECODE );
184 OUString aSysPath;
185 if( osl_getSystemPathFromFileURL( aExe.pData, &aSysPath.pData ) == osl_File_E_None )
186 {
187 rPathList.push_back( aSysPath );
188 }
189 }
190 }
191 }
192
getFontPath()193 OUString psp::getFontPath()
194 {
195 static OUString aPath;
196
197 if( ! aPath.getLength() )
198 {
199 OUStringBuffer aPathBuffer( 512 );
200
201 OUString aConfigPath( getOfficePath( psp::ConfigPath ) );
202 OUString aNetPath( getOfficePath( psp::NetPath ) );
203 OUString aUserPath( getOfficePath( psp::UserPath ) );
204 if( aConfigPath.getLength() )
205 {
206 // #i53530# Path from CustomDataUrl will completely
207 // replace net and user paths if the path exists
208 aPathBuffer.append(aConfigPath);
209 aPathBuffer.appendAscii("/share/fonts");
210 // check existance of config path
211 struct stat aStat;
212 if( 0 != stat( OUStringToOString( aPathBuffer.makeStringAndClear(), osl_getThreadTextEncoding() ).getStr(), &aStat )
213 || ! S_ISDIR( aStat.st_mode ) )
214 aConfigPath = OUString();
215 else
216 {
217 aPathBuffer.append(aConfigPath);
218 aPathBuffer.appendAscii("/share/fonts");
219 }
220 }
221 if( aConfigPath.getLength() == 0 )
222 {
223 if( aNetPath.getLength() )
224 {
225 aPathBuffer.append( aNetPath );
226 aPathBuffer.appendAscii( "/share/fonts/truetype;");
227 aPathBuffer.append( aNetPath );
228 aPathBuffer.appendAscii( "/share/fonts/type1;" );
229 }
230 if( aUserPath.getLength() )
231 {
232 aPathBuffer.append( aUserPath );
233 aPathBuffer.appendAscii( "/user/fonts" );
234 }
235 }
236 OString aEnvPath( getEnvironmentPath( "SAL_FONTPATH_PRIVATE" ) );
237 if( aEnvPath.getLength() )
238 {
239 aPathBuffer.append( sal_Unicode(';') );
240 aPathBuffer.append( OStringToOUString( aEnvPath, osl_getThreadTextEncoding() ) );
241 }
242
243 aPath = aPathBuffer.makeStringAndClear();
244 #if OSL_DEBUG_LEVEL > 1
245 fprintf( stderr, "initializing font path to \"%s\"\n", OUStringToOString( aPath, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
246 #endif
247 }
248 return aPath;
249 }
250
convertPfbToPfa(::osl::File & rInFile,::osl::File & rOutFile)251 bool psp::convertPfbToPfa( ::osl::File& rInFile, ::osl::File& rOutFile )
252 {
253 static const unsigned char hexDigits[] =
254 {
255 '0', '1', '2', '3', '4', '5', '6', '7',
256 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
257 };
258
259 bool bSuccess = true;
260 bool bEof = false;
261 unsigned char buffer[256];
262 sal_uInt64 nRead;
263 sal_uInt64 nOrgPos = 0;
264 rInFile.getPos( nOrgPos );
265
266 while( bSuccess && ! bEof )
267 {
268 // read leading bytes
269 bEof = ((0 != rInFile.read( buffer, 6, nRead)) || (nRead != 6));
270 if( bEof )
271 break;
272 unsigned int nType = buffer[ 1 ];
273 unsigned int nBytesToRead = buffer[2] | buffer[3] << 8 | buffer[4] << 16 | buffer[5] << 24;
274 if( buffer[0] != 0x80 ) // test for pfb magic number
275 {
276 // this migt be a pfa font already
277 sal_uInt64 nWrite = 0;
278 if( ! rInFile.read( buffer+6, 9, nRead ) && nRead == 9 &&
279 ( ! std::strncmp( (char*)buffer, "%!FontType1-", 12 ) ||
280 ! std::strncmp( (char*)buffer, "%!PS-AdobeFont-", 15 ) ) )
281 {
282 if( rOutFile.write( buffer, 15, nWrite ) || nWrite != 15 )
283 bSuccess = false;
284 while( bSuccess &&
285 ! rInFile.read( buffer, sizeof( buffer ), nRead ) &&
286 nRead != 0 )
287 {
288 if( rOutFile.write( buffer, nRead, nWrite ) ||
289 nWrite != nRead )
290 bSuccess = false;
291 }
292 bEof = true;
293 }
294 else
295 bSuccess = false;
296 }
297 else if( nType == 1 || nType == 2 )
298 {
299 unsigned char* pBuffer = new unsigned char[ nBytesToRead+1 ];
300
301 if( ! rInFile.read( pBuffer, nBytesToRead, nRead ) && nRead == nBytesToRead )
302 {
303 if( nType == 1 )
304 {
305 // ascii data, convert dos lineends( \r\n ) and
306 // m_ac lineends( \r ) to \n
307 unsigned char * pWriteBuffer = new unsigned char[ nBytesToRead ];
308 unsigned int nBytesToWrite = 0;
309 for( unsigned int i = 0; i < nBytesToRead; i++ )
310 {
311 if( pBuffer[i] != '\r' )
312 pWriteBuffer[ nBytesToWrite++ ] = pBuffer[i];
313 else if( pBuffer[ i+1 ] == '\n' )
314 {
315 i++;
316 pWriteBuffer[ nBytesToWrite++ ] = '\n';
317 }
318 else
319 pWriteBuffer[ nBytesToWrite++ ] = '\n';
320 }
321 if( rOutFile.write( pWriteBuffer, nBytesToWrite, nRead ) || nRead != nBytesToWrite )
322 bSuccess = false;
323
324 delete [] pWriteBuffer;
325 }
326 else
327 {
328 // binary data
329 unsigned int nBuffer = 0;
330 for( unsigned int i = 0; i < nBytesToRead && bSuccess; i++ )
331 {
332 buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] >> 4 ];
333 buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] & 15 ];
334 if( nBuffer >= 80 )
335 {
336 buffer[ nBuffer++ ] = '\n';
337 if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
338 bSuccess = false;
339 nBuffer = 0;
340 }
341 }
342 if( nBuffer > 0 && bSuccess )
343 {
344 buffer[ nBuffer++ ] = '\n';
345 if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
346 bSuccess = false;
347 }
348 }
349 }
350 else
351 bSuccess = false;
352
353 delete [] pBuffer;
354 }
355 else if( nType == 3 )
356 bEof = true;
357 else
358 bSuccess = false;
359 }
360
361 return bSuccess;
362 }
363
normPath(OString & rPath)364 void psp::normPath( OString& rPath )
365 {
366 char buf[PATH_MAX];
367
368 ByteString aPath( rPath );
369
370 // double slashes and slash at end are probably
371 // removed by realpath anyway, but since this runs
372 // on many different platforms let's play it safe
373 while( aPath.SearchAndReplace( "//", "/" ) != STRING_NOTFOUND )
374 ;
375 if( aPath.Len() > 0 && aPath.GetChar( aPath.Len()-1 ) == '/' )
376 aPath.Erase( aPath.Len()-1 );
377
378 if( ( aPath.Search( "./" ) != STRING_NOTFOUND ||
379 aPath.Search( "~" ) != STRING_NOTFOUND )
380 && realpath( aPath.GetBuffer(), buf ) )
381 {
382 rPath = buf;
383 }
384 else
385 {
386 rPath = aPath;
387 }
388 }
389
splitPath(OString & rPath,OString & rDir,OString & rBase)390 void psp::splitPath( OString& rPath, OString& rDir, OString& rBase )
391 {
392 normPath( rPath );
393 sal_Int32 nIndex = rPath.lastIndexOf( '/' );
394 if( nIndex > 0 )
395 rDir = rPath.copy( 0, nIndex );
396 else if( nIndex == 0 ) // root dir
397 rDir = rPath.copy( 0, 1 );
398 if( rPath.getLength() > nIndex+1 )
399 rBase = rPath.copy( nIndex+1 );
400 }
401
402
403