Another bnd code refresh

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1360983 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/bnd/build/model/BndEditModel.java b/bundleplugin/src/main/java/aQute/bnd/build/model/BndEditModel.java
index 4450c39..d11fbc6 100644
--- a/bundleplugin/src/main/java/aQute/bnd/build/model/BndEditModel.java
+++ b/bundleplugin/src/main/java/aQute/bnd/build/model/BndEditModel.java
@@ -5,13 +5,15 @@
 import java.util.*;
 import java.util.Map.Entry;
 
+import org.osgi.resource.Requirement;
+
 import aQute.bnd.build.model.clauses.*;
 import aQute.bnd.build.model.conversions.*;
-import aQute.lib.osgi.*;
+import aQute.lib.osgi.Constants;
 import aQute.lib.properties.*;
 import aQute.libg.header.*;
 import aQute.libg.tuple.*;
-import aQute.libg.version.*;
+import aQute.libg.version.Version;
 
 /**
  * A model for a Bnd file. In the first iteration, use a simple Properties
@@ -34,16 +36,12 @@
 			aQute.lib.osgi.Constants.SERVICE_COMPONENT, aQute.lib.osgi.Constants.CLASSPATH,
 			aQute.lib.osgi.Constants.BUILDPATH, aQute.lib.osgi.Constants.BUILDPACKAGES,
 			aQute.lib.osgi.Constants.RUNBUNDLES, aQute.lib.osgi.Constants.RUNPROPERTIES, aQute.lib.osgi.Constants.SUB,
-			// BndConstants.RUNFRAMEWORK,
+			aQute.lib.osgi.Constants.RUNFRAMEWORK,
 			aQute.lib.osgi.Constants.RUNVM,
 			// BndConstants.RUNVMARGS,
 			// BndConstants.TESTSUITES,
 			aQute.lib.osgi.Constants.TESTCASES, aQute.lib.osgi.Constants.PLUGIN, aQute.lib.osgi.Constants.PLUGINPATH,
-			aQute.lib.osgi.Constants.RUNREPOS,
-																								// BndConstants.RUNREQUIRE,
-																								// BndConstants.RUNEE,
-																								// BndConstants.RESOLVE_MODE
-																								};
+			aQute.lib.osgi.Constants.RUNREPOS, aQute.lib.osgi.Constants.RUNREQUIRES, aQute.lib.osgi.Constants.RUNEE};
 
 	public static final String										BUNDLE_VERSION_MACRO		= "${"
 																										+ Constants.BUNDLE_VERSION
@@ -136,27 +134,10 @@
 																										});
 
 	protected Converter<Map<String,String>,String>					propertiesConverter			= new PropertiesConverter();
+	
+	protected Converter<List<Requirement>,String>					requirementListConverter	= new RequirementListConverter();
+	protected Converter<EE,String>									eeConverter					= new EEConverter();
 
-	// Converter<List<Requirement>, String> requirementListConverter =
-	// SimpleListConverter.create(new Converter<Requirement, String>() {
-	// public Requirement convert(String input) throws IllegalArgumentException
-	// {
-	// int index = input.indexOf(":");
-	// if (index < 0)
-	// throw new IllegalArgumentException("Invalid format for OBR requirement");
-	//
-	// String name = input.substring(0, index);
-	// String filter = input.substring(index + 1);
-	//
-	// return new Requirement(name, filter);
-	// }
-	// });
-	// Converter<EE, String> eeConverter = new Converter<EE, String>() {
-	// public EE convert(String input) throws IllegalArgumentException {
-	// return EE.parse(input);
-	// }
-	// };
-	//
 	// Converter<ResolveMode, String> resolveModeConverter =
 	// EnumConverter.create(ResolveMode.class, ResolveMode.manual);
 
@@ -176,21 +157,13 @@
 																										LIST_SEPARATOR,
 																										new PropertiesEntryFormatter(),
 																										null);
-	// Converter<String, Collection<? extends Requirement>>
-	// requirementListFormatter = new
-	// CollectionFormatter<Requirement>(LIST_SEPARATOR, new Converter<String,
-	// Requirement>() {
-	// public String convert(Requirement input) throws IllegalArgumentException
-	// {
-	// return new
-	// StringBuilder().append(input.getName()).append(':').append(input.getFilter()).toString();
-	// }
-	// }, null);
-	// Converter<String, EE> eeFormatter = new Converter<String, EE>() {
-	// public String convert(EE input) throws IllegalArgumentException {
-	// return input != null ? input.getEEName() : null;
-	// }
-	// };
+	
+	protected Converter<String,Collection< ? extends Requirement>>	requirementListFormatter	= new CollectionFormatter<Requirement>(
+																										LIST_SEPARATOR,
+																										new RequirementFormatter(),
+																										null);
+
+	protected Converter<String,EE>									eeFormatter					= new EEFormatter();
 	Converter<String,Collection< ? extends String>>					runReposFormatter			= new CollectionFormatter<String>(
 																										LIST_SEPARATOR,
 																										aQute.lib.osgi.Constants.EMPTY_HEADER);
@@ -214,7 +187,7 @@
 		converters.put(Constants.EXPORT_PACKAGE, exportPackageConverter);
 		converters.put(aQute.lib.osgi.Constants.SERVICE_COMPONENT, serviceComponentConverter);
 		converters.put(Constants.IMPORT_PACKAGE, importPatternConverter);
-		// converters.put(BndConstants.RUNFRAMEWORK, stringConverter);
+		converters.put(aQute.lib.osgi.Constants.RUNFRAMEWORK, stringConverter);
 		converters.put(aQute.lib.osgi.Constants.SUB, listConverter);
 		converters.put(aQute.lib.osgi.Constants.RUNPROPERTIES, propertiesConverter);
 		converters.put(aQute.lib.osgi.Constants.RUNVM, stringConverter);
@@ -222,9 +195,9 @@
 		converters.put(aQute.lib.osgi.Constants.TESTSUITES, listConverter);
 		converters.put(aQute.lib.osgi.Constants.TESTCASES, listConverter);
 		converters.put(aQute.lib.osgi.Constants.PLUGIN, headerClauseListConverter);
-		// converters.put(BndConstants.RUNREQUIRE, requirementListConverter);
-		// converters.put(BndConstants.RUNEE, new NoopConverter<String>());
-		// converters.put(BndConstants.RUNREPOS, listConverter);
+		converters.put(aQute.lib.osgi.Constants.RUNREQUIRES, requirementListConverter);
+		converters.put(aQute.lib.osgi.Constants.RUNEE, eeConverter);
+		converters.put(aQute.lib.osgi.Constants.RUNREPOS, listConverter);
 		// converters.put(BndConstants.RESOLVE_MODE, resolveModeConverter);
 
 		formatters.put(aQute.lib.osgi.Constants.BUILDPATH, headerClauseListFormatter);
@@ -240,7 +213,7 @@
 		formatters.put(Constants.EXPORT_PACKAGE, headerClauseListFormatter);
 		formatters.put(aQute.lib.osgi.Constants.SERVICE_COMPONENT, headerClauseListFormatter);
 		formatters.put(Constants.IMPORT_PACKAGE, headerClauseListFormatter);
-		// formatters.put(BndConstants.RUNFRAMEWORK, newlineEscapeFormatter);
+		formatters.put(aQute.lib.osgi.Constants.RUNFRAMEWORK, newlineEscapeFormatter);
 		formatters.put(aQute.lib.osgi.Constants.SUB, stringListFormatter);
 		formatters.put(aQute.lib.osgi.Constants.RUNPROPERTIES, propertiesFormatter);
 		formatters.put(aQute.lib.osgi.Constants.RUNVM, newlineEscapeFormatter);
@@ -248,9 +221,9 @@
 		// formatters.put(BndConstants.TESTSUITES, stringListFormatter);
 		formatters.put(aQute.lib.osgi.Constants.TESTCASES, stringListFormatter);
 		formatters.put(aQute.lib.osgi.Constants.PLUGIN, headerClauseListFormatter);
-		// formatters.put(BndConstants.RUNREQUIRE, requirementListFormatter);
-		// formatters.put(BndConstants.RUNEE, new NoopConverter<String>());
-		// formatters.put(BndConstants.RUNREPOS, runReposFormatter);
+		formatters.put(aQute.lib.osgi.Constants.RUNREQUIRES, requirementListFormatter);
+		formatters.put(aQute.lib.osgi.Constants.RUNEE, eeFormatter);
+		formatters.put(aQute.lib.osgi.Constants.RUNREPOS, runReposFormatter);
 		// formatters.put(BndConstants.RESOLVE_MODE, resolveModeFormatter);
 	}
 
@@ -472,7 +445,7 @@
 		doSetObject(Constants.EXPORT_PACKAGE, oldValue, exports, headerClauseListFormatter);
 
 		if (referencesBundleVersion && getBundleVersionString() == null) {
-			setBundleVersion(new Version(0, 0, 0).toString());
+			setBundleVersion(Version.emptyVersion.toString());
 		}
 	}
 
@@ -645,10 +618,29 @@
         return doGetObject(aQute.lib.osgi.Constants.RUNFRAMEWORK, stringConverter);
     }
 
+    public EE getEE() {
+        return doGetObject(aQute.lib.osgi.Constants.RUNEE, eeConverter);
+    }
+
+    public void setEE(EE ee) {
+        EE old = getEE();
+        doSetObject(aQute.lib.osgi.Constants.RUNEE, old, ee, eeFormatter);
+    }
+
+    
     public void setRunFramework(String clause) {
         String oldValue = getRunFramework();
         doSetObject(aQute.lib.osgi.Constants.RUNFRAMEWORK, oldValue, clause, newlineEscapeFormatter);
     }
+    
+    public List<Requirement> getRunRequires() {
+    	return doGetObject(aQute.lib.osgi.Constants.RUNREQUIRES, requirementListConverter);
+    }
+    
+    public void setRunRequires(List<Requirement> requires) {
+    	List<Requirement> oldValue = getRunRequires();
+    	doSetObject(aQute.lib.osgi.Constants.RUNREQUIRES, oldValue, requires, requirementListFormatter);
+    }
 
 
 	protected <R> R doGetObject(String name, Converter< ? extends R, ? super String> converter) {
@@ -705,4 +697,4 @@
 	public File getBndResource() {
 		return bndResource;
 	}
-}
\ No newline at end of file
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/build/model/EE.java b/bundleplugin/src/main/java/aQute/bnd/build/model/EE.java
new file mode 100644
index 0000000..e7188a9
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/build/model/EE.java
@@ -0,0 +1,40 @@
+package aQute.bnd.build.model;
+
+public enum EE {
+
+    OSGI_Minimum_1_0("OSGi/Minimum-1.0"), OSGI_Minimum_1_1("OSGi/Minimum-1.1", OSGI_Minimum_1_0), OSGI_Minimum_1_2("OSGi/Minimum-1.2", OSGI_Minimum_1_0, OSGI_Minimum_1_1),
+
+    JRE_1_1("JRE-1.1"), J2SE_1_2("J2SE-1.2", JRE_1_1), J2SE_1_3("J2SE-1.3", JRE_1_1, J2SE_1_2, OSGI_Minimum_1_0, OSGI_Minimum_1_1), J2SE_1_4("J2SE-1.4", JRE_1_1, J2SE_1_2, J2SE_1_3, OSGI_Minimum_1_0, OSGI_Minimum_1_1, OSGI_Minimum_1_2), J2SE_1_5(
+            "J2SE-1.5", JRE_1_1, J2SE_1_2, J2SE_1_3, J2SE_1_4, OSGI_Minimum_1_0, OSGI_Minimum_1_1, OSGI_Minimum_1_2),
+
+    JavaSE_1_6("JavaSE-1.6", JRE_1_1, J2SE_1_2, J2SE_1_3, J2SE_1_4, J2SE_1_5, OSGI_Minimum_1_0, OSGI_Minimum_1_1, OSGI_Minimum_1_2), JavaSE_1_7("JavaSE-1.7", JRE_1_1, J2SE_1_2, J2SE_1_3, J2SE_1_4, J2SE_1_5, JavaSE_1_6, OSGI_Minimum_1_0,
+            OSGI_Minimum_1_1, OSGI_Minimum_1_2), JavaSE_1_8("JavaSE-1.8", JRE_1_1, J2SE_1_2, J2SE_1_3, J2SE_1_4, J2SE_1_5, JavaSE_1_6, JavaSE_1_7, OSGI_Minimum_1_0, OSGI_Minimum_1_1, OSGI_Minimum_1_2), JavaSE_1_9("JavaSE-1.9", JRE_1_1,
+            J2SE_1_2, J2SE_1_3, J2SE_1_4, J2SE_1_5, JavaSE_1_6, JavaSE_1_7, JavaSE_1_8, OSGI_Minimum_1_0, OSGI_Minimum_1_1, OSGI_Minimum_1_2);
+
+    private final String eeName;
+    private final EE[] compatible;
+
+    EE(String name, EE... compatible) {
+        eeName = name;
+        this.compatible = compatible;
+    }
+
+    public String getEEName() {
+        return eeName;
+    }
+
+    /**
+     * @return An array of EEs that this EE implicitly offers, through backwards compatibility.
+     */
+    public EE[] getCompatible() {
+        return compatible != null ? compatible : new EE[0];
+    }
+
+    public static EE parse(String str) {
+        for (EE ee : values()) {
+            if (ee.eeName.equals(str))
+                return ee;
+        }
+        throw new IllegalArgumentException("Unrecognised execution environment name: " + str);
+    }
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/EEConverter.java b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/EEConverter.java
new file mode 100644
index 0000000..de6d2ea
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/EEConverter.java
@@ -0,0 +1,11 @@
+package aQute.bnd.build.model.conversions;
+
+import aQute.bnd.build.model.EE;
+
+public class EEConverter implements Converter<EE,String> {
+
+	public EE convert(String input) throws IllegalArgumentException {
+		return EE.parse(input);
+	}
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/EEFormatter.java b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/EEFormatter.java
new file mode 100644
index 0000000..1853685
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/EEFormatter.java
@@ -0,0 +1,9 @@
+package aQute.bnd.build.model.conversions;
+
+import aQute.bnd.build.model.EE;
+
+public final class EEFormatter implements Converter<String,EE> {
+	public String convert(EE input) throws IllegalArgumentException {
+		return input != null ? input.getEEName() : null;
+	}
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/RequirementFormatter.java b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/RequirementFormatter.java
new file mode 100644
index 0000000..b64f1bd
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/RequirementFormatter.java
@@ -0,0 +1,25 @@
+package aQute.bnd.build.model.conversions;
+
+import java.util.Map.Entry;
+
+import org.osgi.resource.Requirement;
+
+public class RequirementFormatter implements Converter<String,Requirement> {
+
+	public String convert(Requirement req) throws IllegalArgumentException {
+		StringBuilder builder = new StringBuilder();
+		
+		builder.append(req.getNamespace());
+		
+		for (Entry<String,String> directive : req.getDirectives().entrySet()) {
+			builder.append(';').append(directive.getKey()).append(":=").append(directive.getValue());
+		}
+		
+		for (Entry<String,Object> attribute : req.getAttributes().entrySet()) {
+			builder.append(';').append(attribute.getKey()).append("=").append(attribute.getValue());
+		}
+		
+		return builder.toString();
+	}
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/RequirementListConverter.java b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/RequirementListConverter.java
new file mode 100644
index 0000000..6249c0f
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/build/model/conversions/RequirementListConverter.java
@@ -0,0 +1,32 @@
+package aQute.bnd.build.model.conversions;
+
+import java.util.Map.Entry;
+
+import org.osgi.resource.Requirement;
+
+import aQute.lib.osgi.resource.CapReqBuilder;
+import aQute.libg.header.Attrs;
+import aQute.libg.tuple.Pair;
+
+public class RequirementListConverter extends ClauseListConverter<Requirement> {
+
+	public RequirementListConverter() {
+		super(new Converter<Requirement,Pair<String,Attrs>>() {
+			public Requirement convert(Pair<String,Attrs> input) throws IllegalArgumentException {
+				String namespace = input.getFirst();
+				CapReqBuilder builder = new CapReqBuilder(namespace);
+				for (Entry<String,String> entry : input.getSecond().entrySet()) {
+					String key = entry.getKey();
+					if (key.endsWith(":")) {
+						key = key.substring(0, key.length() - 1);
+						builder.addDirective(key, entry.getValue());
+					} else {
+						builder.addAttribute(key, entry.getValue());
+					}
+				}
+				return builder.buildSyntheticRequirement();
+			}
+		});
+	}
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/differ/Baseline.java b/bundleplugin/src/main/java/aQute/bnd/differ/Baseline.java
index fd27e41..4319b6b 100644
--- a/bundleplugin/src/main/java/aQute/bnd/differ/Baseline.java
+++ b/bundleplugin/src/main/java/aQute/bnd/differ/Baseline.java
@@ -34,6 +34,12 @@
 	final Differ	differ;
 	final Reporter	bnd;
 	Diff			diff;
+	Set<Info>		infos;
+	String 			bsn;
+	Version			newerVersion;
+	Version			olderVersion;
+	Version			suggestedVersion;
+	String			releaseRepository;
 
 	public Baseline(Reporter bnd, Differ differ) throws IOException {
 		this.differ = differ;
@@ -66,8 +72,14 @@
 			throws Exception {
 		diff = n.diff(o);
 		Diff apiDiff = diff.get("<api>");
-		Set<Info> infos = Create.set();
+		infos = Create.set();
 
+		bsn = getBsn(n);
+
+		newerVersion = getVersion(n);
+		olderVersion = getVersion(o);
+		
+		Delta highestDelta = Delta.MICRO;
 		for (Diff pdiff : apiDiff.getChildren()) {
 			if (pdiff.getType() != Type.PACKAGE) // Just packages
 				continue;
@@ -91,7 +103,7 @@
 			if (pdiff.getDelta() == Delta.UNCHANGED) {
 				info.suggestedVersion = info.olderVersion;
 				if (!info.newerVersion.equals(info.olderVersion)) {
-					info.warning += "No difference but versions are equal";
+					info.warning += "No difference but versions are not equal";
 				}
 			} else if (pdiff.getDelta() == Delta.REMOVED) {
 				info.suggestedVersion = null;
@@ -135,6 +147,13 @@
 					}
 				}
 			}
+			if (pdiff.getDelta().compareTo(highestDelta) > 0) {
+				highestDelta = pdiff.getDelta();
+			}
+		}
+		suggestedVersion = bumpBundle(highestDelta, olderVersion, 1, 0);
+		if (suggestedVersion.getMajor() == 0) {
+			suggestedVersion = Version.ONE;
 		}
 		return infos;
 	}
@@ -148,6 +167,40 @@
 		return diff;
 	}
 
+	public Set<Info> getPackageInfos() {
+		if (infos == null)
+			return Collections.emptySet();
+		return infos;
+	}
+
+	public String getBsn() {
+		return bsn;
+	}
+
+	public Version getSuggestedVersion() {
+		return suggestedVersion;
+	}
+
+	public void setSuggestedVersion(Version suggestedVersion) {
+		this.suggestedVersion = suggestedVersion;
+	}
+
+	public Version getNewerVersion() {
+		return newerVersion;
+	}
+
+	public Version getOlderVersion() {
+		return olderVersion;
+	}
+
+	public String getReleaseRepository() {
+		return releaseRepository;
+	}
+
+	public void setReleaseRepository(String releaseRepository) {
+		this.releaseRepository = releaseRepository;
+	}
+
 	private Version bump(Delta delta, Version last, int offset, int base) {
 		switch (delta) {
 			case UNCHANGED :
@@ -177,5 +230,43 @@
 
 		return OSGiHeader.parseHeader(m.getMainAttributes().getValue(Constants.EXPORT_PACKAGE));
 	}
+	
+	private Version getVersion(Tree top) {
+		Tree manifest = top.get("<manifest>");
+		if (manifest == null) {
+			return Version.emptyVersion;
+		}
+		for (Tree tree : manifest.getChildren()) {
+			if (tree.getName().startsWith(Constants.BUNDLE_VERSION)) {
+				return Version.parseVersion(tree.getName().substring(15));
+			}
+		}
+		return Version.emptyVersion;
+	}
 
+	private String getBsn(Tree top) {
+		Tree manifest = top.get("<manifest>");
+		if (manifest == null) {
+			return "";
+		}
+		for (Tree tree : manifest.getChildren()) {
+			if (tree.getName().startsWith(Constants.BUNDLE_SYMBOLICNAME) && tree.getChildren().length > 0) {
+				return tree.getChildren()[0].getName();
+			}
+		}
+		return "";
+	}
+
+	private Version bumpBundle(Delta delta, Version last, int offset, int base) {
+		switch (delta) {
+			case MINOR :
+				return new Version(last.getMajor(), last.getMinor() + offset, base);
+			case MAJOR :
+				return new Version(last.getMajor() + 1, base, base);
+			case ADDED :
+				return new Version(last.getMajor(), last.getMinor() + offset, base);
+			default :
+				return new Version(last.getMajor(), last.getMinor(), last.getMicro() + offset);
+		}
+	}
 }
diff --git a/bundleplugin/src/main/java/aQute/bnd/maven/MavenCommand.java b/bundleplugin/src/main/java/aQute/bnd/maven/MavenCommand.java
index edd212b..3717062 100644
--- a/bundleplugin/src/main/java/aQute/bnd/maven/MavenCommand.java
+++ b/bundleplugin/src/main/java/aQute/bnd/maven/MavenCommand.java
@@ -77,9 +77,9 @@
 	}
 
 	private void help() {
-		System.err.println("Usage:%n");
+		System.err.printf("Usage:%n");
 		System.err
-				.println("  maven %n" //
+				.printf("  maven %n" //
 						+ "  [-temp <dir>]            use as temp directory%n" //
 						+ "  settings                 show maven settings%n" //
 						+ "  bundle                   turn a bundle into a maven bundle%n" //
@@ -93,7 +93,7 @@
 						+ "    [-developer <email>]   developer email%n" //
 						+ "    [-nodelete]            do not delete temp files%n" //
 						+ "    [-passphrase <gpgp passphrase>] signer password%n"//
-						+ "        <file|url> ");
+						+ "        <file|url>%n");
 	}
 
 	/**
diff --git a/bundleplugin/src/main/java/aQute/bnd/maven/MavenDeployCmd.java b/bundleplugin/src/main/java/aQute/bnd/maven/MavenDeployCmd.java
index da4eff0..8f80562 100644
--- a/bundleplugin/src/main/java/aQute/bnd/maven/MavenDeployCmd.java
+++ b/bundleplugin/src/main/java/aQute/bnd/maven/MavenDeployCmd.java
@@ -30,7 +30,7 @@
 	 */
 	void run(String args[], int i) throws Exception {
 		if (i >= args.length) {
-			System.err.println("Usage:%n");
+			System.err.printf("Usage:%n");
 			System.err
 					.println("  deploy [-url repo] [-passphrase passphrase] [-homedir homedir] [-keyname keyname] bundle ...");
 			System.err.println("  settings");
diff --git a/bundleplugin/src/main/java/aQute/bnd/signing/Signer.java b/bundleplugin/src/main/java/aQute/bnd/signing/Signer.java
index 600c9a8..f885d4d 100644
--- a/bundleplugin/src/main/java/aQute/bnd/signing/Signer.java
+++ b/bundleplugin/src/main/java/aQute/bnd/signing/Signer.java
@@ -141,7 +141,7 @@
 					if (algorithms[a] != null) {
 						byte[] digest = algorithms[a].digest();
 						String header = digestNames[a] + "-Digest: " + new Base64(digest) + "\r\n";
-						out.write(header.getBytes());
+						out.write(header.getBytes("UTF-8"));
 					}
 				}
 			}