<?php

	/*
	*	Gekko - Open Source Web Development Framework
	*	------------------------------------------------------------------------
	*	Copyright (C) 2004-2005, J. Carlos Nieto <xiam@users.sourceforge.net>
	*	This program is Free Software.
	*
	*	@package	Gekko
	*	@license	http://www.gnu.org/copyleft/gpl.html GNU/GPL License 2.0
	*	@author		J. Carlos Nieto <xiam@users.sf.net>
	*	@version	CVS: $Id:$
	*	@link		http://www.gekkoware.org
	*/

	if (!defined("IN-GEKKO")) die("Get a life!");

	function data_compress($data, $compression_engine = null) {
		if (!$compression_engine) {
			if (extension_loaded("bz2")) {
				$compression_engine = "bzip2";
			} elseif (extension_loaded("zlib")) {
				$compression_engine = "gzip";
			}
		}
		switch ($compression_engine) {
			case "bzip2": {
				$data = bzcompress($data);
				break;
			}
			case "gzip": {
				$data = gzencode($data);
				break;
			}
		}
		return $data;
	}

	/*
		Uncompress the given data.

		data_uncompress(Compressed data, Opt Compression Method);
		return: Uncompressed data.
	*/
	function data_uncompress($data, $compression_engine = null) {

		if (!$compression_engine) {
			if ($data[0].$data[1].$data[2] == "BZh") {
				$compression_engine = "bzip2";
			} elseif ($data[0].$data[1] == chr(31).chr(139)) {
				$compression_engine = "gzip";
			}
		}

		switch ($compression_engine) {
			case "bzip2": {
				$data = bzdecompress($data);
				break;
			}
			case "gzip": {
				/*
					*********************************************************
					 This code portion is based on:
					                                    Simple Machines Forum
					*********************************************************
					 URL: http://www.simplemachines.org
					 File: Subs-Package.php :: read_tgz_data();
					 License: GNU/GPL
					 Copyright: (c) Lewis Media (http://www.lewismedia.com)
					 Software Version: SMF 1.0.3
					**********************************************************
				*/

				$flags = unpack("Ct/Cf", substr($data, 2, 2));

				if ($flags["t"] != 8) {
					trigger_error("Corrupted data!", E_USER_ERROR);
				}

				$flags = $flags["f"];

				$offset = 10;
				if ($flags & 12) {
					while ((($flags & 8) || ($flags & 4)) && $data{$offset++} != "\0") $offset;

					//while ($flags & 8 && $data{$offset++} != "\0") $offset;
					//while ($flags & 4 && $data{$offset++} != "\0") $offset;

				}

				$datalen = strlen($data);

				$crc = unpack('Vcrc32/Visize', substr($data, $datalen - 8, 8));

				// this will cause a memmory leak with large files
				if (!($data = gzinflate(substr($data, $offset, $datalen - 8 - $offset)))) return false;

				if ($crc["crc32"] != crc32($data)) return false;

				break;
			}
		}

		return $data;
	}

	/*
		Untars data to directory

		data_untar(Data, Str Directory to write, Bool Overwrite);
		returns: true on success, false on data error
	*/
	function data_untar ($data, $destination = ".", $overwrite = 1) {
		/*
			*********************************************************
				This code portion is based on:
												Simple Machines Forum
			*********************************************************
				URL: http://www.simplemachines.org
				File: Subs-Package.php :: read_tgz_data();
				License: GNU/GPL
				Copyright: (c) Lewis Media (http://www.lewismedia.com)
				Software Version: SMF 1.0.3
			**********************************************************
		*/

		// fixing destination
		if (substr($destination, -1) != "/") $destination = $destination."/";

		// checking destination
		if (!is_writable($destination)) trigger_error("'$destination' must be writable.", E_USER_ERROR);

		$octdec = array('mode', 'uid', 'gid', 'size', 'mtime', 'checksum', 'type');
		$blocks = strlen($data)/512-1;

		$offset = 0;

		while ($offset < $blocks) {

			$header = substr($data, $offset << 9, 512);

			if (!($current = @unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100linkname/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155path", $header))) {
				return false;
			}

			foreach ($current as $k => $v) {
				$current[$k] = in_array($k, $octdec) ? octdec(trim($v)) : trim($v);
			}

			$checksum = 256;
			for ($i = 0; $i < 148; $i++) {
				$checksum += ord($header{$i});
			}
			for ($i = 156; $i < 512; $i++) {
				$checksum += ord($header{$i});
			}

			if ($current["checksum"] != $checksum) return false;

			$size = ceil($current["size"] / 512);
			$current["data"] = substr($data, ++$offset << 9, $current["size"]);
			$offset += $size;

			// Protect from parent directory writing
			$current["filename"] = preg_replace("/(\.\.\/|\/\.\.)/", "", $current["filename"]);
			$current["destination"] = $destination.$current["filename"];

			if (substr($current["filename"], -1) == "/") {
				@mkdir($current["destination"], 0777);
				// this chmod is for some servers, unknown reason
				@chmod($current["destination"], 0777);
				continue;
			}

			if ($overwrite || (!file_exists($current["destination"]))) {
				/*
					Creating folders if extracted file needs to
				*/
				if (strpos($current["filename"], "/") !== false) {
					$dirs = explode("/", $current["filename"]);
					array_pop($dirs);
					$basedir = $destination;
					foreach ($dirs as $dir) {
						if (!file_exists($basedir.$dir)) {
							@mkdir($basedir.$dir, 0777);
							@chmod($basedir.$dir, 0777);
						}
						$basedir .= $dir."/";
					}
				}
				if ($fp = @fopen($current["destination"], "wb")) {
					fwrite($fp, $current["data"]);
					fclose($fp);
					chmod ($current["destination"], 0777);
				}
			}
		}

		return true;
	}

	/*
		Opens a Tar file (could be bzip2'ed or gzip'ed)

		file_untar(Tar file, Str Destination directory, Bool Overwrite);
	*/
	function file_untar($file, $destination, $overwrite = 0, $type = null) {
		# guessing filetype
		if ($fp = fopen($file, "r")) {
			# reading file header
			$hd = fread($fp, 8);
			fclose($fp);

			if (!$type) {
				if ($hd[0].$hd[1].$hd[2] == "BZh") {
					$type = "bzip2";
				} elseif ($hd[0].$hd[1] == chr(31).chr(139)) {
					$type = "gzip";
				}
			}

			$data = null;
			switch ($type) {
				case "bzip2": {
					$fp = fopen($file, "r");
					$data = bzdecompress(fread($fp, filesize($file)));
					fclose($fp);
					break;
				}
				case "gzip": {
					$h = gzopen($file, "r");
					while (!gzeof($h)) {
						$data .= gzread($h, 1048576);
					}
					gzclose($h);
					break;
				}
				default: {
					$h = fopen($file, "r");
					$data = fread($h, filesize($file));
					fclose($h);
				}
			}

			data_untar($data, $destination, $overwrite);

			return true;

		} else {
			return false;
		}
	}

?>