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