diff --git a/Jamfile.jam b/Jamfile.jam
index 9e41cda0f2b9e097c04c7aa64601e7558ced0d22..ae986cca946f66a50995dcc5b49ae61b8bb6d60b 100644
--- a/Jamfile.jam
+++ b/Jamfile.jam
@@ -148,18 +148,12 @@ RELEASE_FILES =
 	readme.txt
 	;
 
-actions ZipAction
+actions ArchiveAction
 {
-	zip -q -9 $(<) $(>)
+	perl tests/archive.pl $(<) $(>)
 }
 
-actions TgzAction
-{
-	tar cf $(<:S=) $(>)
-	gzip -9 $(<:S=)
-}
-
-ZipAction pugixml-$(VERSION).zip : $(RELEASE_FILES) ;
-TgzAction pugixml-$(VERSION).tar.gz : $(RELEASE_FILES) ;
+ArchiveAction pugixml-$(VERSION).zip : $(RELEASE_FILES) ;
+ArchiveAction pugixml-$(VERSION).tar.gz : $(RELEASE_FILES) ;
 Depends release : pugixml-$(VERSION).zip pugixml-$(VERSION).tar.gz : $(RELEASE_FILES) ;
 NotFile release ;
diff --git a/tests/archive.pl b/tests/archive.pl
new file mode 100644
index 0000000000000000000000000000000000000000..240dd02d709355a34c9635a6a96312bdf04ff1d0
--- /dev/null
+++ b/tests/archive.pl
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+
+use Archive::Tar;
+use Archive::Zip;
+
+my $target = shift @ARGV;
+my @sources = @ARGV;
+
+my $zip = $target =~ /\.zip$/;
+
+my $arch = $zip ? Archive::Zip->new : Archive::Tar->new;
+
+for $source (sort {$a cmp $b} @sources)
+{
+	my $contents = &readfile_contents($source);
+	my $meta = &readfile_meta($source);
+
+	if ($zip)
+	{
+		my $path = $source;
+		$arch->addDirectory($path) if $path =~ s/\/[^\/]+$/\// && !defined($arch->memberNamed($path));
+
+		my $member = $arch->addString($contents, $source);
+
+		$member->desiredCompressionMethod(COMPRESSION_DEFLATED);
+		$member->desiredCompressionLevel(9);
+
+		$member->setLastModFileDateTimeFromUnix($$meta{mtime});
+	}
+	else
+	{
+		# tgz releases are for Unix people, Unix people like Unix newlines
+		$contents =~ s/\r//g if (-T $source);
+
+		$arch->add_data($source, $contents, $meta);
+	}
+}
+
+$zip ? $arch->overwriteAs($target) : $arch->write($target, 9);
+
+sub readfile_contents
+{
+	my $file = shift;
+
+	open FILE, $file or die "Can't open $file: $!";
+	binmode FILE;
+	my @contents = <FILE>;
+	close FILE;
+
+	return join('', @contents);
+}
+
+sub readfile_meta
+{
+	my $file = shift;
+
+    my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat($file);
+
+	return {mtime => $mtime};
+}