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 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 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 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