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