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