src/ets.php
function build_mask($datatree, $masktree, $direction = _ETS_FORWARD, $index = -1, $last = FALSE, $key = '', $incode = FALSE, $carray = array(), $safemode = FALSE)
	{
		$built = array();
		// array
		if (isset($datatree) && is_array($datatree) && count($datatree) > 0) {
			$lindex = 0;
			$count = count($datatree) - 1; // don't count parent element
			foreach ($datatree as $dk => $dv) {
				if (!is_scalar($dv) && $dk !== '_parent') {
					if (is_object($dv)) {
						// For some reason, PHP 5 is throwing 500's when the parent datatree has an array in the object. Retarded.
						if (version_compare(phpversion(), '5.0.0', '>')){
						$my_datatree = new stdClass;
							foreach($datatree['_parent'] as $k => $v){
								if(is_array($v)){continue;}
								$my_datatree->{$k} = $v;
							}
							$dv->_parent = $my_datatree;
						} else {
							$dv->_parent = &$datatree['_parent'];
						}
					} elseif (is_array($dv)) {
						$dv['_parent'] = &$datatree['_parent'];
					}
					$built[] = $this->build_mask($dv, $masktree, $direction, $lindex, ($count == $lindex + 1), $dk, $incode, $datatree);
				}
				++$lindex;
			}
			return implode('', $built);
		}
		// define system variables
		if (is_object($datatree) && $index > -1 && !isset($datatree->_key)) {
			$this->add_system_var($datatree, $index, $last, $key);
		}
		// loop through each child element
		foreach ($masktree as $maskinfo => $child) {
			// save array information
			$cindex = $index;
			$clast = $last;
			$ckey = $key;
			// retrieve info from index
			list($masktype, $maskname, $maskvalue) = $this->parse_info($maskinfo);
			// in safe mode, only a subset of elements are available
			if ($safemode) {
				// retrieve datatype and direction and define parent property if necessary
				$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, TRUE);
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// simple tag element are only used to place scalar values
					case _ETS_TAG:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->protect_spaces($currentdata);
						}
						break;
					// set element
					case _ETS_SET:
						if ($datatype != _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// mis element
					case _ETS_MIS:
						if ($datatype == _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// set val element
					case _ETS_SETVAL:
						if ($datatype == _ETS_SCALAR) {
							if ($currentdata == $maskvalue) {
								$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
							}
						}
						break;
					// mis val element
					case _ETS_MISVAL:
						if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// template element
					case _ETS_TEMPLATE:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->build_mask($datatree, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						} elseif ($datatype == _ETS_COMPLEX) {
							$built[] = $this->build_mask($currentdata, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// other element: error
					default:
						$this->error(15, 53, '', 0, $masktype);
						break;
				}
			// normal mode
			} else {
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// php element
					case _ETS_PHP:
						$return = NULL;
						@eval('$return=(string)(' . $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray) . ');');
						if (isset($return)) {
							$built[] = $return;
						}
						break;
					// const element
					case _ETS_CONST:
						$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return])) {
							$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// call element
					case _ETS_CALL:
						$template = $this->build_mask($datatree, $child['template'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return]) && isset($child['args'])) {
							$argdatatree = $datatree;
							foreach ($child['args'] as $arginfo => $argchild) {
								list($argtype, $argname, $argvalue) = $this->parse_info($arginfo);
								$argdatatree->$argname = $this->build_mask($datatree, $argchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
							}
							$built[] = $this->build_mask($argdatatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// include element
					case _ETS_PLACE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$included = $this->read_container($return, _ETS_ROOT);
							if ($included === FALSE) {
								$this->error(13, 54, $return);
							} else {
								$this->masktree = $this->masktree_merge($this->masktree, $included, $maskvalue);
							}
						}
						break;
					// insert element
					case _ETS_INSERT:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$inserted = $this->read_container($return, _ETS_TEXT);
							if ($inserted === FALSE) {
								$this->error(12, 55, $return);
							} else {
								$built[] = $inserted;
							}
						}
						break;
					// eval and safe elements or include
					case _ETS_EVAL:
					case _ETS_SAFE:
					case _ETS_INCLUDE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$evaluated = $this->read_container($return, _ETS_ROOT_EVAL);
							if ($evaluated === FALSE) {
								$this->error(14, 56, $return);
							} else {
								$built[] = $this->build_mask($datatree, $evaluated, $direction, $cindex, $clast, $ckey, $incode, $carray, $masktype == _ETS_SAFE);
							}
						}
						break;
					// other types of element
					default:
						// retrieve datatype and direction and define parent property if necessary
						$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, $safemode);
						switch ($masktype) {
							// simple tag element
							case _ETS_TAG:
								if ($datatype == _ETS_SCALAR && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($datatree, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_SCALAR) {
									if ($incode) {
										if ($currentdata === TRUE) {
											$built[] = 'TRUE';
										} elseif ($currentdata === FALSE) {
											$built[] = 'FALSE';
										} elseif (is_string($currentdata)) {
											$built[] = '"' . addcslashes($currentdata, "\0..\31\"") . '"';
										} else {
											$built[] = $currentdata;
										}
									} else {
										$built[] = $this->protect_spaces($currentdata);
									}
								} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($currentdata, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = 'NULL';
								}
								break;
							// alternate tag element
							case _ETS_ALT_TAG:
								$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(string)(' . $template . ');');
								if (isset($return)) {
									if ($datatype == _ETS_SCALAR && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($currentdata, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_SCALAR) {
										$built[] = $currentdata;
									}
								}
								break;
							// template element
							case _ETS_TEMPLATE:
								if ($datatype == _ETS_SCALAR) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// if element
							case _ETS_IF:
								$test = $this->build_mask($datatree, $child['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(bool)(' . $test . ');');
								if ($return === TRUE) {
									$built[] = $this->build_mask($datatree, $child['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// repeat element
							case _ETS_REPEAT:
								$loop = $this->build_mask($datatree, $child['loops'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(int)(' . $loop . ');');
								for ($i = 0; $i < $return; ++$i) {
									if (is_object($datatree)) {
										$datatree->_count = $i + 1;
									}
									$built[] = $this->build_mask($datatree, $child['repeated'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose element
							case _ETS_CHOOSE:
								$notfound = TRUE;
								if (isset($child['when'])) {
									foreach ($child['when'] as $grandchild)  {
										$test = $this->build_mask($datatree, $grandchild['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
										$return = NULL;
										@eval('$return=(bool)(' . $test . ');');
										if ($return === TRUE) {
											$notfound = FALSE;
											$built[] = $this->build_mask($datatree, $grandchild['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
											break;
										}
									}
								}
								if ($notfound && isset($child['else'])) {
									$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose variable element
							case _ETS_CHOOSEVAR:
								if ($datatype == _ETS_SCALAR) {
									$notfound = TRUE;
									if (isset($child['when'])) {
										foreach ($child['when'] as $gcmaskinfo => $grandchild)  {
											list($gcmasktype, $gcmaskname, $gcmaskvalue) = $this->parse_info($gcmaskinfo);
											if ($currentdata == $gcmaskvalue) {
												$built[] = $this->build_mask($datatree, $grandchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
												$notfound = FALSE;
											}
										}
									}
									if ($notfound && isset($child['else'])) {
										$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// set element
							case _ETS_SET:
								if ($datatype != _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis element
							case _ETS_MIS:
								if ($datatype == _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// set val element
							case _ETS_SETVAL:
								if ($datatype == _ETS_SCALAR) {
									if ($currentdata == $maskvalue) {
										$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// mis val element
							case _ETS_MISVAL:
								if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis mask element
							case _ETS_MIS_TEMPLATE:
								if ($datatype == _ETS_MISSING || $datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
						}
						break;
				}
			}
		}
		// done
		return implode('', $built);
	}
function build_mask($datatree, $masktree, $direction = _ETS_FORWARD, $index = -1, $last = FALSE, $key = '', $incode = FALSE, $carray = array(), $safemode = FALSE)
	{
		$built = array();
		// array
		if (isset($datatree) && is_array($datatree) && count($datatree) > 0) {
			$lindex = 0;
			$count = count($datatree) - 1; // don't count parent element
			foreach ($datatree as $dk => $dv) {
				if (!is_scalar($dv) && $dk !== '_parent') {
					if (is_object($dv)) {
						// For some reason, PHP 5 is throwing 500's when the parent datatree has an array in the object. Retarded.
						if (version_compare(phpversion(), '5.0.0', '>')){
						$my_datatree = new stdClass;
							foreach($datatree['_parent'] as $k => $v){
								if(is_array($v)){continue;}
								$my_datatree->{$k} = $v;
							}
							$dv->_parent = $my_datatree;
						} else {
							$dv->_parent = &$datatree['_parent'];
						}
					} elseif (is_array($dv)) {
						$dv['_parent'] = &$datatree['_parent'];
					}
					$built[] = $this->build_mask($dv, $masktree, $direction, $lindex, ($count == $lindex + 1), $dk, $incode, $datatree);
				}
				++$lindex;
			}
			return implode('', $built);
		}
		// define system variables
		if (is_object($datatree) && $index > -1 && !isset($datatree->_key)) {
			$this->add_system_var($datatree, $index, $last, $key);
		}
		// loop through each child element
		foreach ($masktree as $maskinfo => $child) {
			// save array information
			$cindex = $index;
			$clast = $last;
			$ckey = $key;
			// retrieve info from index
			list($masktype, $maskname, $maskvalue) = $this->parse_info($maskinfo);
			// in safe mode, only a subset of elements are available
			if ($safemode) {
				// retrieve datatype and direction and define parent property if necessary
				$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, TRUE);
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// simple tag element are only used to place scalar values
					case _ETS_TAG:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->protect_spaces($currentdata);
						}
						break;
					// set element
					case _ETS_SET:
						if ($datatype != _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// mis element
					case _ETS_MIS:
						if ($datatype == _ETS_MISSING) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// set val element
					case _ETS_SETVAL:
						if ($datatype == _ETS_SCALAR) {
							if ($currentdata == $maskvalue) {
								$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
							}
						}
						break;
					// mis val element
					case _ETS_MISVAL:
						if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
							$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// template element
					case _ETS_TEMPLATE:
						if ($datatype == _ETS_SCALAR) {
							$built[] = $this->build_mask($datatree, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						} elseif ($datatype == _ETS_COMPLEX) {
							$built[] = $this->build_mask($currentdata, $child, _ETS_FORWARD, $cindex, $clast, $ckey, $incode, $carray, TRUE);
						}
						break;
					// other element: error
					default:
						$this->error(15, 53, '', 0, $masktype);
						break;
				}
			// normal mode
			} else {
				switch ($masktype) {
					// content data element
					case _ETS_TEXT:
						$built[] = $child;
						break;
					// php element
					case _ETS_PHP:
						$return = NULL;
						@eval('$return=(string)(' . $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray) . ');');
						if (isset($return)) {
							$built[] = $return;
						}
						break;
					// const element
					case _ETS_CONST:
						$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return])) {
							$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// call element
					case _ETS_CALL:
						$template = $this->build_mask($datatree, $child['template'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $template . ');');
						if (isset($return) && isset($this->masktree[$return]) && isset($child['args'])) {
							$argdatatree = $datatree;
							foreach ($child['args'] as $arginfo => $argchild) {
								list($argtype, $argname, $argvalue) = $this->parse_info($arginfo);
								$argdatatree->$argname = $this->build_mask($datatree, $argchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
							}
							$built[] = $this->build_mask($argdatatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
						}
						break;
					// include element
					case _ETS_PLACE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$included = $this->read_container($return, _ETS_ROOT);
							if ($included === FALSE) {
								$this->error(13, 54, $return);
							} else {
								$this->masktree = $this->masktree_merge($this->masktree, $included, $maskvalue);
							}
						}
						break;
					// insert element
					case _ETS_INSERT:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$inserted = $this->read_container($return, _ETS_TEXT);
							if ($inserted === FALSE) {
								$this->error(12, 55, $return);
							} else {
								$built[] = $inserted;
							}
						}
						break;
					// eval and safe elements or include
					case _ETS_EVAL:
					case _ETS_SAFE:
					case _ETS_INCLUDE:
						$container = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
						$return = NULL;
						@eval('$return=(string)(' . $container . ');');
						if (isset($return)) {
							$evaluated = $this->read_container($return, _ETS_ROOT_EVAL);
							if ($evaluated === FALSE) {
								$this->error(14, 56, $return);
							} else {
								$built[] = $this->build_mask($datatree, $evaluated, $direction, $cindex, $clast, $ckey, $incode, $carray, $masktype == _ETS_SAFE);
							}
						}
						break;
					// other types of element
					default:
						// retrieve datatype and direction and define parent property if necessary
						$this->get_datatype($maskname, $carray, $incode, $cindex, $ckey, $clast, $datatree, $datatype, $direction, $currentdata, $safemode);
						switch ($masktype) {
							// simple tag element
							case _ETS_TAG:
								if ($datatype == _ETS_SCALAR && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($datatree, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_SCALAR) {
									if ($incode) {
										if ($currentdata === TRUE) {
											$built[] = 'TRUE';
										} elseif ($currentdata === FALSE) {
											$built[] = 'FALSE';
										} elseif (is_string($currentdata)) {
											$built[] = '"' . addcslashes($currentdata, "\0..\31\"") . '"';
										} else {
											$built[] = $currentdata;
										}
									} else {
										$built[] = $this->protect_spaces($currentdata);
									}
								} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$maskname])) {
									$built[] = $this->build_mask($currentdata, $this->masktree[$maskname], $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = 'NULL';
								}
								break;
							// alternate tag element
							case _ETS_ALT_TAG:
								$template = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(string)(' . $template . ');');
								if (isset($return)) {
									if ($datatype == _ETS_SCALAR && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($datatree, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_COMPLEX && isset($this->masktree[$return])) {
										$built[] = $this->build_mask($currentdata, $this->masktree[$return], $direction, $cindex, $clast, $ckey, $incode, $carray);
									} elseif ($datatype == _ETS_SCALAR) {
										$built[] = $currentdata;
									}
								}
								break;
							// template element
							case _ETS_TEMPLATE:
								if ($datatype == _ETS_SCALAR) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								} elseif ($datatype == _ETS_MISSING && $incode) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// if element
							case _ETS_IF:
								$test = $this->build_mask($datatree, $child['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(bool)(' . $test . ');');
								if ($return === TRUE) {
									$built[] = $this->build_mask($datatree, $child['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// repeat element
							case _ETS_REPEAT:
								$loop = $this->build_mask($datatree, $child['loops'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
								$return = NULL;
								@eval('$return=(int)(' . $loop . ');');
								for ($i = 0; $i < $return; ++$i) {
									if (is_object($datatree)) {
										$datatree->_count = $i + 1;
									}
									$built[] = $this->build_mask($datatree, $child['repeated'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose element
							case _ETS_CHOOSE:
								$notfound = TRUE;
								if (isset($child['when'])) {
									foreach ($child['when'] as $grandchild)  {
										$test = $this->build_mask($datatree, $grandchild['test'], $direction, $cindex, $clast, $ckey, TRUE, $carray);
										$return = NULL;
										@eval('$return=(bool)(' . $test . ');');
										if ($return === TRUE) {
											$notfound = FALSE;
											$built[] = $this->build_mask($datatree, $grandchild['true'], $direction, $cindex, $clast, $ckey, $incode, $carray);
											break;
										}
									}
								}
								if ($notfound && isset($child['else'])) {
									$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// choose variable element
							case _ETS_CHOOSEVAR:
								if ($datatype == _ETS_SCALAR) {
									$notfound = TRUE;
									if (isset($child['when'])) {
										foreach ($child['when'] as $gcmaskinfo => $grandchild)  {
											list($gcmasktype, $gcmaskname, $gcmaskvalue) = $this->parse_info($gcmaskinfo);
											if ($currentdata == $gcmaskvalue) {
												$built[] = $this->build_mask($datatree, $grandchild, $direction, $cindex, $clast, $ckey, $incode, $carray);
												$notfound = FALSE;
											}
										}
									}
									if ($notfound && isset($child['else'])) {
										$built[] = $this->build_mask($datatree, $child['else'], $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// set element
							case _ETS_SET:
								if ($datatype != _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis element
							case _ETS_MIS:
								if ($datatype == _ETS_MISSING) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// set val element
							case _ETS_SETVAL:
								if ($datatype == _ETS_SCALAR) {
									if ($currentdata == $maskvalue) {
										$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
									}
								}
								break;
							// mis val element
							case _ETS_MISVAL:
								if ($datatype == _ETS_MISSING || ($datatype == _ETS_SCALAR && $currentdata != $maskvalue)) {
									$built[] = $this->build_mask($datatree, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
							// mis mask element
							case _ETS_MIS_TEMPLATE:
								if ($datatype == _ETS_MISSING || $datatype == _ETS_COMPLEX) {
									$built[] = $this->build_mask($currentdata, $child, $direction, $cindex, $clast, $ckey, $incode, $carray);
								}
								break;
						}
						break;
				}
			}
		}
		// done
		return implode('', $built);
	}
function build_mask ( $ datatree , $ masktree , $ direction = _ETS_FORWARD , $ index = - 1 , $ last = FALSE , $ key = '' , $ incode = FALSE , $ carray = array ( ) , $ safemode = FALSE ) { $ built = array ( ) ; // array if ( isset ( $ datatree ) && is_array ( $ datatree ) && count ( $ datatree ) > 0 ) { $ lindex = 0 ; $ count = count ( $ datatree ) - 1 ; // don't count parent element foreach ( $ datatree as $ dk => $ dv ) { if ( ! is_scalar ( $ dv ) && $ dk !== '_parent' ) { if ( is_object ( $ dv ) ) { // For some reason, PHP 5 is throwing 500's when the parent datatree has an array in the object. Retarded. if ( version_compare ( phpversion ( ) , '5.0.0' , '>' ) ) { $ my_datatree = new stdClass ; foreach ( $ datatree [ '_parent' ] as $ k => $ v ) { if ( is_array ( $ v ) ) { continue ; } $ my_datatree -> { $ k } = $ v ; } $ dv -> _parent = $ my_datatree ; } else { $ dv -> _parent = & $ datatree [ '_parent' ] ; } } elseif ( is_array ( $ dv ) ) { $ dv [ '_parent' ] = & $ datatree [ '_parent' ] ; } $ built [ ] = $ this -> build_mask ( $ dv , $ masktree , $ direction , $ lindex , ( $ count == $ lindex + 1 ) , $ dk , $ incode , $ datatree ) ; } ++ $ lindex ; } return implode ( '' , $ built ) ; } // define system variables if ( is_object ( $ datatree ) && $ index > - 1 && ! isset ( $ datatree -> _key ) ) { $ this -> add_system_var ( $ datatree , $ index , $ last , $ key ) ; } // loop through each child element foreach ( $ masktree as $ maskinfo => $ child ) { // save array information $ cindex = $ index ; $ clast = $ last ; $ ckey = $ key ; // retrieve info from index list ( $ masktype , $ maskname , $ maskvalue ) = $ this -> parse_info ( $ maskinfo ) ; // in safe mode, only a subset of elements are available if ( $ safemode ) { // retrieve datatype and direction and define parent property if necessary $ this -> get_datatype ( $ maskname , $ carray , $ incode , $ cindex , $ ckey , $ clast , $ datatree , $ datatype , $ direction , $ currentdata , TRUE ) ; switch ( $ masktype ) { // content data element case _ETS_TEXT : $ built [ ] = $ child ; break ; // simple tag element are only used to place scalar values case _ETS_TAG : if ( $ datatype == _ETS_SCALAR ) { $ built [ ] = $ this -> protect_spaces ( $ currentdata ) ; } break ; // set element case _ETS_SET : if ( $ datatype != _ETS_MISSING ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray , TRUE ) ; } break ; // mis element case _ETS_MIS : if ( $ datatype == _ETS_MISSING ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray , TRUE ) ; } break ; // set val element case _ETS_SETVAL : if ( $ datatype == _ETS_SCALAR ) { if ( $ currentdata == $ maskvalue ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray , TRUE ) ; } } break ; // mis val element case _ETS_MISVAL : if ( $ datatype == _ETS_MISSING || ( $ datatype == _ETS_SCALAR && $ currentdata != $ maskvalue ) ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray , TRUE ) ; } break ; // template element case _ETS_TEMPLATE : if ( $ datatype == _ETS_SCALAR ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , _ETS_FORWARD , $ cindex , $ clast , $ ckey , $ incode , $ carray , TRUE ) ; } elseif ( $ datatype == _ETS_COMPLEX ) { $ built [ ] = $ this -> build_mask ( $ currentdata , $ child , _ETS_FORWARD , $ cindex , $ clast , $ ckey , $ incode , $ carray , TRUE ) ; } break ; // other element: error default : $ this -> error ( 15 , 53 , '' , 0 , $ masktype ) ; break ; } // normal mode } else { switch ( $ masktype ) { // content data element case _ETS_TEXT : $ built [ ] = $ child ; break ; // php element case _ETS_PHP : $ return = NULL ; @ eval ( '$return=(string)(' . $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) . ');' ) ; if ( isset ( $ return ) ) { $ built [ ] = $ return ; } break ; // const element case _ETS_CONST : $ template = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(string)(' . $ template . ');' ) ; if ( isset ( $ return ) && isset ( $ this -> masktree [ $ return ] ) ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ this -> masktree [ $ return ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // call element case _ETS_CALL : $ template = $ this -> build_mask ( $ datatree , $ child [ 'template' ] , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(string)(' . $ template . ');' ) ; if ( isset ( $ return ) && isset ( $ this -> masktree [ $ return ] ) && isset ( $ child [ 'args' ] ) ) { $ argdatatree = $ datatree ; foreach ( $ child [ 'args' ] as $ arginfo => $ argchild ) { list ( $ argtype , $ argname , $ argvalue ) = $ this -> parse_info ( $ arginfo ) ; $ argdatatree -> $ argname = $ this -> build_mask ( $ datatree , $ argchild , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } $ built [ ] = $ this -> build_mask ( $ argdatatree , $ this -> masktree [ $ return ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // include element case _ETS_PLACE : $ container = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(string)(' . $ container . ');' ) ; if ( isset ( $ return ) ) { $ included = $ this -> read_container ( $ return , _ETS_ROOT ) ; if ( $ included === FALSE ) { $ this -> error ( 13 , 54 , $ return ) ; } else { $ this -> masktree = $ this -> masktree_merge ( $ this -> masktree , $ included , $ maskvalue ) ; } } break ; // insert element case _ETS_INSERT : $ container = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(string)(' . $ container . ');' ) ; if ( isset ( $ return ) ) { $ inserted = $ this -> read_container ( $ return , _ETS_TEXT ) ; if ( $ inserted === FALSE ) { $ this -> error ( 12 , 55 , $ return ) ; } else { $ built [ ] = $ inserted ; } } break ; // eval and safe elements or include case _ETS_EVAL : case _ETS_SAFE : case _ETS_INCLUDE : $ container = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(string)(' . $ container . ');' ) ; if ( isset ( $ return ) ) { $ evaluated = $ this -> read_container ( $ return , _ETS_ROOT_EVAL ) ; if ( $ evaluated === FALSE ) { $ this -> error ( 14 , 56 , $ return ) ; } else { $ built [ ] = $ this -> build_mask ( $ datatree , $ evaluated , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray , $ masktype == _ETS_SAFE ) ; } } break ; // other types of element default : // retrieve datatype and direction and define parent property if necessary $ this -> get_datatype ( $ maskname , $ carray , $ incode , $ cindex , $ ckey , $ clast , $ datatree , $ datatype , $ direction , $ currentdata , $ safemode ) ; switch ( $ masktype ) { // simple tag element case _ETS_TAG : if ( $ datatype == _ETS_SCALAR && isset ( $ this -> masktree [ $ maskname ] ) ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ this -> masktree [ $ maskname ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } elseif ( $ datatype == _ETS_SCALAR ) { if ( $ incode ) { if ( $ currentdata === TRUE ) { $ built [ ] = 'TRUE' ; } elseif ( $ currentdata === FALSE ) { $ built [ ] = 'FALSE' ; } elseif ( is_string ( $ currentdata ) ) { $ built [ ] = '"' . addcslashes ( $ currentdata , "\0..\31\"" ) . '"' ; } else { $ built [ ] = $ currentdata ; } } else { $ built [ ] = $ this -> protect_spaces ( $ currentdata ) ; } } elseif ( $ datatype == _ETS_COMPLEX && isset ( $ this -> masktree [ $ maskname ] ) ) { $ built [ ] = $ this -> build_mask ( $ currentdata , $ this -> masktree [ $ maskname ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } elseif ( $ datatype == _ETS_MISSING && $ incode ) { $ built [ ] = 'NULL' ; } break ; // alternate tag element case _ETS_ALT_TAG : $ template = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(string)(' . $ template . ');' ) ; if ( isset ( $ return ) ) { if ( $ datatype == _ETS_SCALAR && isset ( $ this -> masktree [ $ return ] ) ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ this -> masktree [ $ return ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } elseif ( $ datatype == _ETS_COMPLEX && isset ( $ this -> masktree [ $ return ] ) ) { $ built [ ] = $ this -> build_mask ( $ currentdata , $ this -> masktree [ $ return ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } elseif ( $ datatype == _ETS_SCALAR ) { $ built [ ] = $ currentdata ; } } break ; // template element case _ETS_TEMPLATE : if ( $ datatype == _ETS_SCALAR ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } elseif ( $ datatype == _ETS_COMPLEX ) { $ built [ ] = $ this -> build_mask ( $ currentdata , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } elseif ( $ datatype == _ETS_MISSING && $ incode ) { $ built [ ] = $ this -> build_mask ( $ currentdata , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // if element case _ETS_IF : $ test = $ this -> build_mask ( $ datatree , $ child [ 'test' ] , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(bool)(' . $ test . ');' ) ; if ( $ return === TRUE ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child [ 'true' ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // repeat element case _ETS_REPEAT : $ loop = $ this -> build_mask ( $ datatree , $ child [ 'loops' ] , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(int)(' . $ loop . ');' ) ; for ( $ i = 0 ; $ i < $ return ; ++ $ i ) { if ( is_object ( $ datatree ) ) { $ datatree -> _count = $ i + 1 ; } $ built [ ] = $ this -> build_mask ( $ datatree , $ child [ 'repeated' ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // choose element case _ETS_CHOOSE : $ notfound = TRUE ; if ( isset ( $ child [ 'when' ] ) ) { foreach ( $ child [ 'when' ] as $ grandchild ) { $ test = $ this -> build_mask ( $ datatree , $ grandchild [ 'test' ] , $ direction , $ cindex , $ clast , $ ckey , TRUE , $ carray ) ; $ return = NULL ; @ eval ( '$return=(bool)(' . $ test . ');' ) ; if ( $ return === TRUE ) { $ notfound = FALSE ; $ built [ ] = $ this -> build_mask ( $ datatree , $ grandchild [ 'true' ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; break ; } } } if ( $ notfound && isset ( $ child [ 'else' ] ) ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child [ 'else' ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // choose variable element case _ETS_CHOOSEVAR : if ( $ datatype == _ETS_SCALAR ) { $ notfound = TRUE ; if ( isset ( $ child [ 'when' ] ) ) { foreach ( $ child [ 'when' ] as $ gcmaskinfo => $ grandchild ) { list ( $ gcmasktype , $ gcmaskname , $ gcmaskvalue ) = $ this -> parse_info ( $ gcmaskinfo ) ; if ( $ currentdata == $ gcmaskvalue ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ grandchild , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; $ notfound = FALSE ; } } } if ( $ notfound && isset ( $ child [ 'else' ] ) ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child [ 'else' ] , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } } break ; // set element case _ETS_SET : if ( $ datatype != _ETS_MISSING ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // mis element case _ETS_MIS : if ( $ datatype == _ETS_MISSING ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // set val element case _ETS_SETVAL : if ( $ datatype == _ETS_SCALAR ) { if ( $ currentdata == $ maskvalue ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } } break ; // mis val element case _ETS_MISVAL : if ( $ datatype == _ETS_MISSING || ( $ datatype == _ETS_SCALAR && $ currentdata != $ maskvalue ) ) { $ built [ ] = $ this -> build_mask ( $ datatree , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; // mis mask element case _ETS_MIS_TEMPLATE : if ( $ datatype == _ETS_MISSING || $ datatype == _ETS_COMPLEX ) { $ built [ ] = $ this -> build_mask ( $ currentdata , $ child , $ direction , $ cindex , $ clast , $ ckey , $ incode , $ carray ) ; } break ; } break ; } } } // done return implode ( '' , $ built ) ; }
Recursively match the template tree with the data tree
Recursively match the template tree with the data tree