<?php
> /**
> * LICENSE
/**
> *
* CFTypeDetector
> * This file is part of CFPropertyList.
* Interface for converting native PHP data structures to CFPropertyList objects.
> *
* @author Rodney Rehm <rodney.rehm@medialize.de>
> * The PHP implementation of Apple's PropertyList can handle XML PropertyLists
* @author Christian Kruse <cjk@wwwtech.de>
> * as well as binary PropertyLists. It offers functionality to easily convert
* @package plist
> * data between worlds, e.g. recalculating timestamps from unix epoch to apple
* @subpackage plist.types
> * epoch and vice versa. A feature to automagically create (guess) the plist
* @example example-create-02.php Using {@link CFTypeDetector}
> * structure from a normal PHP data structure will help you dump your data to
* @example example-create-03.php Using {@link CFTypeDetector} with {@link CFDate} and {@link CFData}
> * plist in no time.
* @example example-create-04.php Using and extended {@link CFTypeDetector}
> *
*/
> * Copyright (c) 2018 Teclib'
> *
namespace CFPropertyList;
> * Permission is hereby granted, free of charge, to any person obtaining a copy
use \DateTime, \Iterator;
> * of this software and associated documentation files (the "Software"), to deal
> * in the Software without restriction, including without limitation the rights
class CFTypeDetector {
> * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> * copies of the Software, and to permit persons to whom the Software is
/**
> * furnished to do so, subject to the following conditions:
* flag stating if all arrays should automatically be converted to {@link CFDictionary}
> *
* @var boolean
> * The above copyright notice and this permission notice shall be included in all
*/
> * copies or substantial portions of the Software.
protected $autoDictionary = false;
> *
> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/**
> * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* flag stating if exceptions should be suppressed or thrown
> * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* @var boolean
> * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*/
> * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
protected $suppressExceptions = false;
> * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> * SOFTWARE.
/**
> *
* name of a method that will be used for array to object conversations
> * ------------------------------------------------------------------------------
* @var callable
> * @author Rodney Rehm <rodney.rehm@medialize.de>
*/
> * @author Christian Kruse <cjk@wwwtech.de>
protected $objectToArrayMethod = null;
> * @copyright Copyright © 2018 Teclib
> * @package plist
/**
> * @license MIT
* flag stating if "123.23" should be converted to float (true) or preserved as string (false)
> * @link https://github.com/TECLIB/CFPropertyList/
* @var boolean
> * @link http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/plist.5.html Property Lists
*/
> * ------------------------------------------------------------------------------
protected $castNumericStrings = true;
> */
>
> namespace CFPropertyList;
/**
>
* Create new CFTypeDetector
> use DateTime;
* @param array $options Configuration for casting values [autoDictionary, suppressExceptions, objectToArrayMethod, castNumericStrings]
> use Iterator;
*/
> use stdClass;
< * @example example-create-02.php Using {@link CFTypeDetector}
< * @example example-create-03.php Using {@link CFTypeDetector} with {@link CFDate} and {@link CFData}
< * @example example-create-04.php Using and extended {@link CFTypeDetector}
> * @example example-create-02.php Using CFTypeDetector
> * @example example-create-03.php Using CFTypeDetector with CFDate and CFData
> * @example example-create-04.php Using and extended CFTypeDetector
<
< namespace CFPropertyList;
< use \DateTime, \Iterator;
<
< class CFTypeDetector {
> class CFTypeDetector
> {
< * flag stating if all arrays should automatically be converted to {@link CFDictionary}
> * flag stating if all arrays should automatically be converted to CFDictionary
< public function __construct(array $options=array()) {
> public function __construct(array $options = array())
> {
* Determine if an array is associative or numerical.
* Numerical Arrays have incrementing index-numbers that don't contain gaps.
* @param array $value Array to check indexes of
* @return boolean true if array is associative, false if array has numeric indexes
*/
< protected function isAssociativeArray($value) {
> protected function isAssociativeArray($value)
> {
$numericKeys = true;
$i = 0;
foreach($value as $key => $v) {
if($i !== $key) {
$numericKeys = false;
break;
}
$i++;
}
return !$numericKeys;
}
/**
* Get the default value
* @return CFType the default value to return if no suitable type could be determined
*/
< protected function defaultValue() {
> protected function defaultValue()
> {
return new CFString();
}
/**
* Create CFType-structure by guessing the data-types.
< * {@link CFArray}, {@link CFDictionary}, {@link CFBoolean}, {@link CFNumber} and {@link CFString} can be created, {@link CFDate} and {@link CFData} cannot.
> * CFArray, {@link CFDictionary}, {@link CFBoolean}, {@link CFNumber} and {@link CFString} can be created, {@link CFDate} and {@link CFData} cannot.
* <br /><b>Note:</b>Distinguishing between {@link CFArray} and {@link CFDictionary} is done by examining the keys.
* Keys must be strictly incrementing integers to evaluate to a {@link CFArray}.
* Since PHP does not offer a function to test for associative arrays,
* this test causes the input array to be walked twice and thus work rather slow on large collections.
* If you work with large arrays and can live with all arrays evaluating to {@link CFDictionary},
* feel free to set the appropriate flag.
* <br /><b>Note:</b> If $value is an instance of CFType it is simply returned.
* <br /><b>Note:</b> If $value is neither a CFType, array, numeric, boolean nor string, it is omitted.
* @param mixed $value Value to convert to CFType
< * @param boolean $autoDictionary if true {@link CFArray}-detection is bypassed and arrays will be returned as {@link CFDictionary}.
* @return CFType CFType based on guessed type
* @uses isAssociativeArray() to check if an array only has numeric indexes
*/
< public function toCFType($value) {
> public function toCFType($value)
> {
switch(true) {
case $value instanceof CFType:
return $value;
break;
case is_object($value):
// DateTime should be CFDate
< if(class_exists( 'DateTime' ) && $value instanceof DateTime){
> if ($value instanceof DateTime) {
return new CFDate($value->getTimestamp());
}
// convert possible objects to arrays, arrays will be arrays
if($this->objectToArrayMethod && is_callable(array($value, $this->objectToArrayMethod))){
$value = call_user_func( array( $value, $this->objectToArrayMethod ) );
> } else if ($value instanceof stdClass) {
}
> $value = (array) $value;
if(!is_array($value)){
< if($this->suppressExceptions)
> if ($this->suppressExceptions) {
return $this->defaultValue();
> }
throw new PListException('Could not determine CFType for object of type '. get_class($value));
}
/* break; omitted */
case $value instanceof Iterator:
case is_array($value):
// test if $value is simple or associative array
if(!$this->autoDictionary) {
if(!$this->isAssociativeArray($value)) {
$t = new CFArray();
< foreach($value as $v) $t->add($this->toCFType($v));
> foreach ($value as $v) {
> $t->add($this->toCFType($v));
> }
return $t;
}
}
$t = new CFDictionary();
< foreach($value as $k => $v) $t->add($k, $this->toCFType($v));
> foreach ($value as $k => $v) {
> $t->add($k, $this->toCFType($v));
> }
return $t;
break;
case is_bool($value):
return new CFBoolean($value);
break;
case is_null($value):
return new CFString();
break;
case is_resource($value):
if ($this->suppressExceptions) {
return $this->defaultValue();
}
throw new PListException('Could not determine CFType for resource of type '. get_resource_type($value));
break;
case is_numeric($value):
if (!$this->castNumericStrings && is_string($value)) {
return new CFString($value);
}
return new CFNumber($value);
break;
case is_string($value):
if(strpos($value, "\x00") !== false) {
return new CFData($value);
}
return new CFString($value);
break;
default:
if ($this->suppressExceptions) {
return $this->defaultValue();
}
throw new PListException('Could not determine CFType for '. gettype($value));
break;
}
}
<
}