/* * Created on Apr 1, 2008 * Created by Paul Gardner * * Copyright 2008 Vuze, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ package org.gudy.azureus2.platform.macosx; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import org.gudy.azureus2.core3.util.ByteFormatter; import org.gudy.azureus2.core3.util.FileUtil; public class PListEditor { private String plistFile; private boolean found_bom; public PListEditor( String plistFile ) throws IOException { this.plistFile = plistFile; File file = new File( plistFile ); if ( !file.exists()){ throw( new IOException( "plist file '" + file + "' doesn't exist" )); } if ( !file.canWrite()){ throw( new IOException( "plist file '" + file + "' is read only" )); } } public void setFileTypeExtensions( String[] extensions ) throws IOException { StringBuffer value = new StringBuffer(); StringBuffer find = new StringBuffer(); find.append("(?s).*?<key>CFBundleDocumentTypes</key>\\s*<array>.*?<key>CFBundleTypeExtensions</key>\\s*<array>"); for(int i = 0 ; i < extensions.length ; i++) { value.append("\n\t\t\t\t<string>"); value.append(extensions[i]); value.append("</string>"); find.append(".*?"); find.append(extensions[i]); } value.append("\n\t\t\t"); find.append(".*?</array>.*"); String match = "(?s)(<key>CFBundleDocumentTypes</key>\\s*<array>.*?<key>CFBundleTypeExtensions</key>\\s*<array>)(.*?)(</array>)"; setValue(find.toString(), match, value.toString()); } public void setSimpleStringValue( String key, String value) throws IOException { String find = "(?s).*?<key>" + key + "</key>\\s*" + "<string>" + value + "</string>.*"; String match = "(?s)(<key>" + key + "</key>\\s*" + "<string>)(.*?)(</string>)"; setValue(find, match, value); } public void setArrayValues( String key, String valueType, String[] values) throws IOException { StringBuffer value = new StringBuffer(); StringBuffer find = new StringBuffer(); find.append("(?s).*?<key>" + key + "</key>\\s*" + "<array>"); for(int i = 0 ; i < values.length ; i++) { find.append("\\s*<" + valueType + ">" + values[i] + "</" + valueType + ">"); value.append("\n\t\t\t\t<" + valueType + ">"); value.append(values[i]); value.append("</" + valueType + ">"); } find.append("\\s*</array>.*"); value.append("\n\t\t\t"); String match = "(?s)(<key>" + key + "</key>\\s*<array>)(.*?)(</array>)"; setValue(find.toString(),match,value.toString()); } private boolean isValuePresent( String fileContent, String match ) throws IOException { //System.out.println("Searching for:\n" + match); return fileContent.matches(match); } /** * * @param find the regex expression to find if the value is already present * @param match the regex expression that will match for the replace, it needs to capture 3 groups, the 2nd one being replaced by value * @param value the value that replaces the 2nd match group */ private void setValue( String find, String match, String value) throws IOException { String fileContent = getFileContent(); if( !isValuePresent(fileContent,find)) { //System.out.println("Changing " +plistFile); fileContent = fileContent.replaceFirst(match, "$1"+value + "$3"); setFileContent(fileContent); touchFile(); } } private String getFileContent() throws IOException { InputStreamReader reader = null; try{ byte[] file_bytes = FileUtil.readFileAsByteArray( new File( plistFile )); // handle UTF-8 encoded BOM EFBBBF if ( file_bytes.length > 3 && file_bytes[0] == (byte)0xEF && file_bytes[1] == (byte)0xBB && file_bytes[2] == (byte)0xBF ){ found_bom = true; reader = new InputStreamReader( new ByteArrayInputStream( file_bytes, 3, file_bytes.length - 3 )); }else{ found_bom = false; reader = new InputStreamReader( new ByteArrayInputStream( file_bytes )); } //max 32KB int length = 32 * 1024; char[] buffer = new char[length]; int offset = 0; int len = 0; while((len = reader.read(buffer,offset,length-offset)) > 0) { offset += len; } String result = new String(buffer,0,offset); return result; } finally { if(reader != null) { reader.close(); } } //return FileUtil.readFileAsString(new File(plistFile), 64*1024, "UTF-8" ); } private void setFileContent( String fileContent ) throws IOException { File file = new File( plistFile ); File backup_file = new File( plistFile + ".bak" ); if ( file.exists()){ if ( !FileUtil.copyFile( file, backup_file )){ throw( new IOException( "Failed to backup plist file prior to modification" )); } } boolean ok = false; try{ ByteArrayOutputStream baos = new ByteArrayOutputStream( fileContent.length() + 256 ); if ( found_bom ){ // preserve UTF-8 BOM if it was found baos.write( new byte[]{ (byte)0xEF, (byte)0xBB, (byte)0xBF }); } OutputStreamWriter osw = new OutputStreamWriter( baos ); osw.write( fileContent ); osw.close(); FileOutputStream out = null; try{ out = new FileOutputStream( plistFile ); out.write( baos.toByteArray() ); }finally{ if( out != null ){ out.close(); ok = true; } } }finally{ if ( ok ){ backup_file.delete(); }else{ if ( backup_file.exists()){ File bork_file = new File( plistFile + ".bad" ); file.renameTo( bork_file ); file.delete(); backup_file.renameTo( file ); } } } } public void touchFile() { File file = new File( plistFile ); for(int i = 0 ; i <= 2 ; i++) { if(file != null) { String command[] = new String[] { "touch", file.getAbsolutePath() }; try{ Runtime.getRuntime().exec(command); } catch(Exception e) { e.printStackTrace(); } } file = file.getParentFile(); } } public static void main(String args[]) { try{ PListEditor editor = new PListEditor("/Applications/Vuze.app/Contents/Info.plist"); editor.setFileTypeExtensions(new String[] {"torrent","tor","vuze","vuz"}); editor.setSimpleStringValue("CFBundleName", "Vuze"); editor.setSimpleStringValue("CFBundleTypeName", "Vuze Download"); editor.setSimpleStringValue("CFBundleGetInfoString","Vuze"); editor.setArrayValues("CFBundleURLSchemes", "string", new String[] {"magnet","dht"}); }catch( Throwable e ){ e.printStackTrace(); } } }