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 
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( "BRAND_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 
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 
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 
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 
251 bool psp::convertPfbToPfa( ::osl::File& rInFile, ::osl::File& rOutFile )
252 {
253     static 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 = ! rInFile.read( buffer, 6, nRead ) && nRead == 6 ? false : true;
270         unsigned int nType = buffer[ 1 ];
271         unsigned int nBytesToRead = buffer[2] | buffer[3] << 8 | buffer[4] << 16 | buffer[5] << 24;
272         if( buffer[0] != 0x80 ) // test for pfb m_agic number
273         {
274             // this migt be a pfa font already
275             sal_uInt64 nWrite = 0;
276             if( ! rInFile.read( buffer+6, 9, nRead ) && nRead == 9 &&
277                 ( ! std::strncmp( (char*)buffer, "%!FontType1-", 12 ) ||
278                   ! std::strncmp( (char*)buffer, "%!PS-AdobeFont-", 15 ) ) )
279             {
280                 if( rOutFile.write( buffer, 15, nWrite ) || nWrite != 15 )
281                     bSuccess = false;
282                 while( bSuccess &&
283                        ! rInFile.read( buffer, sizeof( buffer ), nRead ) &&
284                        nRead != 0 )
285                 {
286                     if( rOutFile.write( buffer, nRead, nWrite ) ||
287                         nWrite != nRead )
288                         bSuccess = false;
289                 }
290                 bEof = true;
291             }
292             else
293                 bSuccess = false;
294         }
295         else if( nType == 1 || nType == 2 )
296         {
297             unsigned char* pBuffer = new unsigned char[ nBytesToRead+1 ];
298 
299             if( ! rInFile.read( pBuffer, nBytesToRead, nRead ) && nRead == nBytesToRead )
300             {
301                 if( nType == 1 )
302                 {
303                     // ascii data, convert dos lineends( \r\n ) and
304                     // m_ac lineends( \r ) to \n
305                     unsigned char * pWriteBuffer = new unsigned char[ nBytesToRead ];
306                     unsigned int nBytesToWrite = 0;
307                     for( unsigned int i = 0; i < nBytesToRead; i++ )
308                     {
309                         if( pBuffer[i] != '\r' )
310                             pWriteBuffer[ nBytesToWrite++ ] = pBuffer[i];
311                         else if( pBuffer[ i+1 ] == '\n' )
312                         {
313                             i++;
314                             pWriteBuffer[ nBytesToWrite++ ] = '\n';
315                         }
316                         else
317                             pWriteBuffer[ nBytesToWrite++ ] = '\n';
318                     }
319                     if( rOutFile.write( pWriteBuffer, nBytesToWrite, nRead ) || nRead != nBytesToWrite )
320                         bSuccess = false;
321 
322                     delete [] pWriteBuffer;
323                 }
324                 else
325                 {
326                     // binary data
327                     unsigned int nBuffer = 0;
328                     for( unsigned int i = 0; i < nBytesToRead && bSuccess; i++ )
329                     {
330                         buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] >> 4 ];
331                         buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] & 15 ];
332                         if( nBuffer >= 80 )
333                         {
334                             buffer[ nBuffer++ ] = '\n';
335                             if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
336                                 bSuccess = false;
337                             nBuffer = 0;
338                         }
339                     }
340                     if( nBuffer > 0 && bSuccess )
341                     {
342                         buffer[ nBuffer++ ] = '\n';
343                         if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
344                             bSuccess = false;
345                     }
346                 }
347             }
348             else
349                 bSuccess = false;
350 
351             delete [] pBuffer;
352         }
353         else if( nType == 3 )
354             bEof = true;
355         else
356             bSuccess = false;
357     }
358 
359     return bSuccess;
360 }
361 
362 void psp::normPath( OString& rPath )
363 {
364     char buf[PATH_MAX];
365 
366     ByteString aPath( rPath );
367 
368     // double slashes and slash at end are probably
369     // removed by realpath anyway, but since this runs
370     // on many different platforms let's play it safe
371     while( aPath.SearchAndReplace( "//", "/" ) != STRING_NOTFOUND )
372         ;
373     if( aPath.Len() > 0 && aPath.GetChar( aPath.Len()-1 ) == '/' )
374         aPath.Erase( aPath.Len()-1 );
375 
376     if( ( aPath.Search( "./" ) != STRING_NOTFOUND ||
377 		  aPath.Search( "~" ) != STRING_NOTFOUND )
378         && realpath( aPath.GetBuffer(), buf ) )
379     {
380         rPath = buf;
381     }
382     else
383     {
384         rPath = aPath;
385     }
386 }
387 
388 void psp::splitPath( OString& rPath, OString& rDir, OString& rBase )
389 {
390     normPath( rPath );
391     sal_Int32 nIndex = rPath.lastIndexOf( '/' );
392     if( nIndex > 0 )
393         rDir = rPath.copy( 0, nIndex );
394     else if( nIndex == 0 ) // root dir
395         rDir = rPath.copy( 0, 1 );
396     if( rPath.getLength() > nIndex+1 )
397         rBase = rPath.copy( nIndex+1 );
398 }
399 
400 
401