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