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